Selenium ChromeDriver报错:No node with given id found 求助
问题描述
使用Python 3.10.5 + Selenium + ChromeDriver 113.0.5672.63在Windows 10环境下编写爬虫脚本,通过多级页面导航(省→市→区→社区)点击按钮获取数据,固定迭代次数后触发报错(如provinsi[0]在689次迭代后报错,provinsi[1]在35次后报错)。已尝试添加time.sleep(1)、检查元素可见性与可点击性,问题仍存在。
报错信息
WebDriverException: Message: unknown error: unhandled inspector error: {"code":-32000,"message":"No node with given id found"}
脚本代码
url = '.../' path = Service(r'...\chromedriver_win32') options = Options() options.add_experimental_option("debuggerAddress", "localhost:9222") driver = webdriver.Chrome(service=path, options=options) driver.get(url) wait = WebDriverWait(driver, 10) def scrape_left_table(prob, kab, kec): data = [] rows = driver.find_elements(By.CSS_SELECTOR, 'div:nth-child(1) > table > tbody > tr') for row in rows: wilayah = row.find_element(By.CSS_SELECTOR, 'td.text-xs-left.wilayah-name > button').text persentasi = row.find_element(By.CSS_SELECTOR, 'td.text-xs-left.wilayah-name > span').text class_1= row.find_element(By.CSS_SELECTOR, 'td:nth-child(2)').text class_2= row.find_element(By.CSS_SELECTOR, 'td:nth-child(3)').text data.append([prob, kab, kec, wilayah, persentasi, class_1, class_2]) return data def scrape_right_table(prob, kab, kec): data = [] rows = driver.find_elements(By.CSS_SELECTOR, 'div:nth-child(2) > table > tbody > tr') for row in rows: wilayah = row.find_element(By.CSS_SELECTOR, 'td.text-xs-left.wilayah-name > button').text persentasi = row.find_element(By.CSS_SELECTOR, 'td.text-xs-left.wilayah-name > span').text class_1= row.find_element(By.CSS_SELECTOR, 'td:nth-child(2)').text class_2= row.find_element(By.CSS_SELECTOR, 'td:nth-child(3)').text data.append([prob, kab, kec, wilayah, persentasi, class_1, class_2]) return data data = [] provinsi = driver.find_elements(By.CSS_SELECTOR, 'div:nth-child(1) > table > tbody > tr') button = provinsi[1].find_element(By.TAG_NAME, 'button') pro = button.text wait.until(EC.element_to_be_clickable(button)).click() wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, 'div:nth-child(1) > table > tbody > tr'))) for i in [1,2]: time.sleep(1) kabupaten = driver.find_elements(By.CSS_SELECTOR, 'div:nth-child(' + str(i) + ') > table > tbody > tr') for kab in kabupaten: time.sleep(1) wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, 'div:nth-child(' + str(i) + ') > table > tbody > tr'))) kab_button = kab.find_element(By.TAG_NAME, 'button') kab_name = kab_button.text driver.execute_script("arguments[0].scrollIntoView();", kab_button) driver.execute_script("arguments[0].click();", kab_button) for i in [1,2]: time.sleep(1) kecamatan = driver.find_elements(By.CSS_SELECTOR, 'div:nth-child(' + str(i) + ') > table > tbody > tr') for kec in kecamatan: wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, 'div:nth-child(' + str(i) + ') > table > tbody > tr'))) kec_button = kec.find_element(By.CSS_SELECTOR, 'td.text-xs-left.wilayah-name > button') kec_name = kec_button.text driver.execute_script("arguments[0].scrollIntoView();", kec_button) driver.execute_script("arguments[0].click();", kec_button) kelurahan = driver.find_elements(By.CSS_SELECTOR, 'div:nth-child(1) > table > tbody > tr') time.sleep(1) left_table = scrape_left_table(pro, kab_name, kec_name) right_table = scrape_right_table(pro, kab_name, kec_name) data += left_table + right_table back = driver.find_element(By.CSS_SELECTOR, '#app > div.sticky-top.bg-white > div > div:nth-child(2) > div > div > div > div:nth-child(5) > div > div > div.vs__actions > button') driver.execute_script("arguments[0].scrollIntoView();", back) driver.execute_script("arguments[0].click();", back) back = driver.find_element(By.CSS_SELECTOR, '#app > div.sticky-top.bg-white > div > div:nth-child(2) > div > div > div > div:nth-child(4) > div > div > div.vs__actions > button') driver.execute_script("arguments[0].scrollIntoView();", back) driver.execute_script("arguments[0].click();", back)
报错栈信息
WebDriverException Traceback (most recent call last) c:\...\web_scraping.ipynb Cell 4 in () 23 for kec in kecamatan: 24 wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, 'div:nth-child(' + str(i) + ') > table > tbody > tr'))) ---> 26 kec_button = kec.find_element(By.CSS_SELECTOR, 'td.text-xs-left.wilayah-name > button') 27 kec_name = kec_button.text 28 driver.execute_script("arguments[0].scrollIntoView();", kec_button) WebDriverException: Message: unknown error: unhandled inspector error: {"code":-32000,"message":"No node with given id found"}
解决方案
核心原因
报错本质是元素引用失效(Stale Element Reference):提前获取的kecamatan元素列表,在点击进入下级页面再返回后,页面DOM已刷新,旧的kec元素引用无法对应新DOM中的节点,此时调用kec.find_element就会触发"No node with given id found"。另外代码存在变量名冲突、固定sleep不可靠等问题,加剧了报错概率。
具体修复步骤
- 放弃复用旧元素引用,每次循环重新定位
不要一次性获取所有行再循环,改为先获取行数量,再通过索引逐行重新定位元素,确保每次拿到的都是当前DOM中的有效元素:
# 替换原kecamatan循环逻辑 for j in [1,2]: wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, f'div:nth-child({j}) > table > tbody > tr'))) # 获取当前页面的行总数 kec_row_count = len(driver.find_elements(By.CSS_SELECTOR, f'div:nth-child({j}) > table > tbody > tr')) # 通过索引循环,每次重新定位元素 for kec_idx in range(kec_row_count): kec = driver.find_element(By.CSS_SELECTOR, f'div:nth-child({j}) > table > tbody > tr:nth-child({kec_idx+1})') # 后续操作不变
- 修复变量名冲突
嵌套循环中重复使用i变量,会导致外层循环的i被内层覆盖,导致CSS选择器定位错误。把内层循环的i改为j:
# 原内层循环 # for i in [1,2]: # 修改为 for j in [1,2]:
- 替换固定sleep为显式等待
删掉所有time.sleep(1),用WebDriverWait等待元素就绪,既保证元素加载完成,又避免不必要的等待:
# 替换time.sleep(1) wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, f'div:nth-child({j}) > table > tbody > tr')))
优化元素定位稳定性
避免使用div:nth-child(1)这种依赖DOM顺序的选择器,尽量用元素的专属class或属性。比如如果表格有region-list-table类,就用div.region-list-table > table,减少页面结构变化带来的定位失败。简化返回按钮定位
原返回按钮的CSS选择器过长且依赖DOM结构,可简化为:
# 用文本定位(如果按钮有返回文本) back = wait.until(EC.element_to_be_clickable((By.XPATH, '//button[contains(text(), "返回")]'))) back.click() # 或用按钮的图标class定位 back = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button.vs__clear'))) back.click()
修复后的关键代码片段
# 外层kabupaten循环 for i in [1,2]: wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, f'div:nth-child({i}) > table > tbody > tr'))) kab_row_count = len(driver.find_elements(By.CSS_SELECTOR, f'div:nth-child({i}) > table > tbody > tr')) for kab_idx in range(kab_row_count): kab = driver.find_element(By.CSS_SELECTOR, f'div:nth-child({i}) > table > tbody > tr:nth-child({kab_idx+1})') kab_button = kab.find_element(By.TAG_NAME, 'button') kab_name = kab_button.text wait.until(EC.element_to_be_clickable(kab_button)).click() # 内层kecamatan循环,变量名改为j for j in [1,2]: wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, f'div:nth-child({j}) > table > tbody > tr'))) kec_row_count = len(driver.find_elements(By.CSS_SELECTOR, f'div:nth-child({j}) > table > tbody > tr')) for kec_idx in range(kec_row_count): # 每次重新定位kec元素 kec = driver.find_element(By.CSS_SELECTOR, f'div:nth-child({j}) > table > tbody > tr:nth-child({kec_idx+1})') kec_button = kec.find_element(By.CSS_SELECTOR, 'td.text-xs-left.wilayah-name > button') kec_name = kec_button.text wait.until(EC.element_to_be_clickable(kec_button)).click() # 等待表格加载完成后抓取数据 wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'div:nth-child(1) > table > tbody > tr'))) left_table = scrape_left_table(pro, kab_name, kec_name) right_table = scrape_right_table(pro, kab_name, kec_name) data += left_table + right_table # 返回kecamatan列表,等待页面加载完成 back = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#app > div.sticky-top.bg-white > div > div:nth-child(2) > div > div > div > div:nth-child(5) > div > div > div.vs__actions > button'))) back.click() wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, f'div:nth-child({j}) > table > tbody > tr'))) # 返回kabupaten列表,等待页面加载完成 back = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#app > div.sticky-top.bg-white > div > div:nth-child(2) > div > div > div > div:nth-child(4) > div > div > div.vs__actions > button'))) back.click() wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, f'div:nth-child({i}) > table > tbody > tr')))
内容的提问来源于stack exchange,提问作者Alvanzah
相关产品推荐
相关产品推荐

