了解并修复 Selenium 中的常见 JavaScript 错误
当网页抓取时 硒网络驱动程序,遇到与 JavaScript 相关的错误并不罕见,尤其是在处理动态 Web 元素时,例如 影子 DOM。开发人员经常遇到的一个错误是 JavascriptException:无法读取 null 的属性(读取“shadowRoot”),这在与复杂页面元素交互时经常发生。
当 Selenium 无法访问或与 a 中的元素交互时,通常会出现此错误 影子 DOM,一种独特类型的封装 DOM 结构,许多现代网站都使用它来实现更好的模块化。在 Python 中,使用 Selenium 来控制浏览器对于此类元素可能会很棘手。
在从 Shopee 等平台进行网页抓取的情况下,弹出窗口或横幅通常会使用影子 DOM,这可能很难以编程方式关闭。此问题可能会阻碍自动化任务的顺利进行并扰乱数据收集。
本指南将引导您找到一个明确的解决方案来解决 “无法读取 Null 的属性” 错误并提供了一种实用的方法来关闭 Shopee 中嵌入 Shadow DOM 的弹出窗口,使用 Python 硒。
命令 | 使用示例 |
---|---|
shadowRoot | 这用于访问影子 DOM 中的元素。 Shadow DOM 将某些元素与主 DOM 树隔离,需要 ShadowRoot 属性才能访问它们。在此脚本中,它用于定位弹出窗口内的关闭按钮。 |
execute_script() | 此 Selenium 方法允许在浏览器会话中执行原始 JavaScript。在与影子 DOM 元素交互时,这一点至关重要,因为传统的 Selenium 方法可能不起作用。 |
WebDriverWait() | 此命令在 Selenium 中设置显式等待。它确保脚本等待直到满足指定条件,例如元素变得可单击。这对于动态内容加载至关重要,正如 Shopee 的弹出窗口所示。 |
expected_conditions | 该模块包含可与 WebDriverWait 一起使用的条件,例如元素可见性或存在。它确保只有当目标元素准备就绪时才会发生单击等操作。 |
EC.presence_of_element_located() | 与 WebDriverWait 一起使用的条件,以确保目标元素存在于 DOM 中。当等待影子 DOM 中的元素加载时,这特别有用。 |
EC.element_to_be_clickable() | WebDriverWait 的另一个有用条件是,这可确保目标元素在尝试任何交互之前可见且可单击,从而减少动态网页中的错误。 |
By.CSS_SELECTOR | 此方法允许通过 CSS 选择器定位元素。当定位影子 DOM 内的元素时,它特别有用,因为使用标准 XPath 方法可能无法访问这些元素。 |
driver.quit() | 确保脚本运行完毕后正确关闭浏览器实例。避免保持打开的浏览器会话是一个重要的最佳实践。 |
如何在 Selenium 网页抓取中处理 Shadow DOM 和弹出窗口
上面提供的脚本旨在解决网络抓取中遇到的常见问题 硒网络驱动程序 与影子 DOM 元素交互时。影子 DOM 是网页的一部分,与主 DOM 分开运行,通常在复杂的 Web 组件中使用。在像 Shopee 这样的抓取网站中,弹出窗口经常出现在影子 DOM 中,如果使用传统的 Selenium 方法访问,可能会导致错误。第一个脚本旨在使用 JavaScript 执行来关闭弹出窗口 执行脚本(),一个强大的工具,允许 Selenium 在浏览器上下文中运行原始 JavaScript。
关键的挑战是影子 DOM 中的元素无法使用常见的 Selenium 命令访问,例如 按_xpath查找元素()。相反,我们使用 JavaScript 来遍历 Shadow DOM,使用 影子根 财产。该脚本通过首先访问其影子主机元素,然后查询其内部结构来定位 Shopee 弹出窗口的关闭按钮。通过利用 驱动程序.execute_script(),脚本能够操作和关闭这个隔离 DOM 内的元素。当与显式等待相结合来处理异步加载的动态页面元素时,此解决方案效果很好。
第二个脚本介绍 WebDriver等待,管理动态页面元素时序的重要工具。由于 Shopee 的弹出窗口是异步加载的,直接与这些元素交互可能会导致错误。为了避免这种情况, WebDriver等待() 确保我们希望与之交互的元素已完全加载并准备就绪。该脚本等待主 DOM 元素和影子 DOM 元素的存在。方法 EC.presence_of_element_ located() 确保 Selenium 仅在元素可见且存在后才与元素交互,这对于避免空引用错误至关重要。
在这两个脚本中,我们都使用 尝试例外 阻止以确保程序不会因意外错误(例如未找到元素)而崩溃。在抓取经常更新其结构或更改弹出行为的网站时,错误处理尤为重要。此外,这些脚本通过使用终止浏览器会话来遵循最佳实践 驱动程序.quit() 执行后以避免内存泄漏或性能问题。
在 Python 中使用 Selenium 处理 Shadow DOM 并关闭弹出窗口
使用 Python 和 Selenium WebDriver 与 Shadow DOM 元素交互并动态处理弹出窗口。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import JavascriptException
import time
# Initialize WebDriver with Chrome
options = Options()
driver = webdriver.Chrome(service=Service(), options=options)
# Open Shopee website
driver.get('https://www.shopee.co.th/')
# Click the Thai language button
th_button = driver.find_element(By.XPATH, '/html/body/div[2]/div[1]/div[1]/div/div[3]/div[1]/button')
th_button.click()
# Pause to allow popups to load
time.sleep(3)
# Try to close the shadow DOM popup
try:
close_button = driver.execute_script('return document.querySelector("shopee-banner-popup-stateful")'
'.shadowRoot.querySelector("div.shopee-popup__close-btn")')
close_button.click()
except JavascriptException as e:
print("Error: ", e)
# Close the browser
driver.quit()
使用 WebDriverWait 进行 Shadow DOM 交互
在 Selenium 中使用显式等待来确保 Shadow DOM 中的元素已准备好进行交互。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# Initialize WebDriver with Chrome
options = Options()
driver = webdriver.Chrome(service=Service(), options=options)
# Open Shopee website
driver.get('https://www.shopee.co.th/')
# Click the Thai language button
th_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, '/html/body/div[2]/div[1]/div[1]/div/div[3]/div[1]/button'))
)
th_button.click()
# Wait for the shadow DOM popup to be present
try:
shadow_host = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'shopee-banner-popup-stateful'))
)
shadow_root = driver.execute_script('return arguments[0].shadowRoot', shadow_host)
close_button = shadow_root.find_element(By.CSS_SELECTOR, 'div.shopee-popup__close-btn')
close_button.click()
except Exception as e:
print("Error closing the popup: ", e)
# Close the browser
driver.quit()
使用 Selenium WebDriver 处理动态内容
使用 Selenium WebDriver 进行网页抓取时要考虑的另一个关键方面是如何处理 动态内容 页面加载后不断更新或更改。许多现代网站(例如 Shopee)使用 JavaScript 动态加载和更新内容。这意味着页面加载后页面上的元素可能无法立即可用。在这种情况下,Selenium 等待页面加载事件的默认行为可能不够。使用显式等待,例如 WebDriver等待 可以通过等待特定元素出现或变得可点击来解决此问题。
用于抓取带有弹出窗口、横幅或依赖于以下内容的复杂 UI 组件的网站 影子 DOM,了解如何与他们互动非常重要。这些组件将元素隐藏在独立的 DOM 结构中,无法通过 XPath 或 CSS 选择器等传统方法访问。使用 执行脚本() 该命令允许您直接在浏览器中运行 JavaScript,允许您访问影子 DOM,并允许与页面隐藏部分中的关闭按钮或表单字段等元素进行交互,从而帮助弥补这一差距。
此外,在这种情况下,错误处理变得至关重要。网站经常会改变其结构,导致抓取工具损坏。正确使用 尝试例外 Python 中的块允许您捕获错误,例如 JavaScript异常 并优雅地处理它们,确保铲运机不会意外崩溃。结合日志记录来捕获错误详细信息可以帮助识别根本原因并在将来的抓取中解决它。
有关在 Selenium 中处理 Shadow DOM 和弹出窗口的常见问题
- 什么是 Shadow DOM,为什么它难以访问?
- 这 shadow DOM 是一个独立的 DOM 树,Web 开发人员用它来封装元素并防止它们受到主文档中的样式或脚本的影响。由于传统的 Selenium 方法不支持与影子 DOM 元素直接交互,因此很难访问。
- 怎么样 execute_script() 帮助与 Shadow DOM 交互?
- execute_script() 允许直接在浏览器会话中运行 JavaScript,从而能够访问影子 DOM 元素,否则使用常规 Selenium 命令无法访问这些元素。
- 为什么是 WebDriverWait 对于抓取动态内容很重要吗?
- WebDriverWait 确保脚本在与其交互之前等待特定条件,例如元素可单击或存在。这对于处理异步加载的动态内容至关重要。
- 遇到时我该怎么办 JavascriptException?
- JavascriptException 当执行 JavaScript 代码出现问题时会发生。使用实现错误处理 try-except 块可以帮助捕获和管理这些错误,而不会导致整个脚本崩溃。
- 如何关闭使用 Shadow DOM 的动态弹出窗口?
- 要关闭封装在影子 DOM 中的动态弹出窗口,您需要首先使用以下命令访问影子根 execute_script() 然后找到 Shadow DOM 内的弹出关闭按钮。
关于在 Selenium 中处理 Shadow DOM 的最终想法
使用 Selenium 进行网页抓取时,与影子 DOM 元素交互可能具有挑战性。然而,通过利用 JavaScript 执行和显式等待,您可以有效地管理使用标准方法难以访问的元素。
通过正确处理错误并合并等待,您可以确保您的抓取脚本健壮且可靠。这些技术将有助于避免处理嵌入在影子 DOM 中的动态内容和弹出窗口时的常见陷阱,从而确保更流畅的抓取体验。
在 Selenium 中处理 Shadow DOM 的有用来源和参考
- 有关与 Selenium 中的 Shadow DOM 元素交互的信息,来自 Selenium WebDriver 文档 。
- 关于处理 JavascriptException 错误的见解 堆栈溢出 。
- 使用网页抓取动态内容的最佳实践指南 真正的Python 。