使用Python迭代时出现StaleElementException

使用Python迭代时出现StaleElementException,python,selenium,xpath,webdriverwait,staleelementreferenceexception,Python,Selenium,Xpath,Webdriverwait,Staleelementreferenceexception,我正在尝试为Amazon结果创建一个基本的web刮板。在遍历结果时,有时会进入结果的第5页(有时仅第2页),然后抛出StaleElementException。当抛出异常后查看浏览器时,我可以看到驱动程序/页面没有向下滚动到页码所在的位置(底部栏) 我的代码: driver.get('https://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sonicare+toothbrush')

我正在尝试为Amazon结果创建一个基本的web刮板。在遍历结果时,有时会进入结果的第5页(有时仅第2页),然后抛出
StaleElementException
。当抛出异常后查看浏览器时,我可以看到驱动程序/页面没有向下滚动到页码所在的位置(底部栏)

我的代码:

driver.get('https://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sonicare+toothbrush')

for page in range(1,last_page_number +1):

    driver.implicitly_wait(10)

    bottom_bar = driver.find_element_by_class_name('pagnCur')
    driver.execute_script("arguments[0].scrollIntoView(true);", bottom_bar)

    current_page_number = int(driver.find_element_by_class_name('pagnCur').text)

    if page == current_page_number:
        next_page = driver.find_element_by_xpath('//div[@id="pagn"]/span[@class="pagnLink"]/a[text()="{0}"]'.format(current_page_number+1))
        next_page.click()
        print('page #',page,': going to next page')
    else:
        print('page #: ', page,'error')
我已经看过了,我猜可以应用类似的修复,但我不确定如何在页面上找到消失的东西。另外,根据print语句发生的速度,我可以看到
隐式地等待(10)
实际上并没有等待整整10秒

异常指向以“driver.execute\u script”开头的行。这是一个例外:

StaleElementReferenceException: Message: The element reference of <span class="pagnCur"> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed

因此,这些错误/异常让我相信等待页面完全刷新是有问题的。

如果您只想让脚本在所有结果页面上迭代,您不需要任何复杂的逻辑,只要在可能的情况下单击“下一步”按钮即可:

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

driver = webdriver.Chrome()

driver.get('https://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sonicare+toothbrush')

while True:
    try:
        wait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'a > span#pagnNextString'))).click()
    except TimeoutException:
        break

另请注意,
隐式地等待(10)
不应该等待整整10秒,而是最多等待10秒,让元素出现在HTML DOM中。因此,如果在1秒或2秒内找到元素,则等待完成,您将不会等待剩余的8-9秒…

如果您只想让脚本在所有结果页面上迭代,您不需要任何复杂的逻辑-只要在可能的情况下单击“下一步”按钮即可:

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

driver = webdriver.Chrome()

driver.get('https://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sonicare+toothbrush')

while True:
    try:
        wait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'a > span#pagnNextString'))).click()
    except TimeoutException:
        break
另请注意,
隐式地等待(10)
不应该等待整整10秒,而是最多等待10秒,让元素出现在HTML DOM中。所以,如果在1或2秒内找到元素,则等待完成,您将不会等待剩余的8-9秒…

此错误消息

