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')
我已经看过这个问题了,我猜想可以应用类似的修复程序,但是我不确定如何在页面上找到消失的东西。另外,根据打印语句的执行速度,我可以看到
implicitly_wait(10)
实际上并没有等待整整10秒钟。例外是指向以“ driver.execute_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
有时我会遇到ValueError:
ValueError: invalid literal for int() with base 10: ''
所以这些错误/ exceptions使我相信等待页面完全刷新时发生了某些事情。
#1 楼
此错误消息...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
...意味着该元素的先前引用现在已过时,并且该元素引用不再出现在页面的DOM中。
此问题背后的原因是:
该元素在HTML中的位置已更改。
该元素不再附加到DOM TREE。
该元素所在的网页的一部分已被刷新。
元素的先前实例已被JavaScript或AjaxCall刷新。
此用例
保留了滚动
scrollIntoView()
的概念并打印一些有用的调试消息,我对WebDriverWait进行了一些小的调整,您可以使用以下解决方案:代码块:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
options.add_argument("--disable-extensions")
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
driver.get("https://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sonicare+toothbrush")
while True:
try:
current_page_number_element = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "span.pagnCur")))
driver.execute_script("arguments[0].scrollIntoView(true);", current_page_number_element)
current_page_number = current_page_number_element.get_attribute("innerHTML")
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "span.pagnNextArrow"))).click()
print("page # {} : going to next page".format(current_page_number))
except:
print("page # {} : error, no more pages".format(current_page_number))
break
driver.quit()
控制台输出:
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
评论
这很棒!!!谢谢!第二个WebDriverWait行的目的是什么?
–玛丽亚·阿金比(Mariah Akinbi)
18/12/6在8:40
@MariahAkinbi在尝试滚动之前,首先要看到current_page_number_element的WebDriverWait。一旦我们已经滚动了第二个WebDriverWait的element_to_be_clickable,那么我们的解决方案就可以在跨平台上完美地工作了。
– DebanjanB
18/12/6在8:44
好吧,有道理!如果该元素可见,那是否意味着它是可单击的?还是我可以跳过可见的等待,而只使用可点击的等待-因为最重要的是是否可以点击?
–玛丽亚·阿金比(Mariah Akinbi)
18/12/6在8:49
不可以,如果该元素可见,则不能保证该元素是可单击的。理想情况下,如果您不单击可见的等待就足够了,但是在尝试单击之前,需要单击等待以使程序完美的跨平台。
– DebanjanB
18/12/6在8:58
#2 楼
如果只想让脚本遍历所有结果页面,则不需要任何复杂的逻辑-只要有可能,只需单击“下一步”按钮即可: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
PS还要注意,
implicitly_wait(10)
不应等待完整的10秒钟,而应等待10秒钟,以使元素出现在HTML DOM中。因此,如果在1或2秒钟内找到了元素,则等待完成,而您不会等待8-9秒钟的休息... 评论
像往常一样最干净的方法。
– SIM
18/12/6在7:37
@andersson,效果很好!谢谢!您怎么知道'a> span#pagnNextString'是合适的CSS选择器?当我检查下一个按钮并复制CSS选择器时,它显示为“ #pagnNextString”。另外,感谢您对explicitly_wait()的解释!
–玛丽亚·阿金比(Mariah Akinbi)
18/12/6在8:38
@MariahAkinbi,请注意,在最后一页上,“下一步”按钮(具有id =“ pagnNextString”的跨度)不是锚点(a)的子级,但是Selenium(出于某种原因)仍然“认为”它是可单击的。因此,要打破上一次迭代的循环,我们应该明确指定需要一个带有“ pagnNextString”子元素的链接,而不仅仅是元素“ pagnNextString”
–安德森
18/12/6在8:43
评论
您的情况是什么?预期输出是什么?一旦您单击(),它将加载一个新页面(带有一个新的DOM)。所以循环的第2次迭代中元素是陈旧的。