【问题标题】:How to refresh Selenium Webdriver DOM data without reloading page?如何在不重新加载页面的情况下刷新 Selenium Webdriver DOM 数据?
【发布时间】:2018-06-23 02:26:07
【问题描述】:

我使用 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 获取新元素?

【问题讨论】:

  • 您应该能够再次使用元素选择器来获取页面上元素的新副本。
  • @andrewgu 你能解释一下吗?如果我使用find_elements,我会在StaleError 的每2-7 次测试中获得带有旧元素ID 的列表。并非总是如此,但仍然无法使用。
  • 您确定您使用的浏览器在您尝试选择它们之前实际创建了新元素吗?尝试在搜索和重新选择元素之间添加更长的延迟以进行测试。
  • 有等待页面更新的方法,但这取决于您的具体情况。快速搜索出现this SO question。如果您想继续对话,我建议将其移至聊天(Selenium IRC 或 SE 聊天)。同时,出于测试目的,我建议您延长等待时间,我想看看这是否有帮助。
  • @sortas 我不打算这样做,因为我认为您的问题可能是骗人的,但我希望我的回答能帮助您指导您!我的回答比我们的 cmets 更深入(使用示例代码)。很高兴看到您稍微修改您的问题以提高专业水平,并且您现在对您的问题有了更好的了解。一些sn-ps的代码显示你也不会受到伤害!

标签: python python-3.x selenium selenium-webdriver webdriver


【解决方案1】:

在不了解页面内容的情况下,很难为您的问题制定解决方案。

当您的 Selenium 代码从 webdriver 中选择元素时,它会在您的选择器代码执行时加载页面,这意味着页面确实不需要重新加载以检索新的元素。相反,您的问题似乎是页面上尚不存在元素,这意味着当您的选择器尝试获取元素的新副本时,搜索结果可能尚未加载。


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

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 搜索加载图标或查看结果是否更改。一个好的起点是查看WebDriverWait's in Selenium

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 预搜索以清除任何现有结果或与您的选择器匹配的元素。这应该可以解决您的 Selenium 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 的搜索,这可能是获得搜索结果的最佳(性能、可靠性)方式。

【讨论】:

    【解决方案2】:

    您只需要再次要求驱动程序获取元素,重复使用相同的 sn-p :

    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 reload 改变的新对象,而它的描述是一样的!

    【讨论】:

      猜你喜欢
      • 2017-06-27
      • 1970-01-01
      • 2022-11-29
      • 2013-08-20
      • 2011-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多