StaleElementReferenceException: Message: The element reference of <span class="pagnCur"> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed
  • 控制台输出:

    page # 1 : going to next page
    page # 2 : going to next page
    page # 3 : going to next page
    page # 4 : going to next page
    page # 5 : going to next page
    page # 6 : going to next page
    page # 7 : going to next page
    page # 8 : going to next page
    page # 9 : going to next page
    page # 10 : going to next page
    page # 11 : going to next page
    page # 12 : going to next page
    page # 13 : going to next page
    page # 14 : going to next page
    page # 15 : going to next page
    page # 16 : going to next page
    page # 17 : going to next page
    page # 18 : going to next page
    page # 19 : going to next page
    page # 20 : error, no more pages
    
  • 此错误消息

    StaleElementReferenceException: Message: The element reference of <span class="pagnCur"> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed
    
  • 控制台输出:

    page # 1 : going to next page
    page # 2 : going to next page
    page # 3 : going to next page
    page # 4 : going to next page
    page # 5 : going to next page
    page # 6 : going to next page
    page # 7 : going to next page
    page # 8 : going to next page
    page # 9 : going to next page
    page # 10 : going to next page
    page # 11 : going to next page
    page # 12 : going to next page
    page # 13 : going to next page
    page # 14 : going to next page
    page # 15 : going to next page
    page # 16 : going to next page
    page # 17 : going to next page
    page # 18 : going to next page
    page # 19 : going to next page
    page # 20 : error, no more pages
    

  • 您的方案是什么?预期的输出是什么?一旦您
    单击()
    ,它将加载一个新页面(带有新的DOM)。因此,在循环的第二次迭代中,元素过时了。您的场景是什么?预期的输出是什么?一旦您
    单击()
    ,它将加载一个新页面(带有新的DOM)。所以,循环的第二次迭代中,元素过时了。最干净的方法和往常一样。@andersson这很好地工作了!非常感谢。您如何知道“a>span#pagnNextString”是合适的css选择器?当我检查next按钮并复制css选择器时,它显示为“#pagnNextString”。另外,感谢您的含蓄解释_wait()@MariahAkinbi,请注意,在最后一页上,“下一步”按钮(span with
    id=“pagnNextString”
    )不是锚(
    a
    )的子按钮,但Selenium(出于某种原因)仍然“认为”它是可点击的。因此,为了在上一次迭代中打破循环,我们应该明确指定我们需要一个带有
    “pagnNextString”
    子元素的链接,而不仅仅是元素
    “pagnNextString”
    最干净的方法。@Anderson这很好地工作了!非常感谢。您如何知道“a>span#pagnNextString”是合适的css选择器?当我检查next按钮并复制css选择器时,它显示为“#pagnNextString”。另外,感谢您的含蓄解释_wait()@MariahAkinbi,请注意,在最后一页上,“下一步”按钮(span with
    id=“pagnNextString”
    )不是锚(
    a
    )的子按钮,但Selenium(出于某种原因)仍然“认为”它是可点击的。因此,为了在上一次迭代中打破循环,我们应该明确指定我们需要一个带有
    “pagnNextString”
    子元素的链接,而不仅仅是元素
    “pagnNextString”
    这非常有效!!!非常感谢。第二行WebDriverWait的用途是什么?@MariahAkinbi First
    WebDriverWait
    在我们尝试滚动之前,当前的页面号元素是可见的。一旦我们已经滚动了第二个
    WebDriverWait
    ,使
    元素可点击
    ,那么我们的解决方案就可以完美地跨平台工作了。好吧,这是有意义的!如果元素是可见的,这不意味着它是可点击的吗?或者我可以跳过可见的等待,只使用可点击的等待,因为重要的是它是否可点击?不,如果元素是可见的,则不能保证它是可点击的。理想情况下,如果您没有单击“可见”,等待就足够了,但在您尝试单击之前,需要单击“等待”,以使您的程序无缺陷地跨平台运行。这非常有效!!!非常感谢。第二行WebDriverWait的用途是什么?@MariahAkinbi First
    WebDriverWait
    在我们尝试滚动之前,当前的页面号元素是可见的。一旦我们已经滚动了第二个
    WebDriverWait
    ,使
    元素可点击
    ,那么我们的解决方案就可以完美地跨平台工作了。好吧,这是有意义的!如果元素是可见的,这不意味着它是可点击的吗?或者我可以跳过可见的等待,只使用可点击的等待,因为重要的是它是否可点击?不,如果元素是可见的,则不能保证它是可点击的。理想情况下,如果您没有单击visible wait(可见等待)就足够了,但在您尝试单击之前,需要单击wait(等待),以使您的程序无缺陷地跨平台运行。