等待页面使用 Python 版 Selenium WebDriver 加载
- 2024-11-28 08:38:00
- admin 原创
- 212
问题描述:
我想抓取无限滚动实现的页面的所有数据。以下 python 代码有效。
for i in range(100):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)
这意味着每次我向下滚动到页面底部时,我需要等待 5 秒钟,这通常足以让页面完成加载新生成的内容。但这可能不节省时间。页面可能在 5 秒内完成加载新内容。每次向下滚动时,我如何检测页面是否完成了新内容的加载?如果我能检测到这一点,一旦我知道页面已完成加载,我就可以再次向下滚动以查看更多内容。这更节省时间。
解决方案 1:
将webdriver
通过方法默认等待页面加载.get()
。
正如@user227215所说,您可能正在寻找某些特定元素,您应该使用它WebDriverWait
来等待位于您页面中的元素:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
browser = webdriver.Firefox()
browser.get("url")
delay = 3 # seconds
try:
myElem = WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'IdOfMyElement')))
print "Page is ready!"
except TimeoutException:
print "Loading took too much time!"
我曾用它来检查警报。您可以使用任何其他类型的方法来查找定位器。
编辑1:
我应该提到,webdriver
默认情况下会等待页面加载。它不会等待框架内或 ajax 请求的加载。这意味着当您使用时.get('url')
,您的浏览器将等到页面完全加载,然后转到代码中的下一个命令。但是当您发布 ajax 请求时,webdriver
不会等待,您有责任等待适当的时间来加载页面或页面的一部分;因此有一个名为的模块expected_conditions
。
解决方案 2:
尝试传递find_element_by_id
给构造函数(如接受的答案presence_of_element_located
所示)导致引发。我不得不使用fragles '评论中的语法:NoSuchElementException
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
driver.get('url')
timeout = 5
try:
element_present = EC.presence_of_element_located((By.ID, 'element_id'))
WebDriverWait(driver, timeout).until(element_present)
except TimeoutException:
print "Timed out waiting for page to load"
这与文档中的示例相符。以下是By 的文档链接。
解决方案 3:
有以下 3 种方法:
就绪状态
检查页面就绪状态(不可靠):
def page_has_loaded(self):
self.log.info("Checking if {} page is loaded.".format(self.driver.current_url))
page_state = self.driver.execute_script('return document.readyState;')
return page_state == 'complete'
这个
wait_for
辅助函数很好,但不幸的是,click_through_to_new_page
它容易受到竞争条件的影响,我们设法在旧页面中执行脚本,在浏览器开始处理点击之前,然后page_has_loaded
立即返回 true。
id
将新页面 ID 与旧页面 ID 进行比较:
def page_has_loaded_id(self):
self.log.info("Checking if {} page is loaded.".format(self.driver.current_url))
try:
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
except NoSuchElementException:
return False
比较 ID 可能不如等待陈旧引用异常那么有效。
staleness_of
使用staleness_of
方法:
@contextlib.contextmanager
def wait_for_page_load(self, timeout=10):
self.log.debug("Waiting for page to load at {}.".format(self.driver.current_url))
old_page = self.find_element_by_tag_name('html')
yield
WebDriverWait(self, timeout).until(staleness_of(old_page))
欲了解更多详情,请查看Harry 的博客。
解决方案 4:
正如David Cullen在回答中提到的那样,我总是看到建议使用如下一行:
element_present = EC.presence_of_element_located((By.ID, 'element_id'))
WebDriverWait(driver, timeout).until(element_present)
我很难找到可以与 一起使用的所有可能的定位器By
,所以我认为在这里提供列表会很有用。根据Ryan Mitchell 的《Web Scraping with Python》 :
ID
在示例中使用;通过 HTML id 属性查找元素
CLASS_NAME
用于通过 HTML 类属性查找元素。为什么这个函数
CLASS_NAME
不简单CLASS
?使用表单object.CLASS
会给 Selenium 的 Java 库带来问题,其中.class
是保留方法。为了保持不同语言之间的 Selenium 语法一致,CLASS_NAME
改用。
CSS_SELECTOR
#idName
使用,
.className
,约定,按类、id 或标签名称查找元素tagName
。
LINK_TEXT
根据标签所含文本查找 HTML 标签。例如,可以使用 选择“下一步”链接
(By.LINK_TEXT, "Next")
。
PARTIAL_LINK_TEXT
类似于
LINK_TEXT
,但匹配部分字符串。
NAME
根据名称属性查找 HTML 标签。这对于 HTML 表单来说非常方便。
TAG_NAME
根据标签名称查找 HTML 标签。
XPATH
使用 XPath 表达式...来选择匹配的元素。
解决方案 5:
来自selenium/webdriver/support/wait.py
driver = ...
from selenium.webdriver.support.wait import WebDriverWait
element = WebDriverWait(driver, 10).until(
lambda x: x.find_element_by_id("someId"))
解决方案 6:
你试过吗driver.implicitly_wait
?它就像驱动程序的一个设置,因此你只需在会话中调用一次,它基本上会告诉驱动程序等待给定的时间,直到每个命令都可以执行。
driver = webdriver.Chrome()
driver.implicitly_wait(10)
因此,如果您将等待时间设置为 10 秒,它将尽快执行命令,等待 10 秒后放弃。我在类似的向下滚动场景中使用过它,所以我不明白为什么它在您的例子中不起作用。希望这对您有帮助。
为了修复此答案,我必须添加新文本。请确保在 中使用小写“w” implicitly_wait
。
解决方案 7:
在这里我使用了一个相当简单的形式来实现:
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("url")
searchTxt=''
while not searchTxt:
try:
searchTxt=browser.find_element_by_name('NAME OF ELEMENT')
searchTxt.send_keys("USERNAME")
except:continue
解决方案 8:
针对持续加载数据的 ajax 页面的解决方案。所述预览方法不起作用。我们可以做的是抓取页面 dom 并对其进行哈希处理,然后在增量时间内将新旧哈希值进行比较。
import time
from selenium import webdriver
def page_has_loaded(driver, sleep_time = 2):
'''
Waits for page to completely load by comparing current page hash values.
'''
def get_page_hash(driver):
'''
Returns html dom hash
'''
# can find element by either 'html' tag or by the html 'root' id
dom = driver.find_element_by_tag_name('html').get_attribute('innerHTML')
# dom = driver.find_element_by_id('root').get_attribute('innerHTML')
dom_hash = hash(dom.encode('utf-8'))
return dom_hash
page_hash = 'empty'
page_hash_new = ''
# comparing old and new page DOM hash together to verify the page is fully loaded
while page_hash != page_hash_new:
page_hash = get_page_hash(driver)
time.sleep(sleep_time)
page_hash_new = get_page_hash(driver)
print('<page_has_loaded> - page not loaded')
print('<page_has_loaded> - page loaded: {}'.format(driver.current_url))
解决方案 9:
selenium 无法检测页面是否已完全加载,但 javascript 可以。我建议你试试这个。
from selenium.webdriver.support.ui import WebDriverWait
WebDriverWait(driver, 100).until(lambda driver: driver.execute_script('return document.readyState') == 'complete')
这将执行 javascript 代码而不是使用 python,因为 javascript 可以检测到页面何时完全加载,它会显示“完成”。此代码意味着在 100 秒内,继续尝试 document.readyState 直到显示完成。
解决方案 10:
您可以使用此功能非常简单地完成此操作:
def page_is_loading(driver):
while True:
x = driver.execute_script("return document.readyState")
if x == "complete":
return True
else:
yield False
当你想在页面加载完成后执行某些操作时,你可以使用:
Driver = webdriver.Firefox(options=Options, executable_path='geckodriver.exe')
Driver.get("https://www.google.com/")
while not page_is_loading(Driver):
continue
Driver.execute_script("alert('page is loaded')")
解决方案 11:
如何将 WebDriverWait 放入 While 循环并捕获异常。
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
browser = webdriver.Firefox()
browser.get("url")
delay = 3 # seconds
while True:
try:
WebDriverWait(browser, delay).until(EC.presence_of_element_located(browser.find_element_by_id('IdOfMyElement')))
print "Page is ready!"
break # it will break from the loop once the specific element will be present.
except TimeoutException:
print "Loading took too much time!-Try again"
解决方案 12:
在代码中使用它:
from selenium import webdriver
driver = webdriver.Firefox() # or Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://www.......")
或者,如果您正在寻找特定标签,则可以使用此代码:
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 as EC
driver = webdriver.Firefox() #or Chrome()
driver.get("http://www.......")
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "tag_id"))
)
finally:
driver.quit()
解决方案 13:
这里的答案非常好。等待的快速示例XPATH
。
# wait for sizes to load - 2s timeout
try:
WebDriverWait(driver, 2).until(expected_conditions.presence_of_element_located(
(By.XPATH, "//div[@id='stockSizes']//a")))
except TimeoutException:
pass
解决方案 14:
我费了一番功夫才让它工作,因为它并没有像我预期的那样发挥作用。任何仍在努力让它工作的人都可以检查一下。
我想等待元素出现在网页上后再继续进行操作。
我们可以使用 WebDriverWait(driver, 10, 1).until(),但问题是,until()需要一个函数,该函数可以每 1 秒执行一段时间(在我们的例子中是 10 次)。所以对我来说,保持下面的样子是可行的。
element_found = wait_for_element.until(lambda x: x.find_element_by_class_name("MY_ELEMENT_CLASS_NAME").is_displayed())
以下是Until()在幕后所做的事情
def until(self, method, message=''):
"""Calls the method provided with the driver as an argument until the \n return value is not False."""
screen = None
stacktrace = None
end_time = time.time() + self._timeout
while True:
try:
value = method(self._driver)
if value:
return value
except self._ignored_exceptions as exc:
screen = getattr(exc, 'screen', None)
stacktrace = getattr(exc, 'stacktrace', None)
time.sleep(self._poll)
if time.time() > end_time:
break
raise TimeoutException(message, screen, stacktrace)
解决方案 15:
如果您尝试滚动并查找页面上的所有项目。您可以考虑使用以下方法。这是其他人在这里提到的几种方法的组合。它对我来说很管用:
while True:
try:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
driver.implicitly_wait(30)
time.sleep(4)
elem1 = WebDriverWait(driver, 30).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "element-name")))
len_elem_1 = len(elem1)
print(f"A list Length {len_elem_1}")
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
driver.implicitly_wait(30)
time.sleep(4)
elem2 = WebDriverWait(driver, 30).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "element-name")))
len_elem_2 = len(elem2)
print(f"B list Length {len_elem_2}")
if len_elem_1 == len_elem_2:
print(f"final length = {len_elem_1}")
break
except TimeoutException:
print("Loading took too much time!")
解决方案 16:
nono = driver.current_url
driver.find_element(By.XPATH,"//button[@value='Send']").click()
while driver.current_url == nono:
pass
print("page loaded.")
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)