VBA+Selenium开发Instagram私信宏 XPath首次运行正常二次报NoSuchElementError
Instagram私信自动发送宏NoSuchElementError报错原因
- XPath定位规则不合理:你使用的是从html根节点开始的绝对XPath,依赖固定的DOM层级和节点序号(比如
/html/body/div[6]中的序号6),Instagram是动态渲染页面,每次加载时DOM结构、动态生成的div序号都会发生变化,第二次运行时元素的实际路径已经和你复制的路径不一致,就会触发找不到元素的错误。 - 固定等待时间不可靠:代码中全部使用固定时长的
driver.Wait,如果遇到网络波动、页面渲染延迟,执行元素查找操作时元素还未加载完成,也会抛出该错误。 - 登录状态判断缺失:首次运行时浏览器是无缓存的未登录状态,第二次运行如果浏览器保留了上次的登录缓存,登录页的
loginForm元素根本不会渲染,直接查找就会报错。 - 弹窗干扰未处理:登录成功后会弹出「是否保存登录信息」「是否开启通知」两类弹窗,会遮挡后续要操作的元素,也会导致元素定位失败。
代码调整方案
- 替换所有绝对XPath为相对XPath,优先用元素的aria-label、placeholder、文本内容等稳定属性定位,不要依赖DOM层级和节点序号,比如私信输入框可以定位为
//textarea[contains(@placeholder, '发消息')]。 - 替换固定等待为显式等待,使用Selenium自带的
WaitForElementPresent方法,指定最长等待时间,只有元素加载完成后才执行后续操作。 - 增加登录状态判断、弹窗处理逻辑,避免缓存、弹窗导致的定位失败。
- 增加基础异常捕获,避免偶发问题直接导致程序崩溃。
优化后完整代码
Sub Sending_DM() Dim driver As Selenium.ChromeDriver Dim username As String, Login_ID As String, Login_PW As String Set driver = New Selenium.ChromeDriver driver.Start driver.Wait 2000 username = Sheet3.Range("B2").Value 'B2 = User ID = username Login_ID = Sheet3.Range("A1").Value Login_PW = Sheet3.Range("A2").Value driver.Get "https://www.instagram.com/" & username '-----------登录逻辑,先判断是否已登录 On Error Resume Next Set loginInput = driver.FindElementByXPath("//*[@id='loginForm']/div/div[1]/div/label/input", timeout:=3000) On Error GoTo 0 If Not loginInput Is Nothing Then loginInput.SendKeys Login_ID driver.FindElementByXPath("//*[@id='loginForm']/div/div[2]/div/label/input").SendKeys Login_PW driver.FindElementByXPath("//*[@id='loginForm']/div/div[3]").Click ' 等待登录完成,处理保存登录信息弹窗 driver.WaitForElementPresent "//button[text()='以后再说']", 10000 On Error Resume Next driver.FindElementByXPath("//button[text()='以后再说']", timeout:=2000).Click On Error GoTo 0 End If driver.Get "https://www.instagram.com/direct/inbox/" ' 处理通知权限弹窗 On Error Resume Next driver.FindElementByXPath("//button[text()='以后再说']", timeout:=2000).Click On Error GoTo 0 '-----------发送私信逻辑,全部使用显式等待 ' 点击新建消息按钮 driver.WaitForElementPresent "//button[contains(@aria-label, '新建消息')]", 10000 driver.FindElementByXPath("//button[contains(@aria-label, '新建消息')]").Click ' 输入收信人用户名 driver.WaitForElementPresent "//input[contains(@placeholder, '搜索')]", 5000 driver.FindElementByXPath("//input[contains(@placeholder, '搜索')]").SendKeys Sheet3.Range("C1").Value driver.Wait 1000 ' 选择第一个匹配的用户 driver.FindElementByXPath("//div[@role='dialog']//div[contains(text(), '" & Sheet3.Range("C1").Value & "')]").Click ' 点击聊天按钮 driver.WaitForElementPresent "//div[@role='dialog']//button[text()='聊天']", 3000 driver.FindElementByXPath("//div[@role='dialog']//button[text()='聊天']").Click ' 输入消息内容 driver.WaitForElementPresent "//textarea[contains(@placeholder, '发消息')]", 5000 driver.FindElementByXPath("//textarea[contains(@placeholder, '发消息')]").SendKeys Sheet3.Range("C2").Value ' 点击发送 driver.FindElementByXPath("//button[text()='发送']").Click Sheet3.Range("D2") = "o" 'Sending Check driver.Quit Set driver = Nothing End Sub
注:如果你的Instagram界面是英文,把XPath里的「以后再说」「新建消息」「搜索」「聊天」「发消息」「发送」替换成对应英文文本即可。
内容的提问来源于stack exchange,提问作者Dongha oh
相关产品推荐
相关产品推荐

