如何让Selenium WebDriver获取与requests一致的网页响应?
问题描述
原本基于requests的代码可正常运行:
response = requests.get(url).text soup = BeautifulSoup(response, 'html.parser')
替换为Selenium WebDriver实现后:
driver = web_driver() response = driver.page_source soup = BeautifulSoup(response, 'html.parser')
两者获取的响应存在差异,导致后续代码报错。想知道:
- 是否有办法让Selenium WebDriver获取与
requests完全一致的响应? - 若可行,是否存在适配所有URL的通用方案?
使用示例:在从URL https://int.soccerway.com/teams/egypt/pharco/38185/squad/ 的表格生成Pandas DataFrame的场景中,requests与Selenium读取元素的结果不同。
解决方案
差异根源
requests直接获取服务器返回的原始HTML响应,而Selenium的page_source是浏览器渲染完成后的DOM结构——这其中可能包含JS动态生成的内容,同时部分网站会根据请求的客户端特征(如User-Agent、是否为自动化浏览器)返回不同内容,导致两者结果不一致。
让Selenium贴近requests行为的方法
1. 完全模拟requests的请求特征
同步requests的请求头、Cookie,甚至禁用JavaScript,让Selenium的请求行为尽可能贴近requests:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from bs4 import BeautifulSoup # 从requests请求中复制完整请求头(可通过requests.get(url).request.headers获取) headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", # 按需添加其他headers字段 } chrome_options = Options() # 设置User-Agent chrome_options.add_argument(f"user-agent={headers['User-Agent']}") # 禁用JavaScript,避免动态渲染 chrome_options.add_argument("--disable-javascript") # 隐藏Selenium自动化标识 chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) driver = webdriver.Chrome(options=chrome_options) driver.get(url) # 若requests有登录态Cookie,同步到Selenium # for name, value in requests_cookies.items(): # driver.add_cookie({"name": name, "value": value, "domain": ".soccerway.com"}) # driver.refresh() response = driver.page_source soup = BeautifulSoup(response, 'html.parser') driver.quit()
2. 通过CDP获取原始HTTP响应
利用Chrome DevTools协议直接抓取服务器返回的原始HTML,绕过浏览器渲染,这是最接近requests的方式:
from selenium import webdriver from bs4 import BeautifulSoup driver = webdriver.Chrome() # 启用网络监听 driver.execute_cdp_cmd("Network.enable", {}) # 拦截文档类型请求 driver.execute_cdp_cmd("Network.setRequestInterception", { "patterns": [{"urlPattern": "*", "resourceType": "Document", "interceptionStage": "HeadersReceived"}] }) raw_response = None def capture_response(event): global raw_response # 获取响应体 body = driver.execute_cdp_cmd("Network.getResponseBody", {"requestId": event["requestId"]}) raw_response = body["body"] # 放行请求 driver.execute_cdp_cmd("Network.continueInterceptedRequest", {"requestId": event["requestId"]}) driver.add_event_listener("Network.responseReceived", capture_response) driver.get(url) # 处理压缩响应(若返回内容是gzip格式) # import gzip # raw_response = gzip.decompress(raw_response).decode('utf-8') soup = BeautifulSoup(raw_response, 'html.parser') driver.quit()
通用方案的局限性
不存在适配所有URL的完美方案:
- 部分网站会通过Canvas/WebGL指纹等复杂检测识别自动化工具,此时需用
undetected-chromedriver等库隐藏Selenium特征。 - 如果网站核心内容完全依赖JS动态生成,
requests无法获取这些内容,此时Selenium的page_source必然与requests响应不同,这种场景下无法让两者一致。
内容的提问来源于stack exchange,提问作者Digital Farmer
相关产品推荐
相关产品推荐

