如何在不重新加载页面的情况下刷新硒网络驱动程序 DOM 数据?



我使用Selenium和Python来解析来自数据库站点的搜索结果。搜索输出是动态的,因此,当我键入新请求时,页面不会重新加载,但搜索结果是新的。

问题是Selenium不会更新WebDriver DOM数据,所以下次我尝试类似driver.find_elements_by_class_name('query_header')我从以前的搜索请求和StaleError中接收元素。

使用WebDriverWait(driver, timeout).until(element_present)无济于事。元素在那里(所有搜索结果块都有相同的类、名称等),但它们是旧的:)

我通过在每次请求后重新加载带有driver.refresh()的页面来修复它,但它看起来有点不自然 + 双重请求。

有没有办法刷新Selenium DOM数据,这样我就可以在不重新加载页面的情况下获得带有find_elements的新元素?

如果不知道页面的内容,就很难为您的问题制定解决方案。

当您的 Selenium 代码从 Web 驱动程序中选择元素时,它会在页面上执行此操作,就像在您的选择器代码执行时加载的那样,这意味着不需要重新加载页面即可检索新元素。相反,您的问题似乎是页面上尚不存在这些元素,这意味着当您的选择器尝试获取元素的新副本时,搜索结果可能尚未加载。


一个简单的解决方案是增加开始搜索和选择搜索结果之间的等待时间,以便页面有时间加载搜索结果

from selenium import webdriver
import time
# Load page
driver = webdriver.Firefox()
driver.get('https://www.example.com')
# Begin search
driver.find_element_by_tag_name('a').click()
# Wait for search results to load
time.sleep(5)
# Retrieve search results
results = driver.find_elements_by_class_name('result')

这样做的缺点是它实际上取决于网络 QoS 以及在您的页面上执行搜索查询所需的时间。


一个更复杂但规范的解决方案是等待页面加载搜索结果,也许通过检查 Ajax 搜索加载图标或查看结果是否更改。一个好的起点是看看Selenium中的WebDriverWait。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
# Load page
driver = webdriver.Firefox()
driver.get('https://www.example.com')
# Begin search
driver.find_element_by_tag_name('a').click()
# Wait for search results to load
WebDriverWait(driver, 30).until(
expected_conditions.invisibility_of_element_located((By.ID, 'ajax_loader'))
)
# Retrieve search results
results = driver.find_elements_by_class_name('result')

这种方法的缺点是可能需要花费大量时间来弄清楚如何使其工作,并且需要针对您要等待更新的每个页面进行自定义。

你提到这种方法似乎不适合你。对此的建议是(如果它不会破坏页面)在等待新结果加载之前操作 DOM 预搜索以清除与您的选择器匹配的任何现有结果或元素。这应该可以解决在等待与搜索结果选择器匹配的元素时硒WebDriverWait的问题。

driver.execute_script("el = document.getElementById('#results');el.parentElement.removeChild(el)")

此外,由于您提到页面不应重新加载,因此可能是您的页面正在使用 Ajax 加载搜索结果,然后使用 JavaScript 修改 DOM。检查网络流量(大多数浏览器的 DevTools 应该有一个"网络"选项卡)并尝试对网站发送搜索查询和解析数据的方式进行逆向工程可能会很有用。

import requests
# Search term (birds)
term = 'ja'
# Send request
request = requests.get('https://jqueryui.com/resources/demos/autocomplete/search.php?term=' + term)
# Print response
print(request.json())

这可能会违反某些站点的 TOS 或政策(实际上这些方法中的任何一种都可能),因此请注意这一点,并且一开始可能很难找到如何在比页面加载后在 DOM 上加载的级别更低的级别发送和解析请求更传统。从好的方面来说,这可能是获取搜索结果的最佳(性能、可靠性)方式,假设使用了类似 Ajax 的搜索。

你只需要要求驱动程序再次获取元素,重用相同的代码片段:

var X = driver.findElement( By.xpath("myxpath") ); //suppose element A is returned
//...do things
// the dom is reloaded
//copy paste the same command again :
var Y = driver.findElement( By.xpath("myxpath") ); //element B shall be returned after the dom has been updated.

然后 Y 将是 dom 重新加载更改的新对象,而它的描述是完全相同的!

最新更新