C#使用Selenium Chromedriver爬谷歌地图出现stale element reference报错如何解决
错误原因
StaleElementReferenceException 触发的核心原因是首次在搜索结果页获取的companies元素集合,所有元素均绑定原搜索结果页的DOM节点,当第一次循环调用driver.Navigate().GoToUrl(companyurl)跳转到商家详情页后,原搜索结果页的DOM被完全卸载,之前缓存的companies集合内的所有剩余元素都已经和原页面脱离关联,第二次循环访问元素属性时自然触发异常。
可行解决方案
修改逻辑为先在搜索结果页一次性收集所有商家的href链接存入字符串集合,再遍历字符串集合跳转爬取详情,无需持有原页面元素对象,完全规避stale元素问题。
修改后代码
var chromeDriverService = ChromeDriverService.CreateDefaultService(); chromeDriverService.HideCommandPromptWindow = true; ChromeOptions options = new ChromeOptions(); options.AddExcludedArgument("excludeSwitches"); options.AddExcludedArgument("useAutomationExtension"); options.AddArguments("ignore-certificate-errors"); options.AddArguments("start-maximized"); options.AddArguments("enable-automation"); options.AddArguments("--log-level=OFF"); //options.AddArguments("headless"); options.AddArguments("--disable-blink-features=AutomationControlled"); var driver = new ChromeDriver(chromeDriverService, options); Actions builder = new Actions(driver); driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(15); driver.Navigate().GoToUrl("https://www.google.co.uk/maps/search/lincoln+plumbers/"); try { driver.FindElement(By.CssSelector("#yDmH0d > c-wiz > div > div > div > div.NIoIEf > div.G4njw > div.AIC7ge > form > div > div > button > span")).Click(); // 短暂等待确保页面交互后加载完成 Thread.Sleep(2000); } catch { } // 提前提取所有商家链接存入字符串列表,不持有原页面元素对象 List<string> companyUrlList = new List<string>(); var companyElements = driver.FindElements(By.XPath("//*[@id=\"pane\"]/div/div[1]/div/div/div[4]/div[1]/div/div/a")); foreach (var ele in companyElements) { string href = ele.GetAttribute("href"); if(!string.IsNullOrEmpty(href)) { companyUrlList.Add(href); } } // 遍历字符串链接集合爬取详情,无stale元素风险 foreach (var url in companyUrlList) { try { driver.Navigate().GoToUrl(url); // 等待详情页加载完成,可替换为显式等待提升效率 Thread.Sleep(1500); var companyName = driver.FindElement(By.TagName("h1")).Text; Console.WriteLine(companyName); } catch (Exception ex) { Console.WriteLine(ex); } } Console.ReadLine();
可选优化点
- 将硬编码的
Thread.Sleep替换为Selenium官方的WebDriverWait显式等待,既可以提升爬取效率,也能避免网络波动导致的元素未加载异常 - 谷歌地图搜索结果为滚动加载逻辑,若需要爬取全量结果,可以先模拟滚动列表到最底部,加载完全部商家元素后再统一提取href
- 若有需要复用搜索结果页的场景,也可以每次爬取详情后调用
driver.Navigate().Back()返回列表页,重新获取元素集合后再爬取下一个,但该方案稳定性低于提前提取链接的方案
内容的提问来源于stack exchange,提问作者MattHodson
相关产品推荐
相关产品推荐

