Selenium 错误:元素不再附加到 DOM

问题描述

我正在尝试使用 Selenium(通过 PhantomJS 无头)和 BeautifulSoup 从 https://sslproxies.org/ 获取代理列表:

这是我目前所做的:

from bs4 import BeautifulSoup
from selenium import webdriver

driver = webdriver.PhantomJS()
driver.set_window_size(1120,550)
driver.get("https://sslproxies.org/")

while True:
    try:
        next_button = driver.find_element_by_xpath("//li[@class='paginate_button next'][@id='proxylisttable_next']")
    
    except:
        break
    next_button.click()

    soup = BeautifulSoup(next_button.get_attribute('innerHTML'),'html.parser')

但我收到此错误

"errorMessage":"Element is no longer attached to the DOM"

解决方法

您正在定义 next_button,然后单击所述按钮,然后再次尝试引用 next_button 变量。您的点击导致您导航到另一个具有全新 DOM 的页面,您对 next_button 的定义不再有效。为避免这种情况,您可以简单地重新定义变量或始终使用整个

driver.find_element_by_xpath("//li[@class='paginate_button next'][@id='proxylisttable_next']")
,

1 您可以使用 for 循环遍历页面,但为此您需要获取页面数。根据站点的不同,获取页数的方法可能会有所不同。在你的情况下,这很容易。 你得到页面定位器列表+1的长度,像这样:len(driver.find_elements_by_xpath("//li[@class='paginate_button ']"))

2 您的定位器不正确,所以我将其更改为://li[@class='paginate_button next'][@id='proxylisttable_next']/a(添加了 /a

3 找到按钮后,在 finally 中单击它。

解决方案

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


driver = webdriver.Chrome(executable_path='/snap/bin/chromium.chromedriver')
driver.implicitly_wait(10)
driver.set_window_size(1120,550)
driver.get("https://sslproxies.org/")

wait = WebDriverWait(driver,10)
length = len(driver.find_elements_by_xpath("//li[@class='paginate_button ']"))
print(f"List length is: {length}")
for j in range(1,length+1):
    try:
        print("Clicking Page " + str(j+1))
        wait.until(
            EC.visibility_of_element_located((By.CSS_SELECTOR,"section[id='list']")))
        wait.until(EC.element_to_be_clickable((By.XPATH,"//li[@class='paginate_button next'][@id='proxylisttable_next']/a")))
    finally:
        next_button = driver.find_element_by_xpath(
            "//li[@class='paginate_button next'][@id='proxylisttable_next']/a")
        next_button.click()

附言我在 Chrome 上对其进行了测试,但它应该可以在任何浏览器中运行,因为我使用了稳定的定位器和等待。

我的调试输出:

List length is: 4
Clicking Page 2
Clicking Page 3
Clicking Page 4
Clicking Page 5