Selenium间歇性无法获取页面中JavaScript注入的venueProfile数据
如何确保Selenium爬取时JavaScript生成的venueProfile数据稳定加载?
问题描述
我用Selenium爬取页面https://www-eur.cvent.com/venues/en-US/dubai/hotel/delano-dubai/venue-12d8dd54-25d5-49f8-99a0-d292e52f3b34,目标是提取JavaScript注入到页面的venueProfile JSON数据,通过driver.page_source配合正则表达式查找。但现在的问题是,页面源码里有时能找到venueProfile字符串,有时找不到——原本以为用WebDriverWait等待<body>加载完成就能确保数据存在,但实际效果不稳定。
已尝试的操作
- 确认浏览器开发者工具中确实存在该字符串
- 失败时保存debug.html,确认源码中确实无该字符串
- 添加10秒以上的固定延迟等待
- 修改user-agent字符串为
Mozilla/5.0 - 验证无异常抛出,页面加载完成但数据缺失
最简复现代码
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By import re options = Options() options.add_argument("--headless") options.add_argument("user-agent=Mozilla/5.0") driver = webdriver.Chrome(options=options) driver.get("https://www-eur.cvent.com/venues/en-US/dubai/hotel/delano-dubai/venue-12d8dd54-25d5-49f8-99a0-d292e52f3b34") WebDriverWait(driver, 15).until( EC.presence_of_element_located((By.TAG_NAME, "body")) ) html = driver.page_source match = re.search(r'"venueProfile":"(.*?)"', html) print("Found" if match else "Not found") driver.quit()
解决方案与最佳实践
1. 直接等待目标数据/JS变量加载完成
不要等待<body>这种宽泛的条件,直接针对venueProfile做精准等待:
- 检查页面源码中是否出现目标字符串:
WebDriverWait(driver, 20).until( lambda driver: '"venueProfile"' in driver.page_source )
- 如果
venueProfile是挂载在window对象下的JS变量,直接检查变量是否存在:
WebDriverWait(driver, 20).until( lambda driver: driver.execute_script('return typeof window.venueProfile !== "undefined";') )
2. 等待包含目标数据的DOM元素
这类JS注入的数据通常会放在<script>标签里,直接等待该标签出现:
WebDriverWait(driver, 20).until( EC.presence_of_element_located((By.XPATH, '//script[contains(text(), "venueProfile")]')) )
3. 优化无头模式配置,模拟真实浏览器
无头模式下的渲染逻辑和正常浏览器有差异,添加这些参数提升兼容性:
options = Options() options.add_argument("--headless=new") # 新版无头模式,更接近正常Chrome options.add_argument("--disable-gpu") options.add_argument("--no-sandbox") options.add_argument("--window-size=1920,1080") # 避免响应式布局影响渲染 options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36")
4. 直接通过JS提取数据,避免依赖page_source
既然数据是JS生成的,直接在浏览器执行JS获取,比正则解析更可靠:
# 如果venueProfile是window下的对象 venue_data = driver.execute_script('return window.venueProfile;') # 如果数据在script标签内,先获取标签内容再解析 script_tag = driver.find_element(By.XPATH, '//script[contains(text(), "venueProfile")]') script_content = script_tag.get_attribute('innerHTML') # 再用正则或JSON库解析内容 match = re.search(r'"venueProfile":"(.*?)"', script_content)
5. 添加重试机制应对偶发失败
如果偶尔还是会出现加载失败,加个重试逻辑:
import time max_retries = 3 retry_count = 0 match = None while retry_count < max_retries and not match: html = driver.page_source match = re.search(r'"venueProfile":"(.*?)"', html) if not match: time.sleep(2) retry_count += 1 print("Found" if match else "Not found after retries")
优化后的完整代码示例
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By import re options = Options() options.add_argument("--headless=new") options.add_argument("--disable-gpu") options.add_argument("--no-sandbox") options.add_argument("--window-size=1920,1080") options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36") driver = webdriver.Chrome(options=options) driver.get("https://www-eur.cvent.com/venues/en-US/dubai/hotel/delano-dubai/venue-12d8dd54-25d5-49f8-99a0-d292e52f3b34") # 等待目标数据出现 WebDriverWait(driver, 20).until( lambda driver: '"venueProfile"' in driver.page_source ) html = driver.page_source match = re.search(r'"venueProfile":"(.*?)"', html) print("Found" if match else "Not found") driver.quit()
内容的提问来源于stack exchange,提问作者Faz
相关产品推荐
相关产品推荐

