Python3使用Selenium无头Chrome时如何获取XHR响应的JSON内容?
实现方案:Selenium Chrome无头模式捕获XHR JSON响应
以下两种方案均可实现直接获取XHR接口的JSON响应,无需解析DOM元素,稳定性和效率远高于原有页面解析方案。
方案1:CDP事件监听(推荐,无需改动现有业务逻辑)
通过Chrome原生的开发者协议(CDP)的Network域监听所有网络请求,筛选目标XHR接口后直接读取响应内容,兼容性好、适配所有场景。
- 核心逻辑:Selenium 4+版本原生支持调用CDP接口,注册响应接收回调后,可过滤出JSON类型的XHR请求,匹配到目标接口特征后直接拉取响应正文转JSON即可,原有页面操作逻辑无需改动。
- 依赖要求:Selenium版本≥4.0
- 代码示例(适配你的现有业务):
import json import time from selenium.webdriver.common.desired_capabilities import DesiredCapabilities @staticmethod def fetch_music_download_url_impl(music_name: str): chrome_driver_service = Service(ChromeDriverManager(chrome_type=ChromeType.GOOGLE).install()) chrome_options = Options() chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--headless=new") # 新版无头模式,和有头模式行为完全一致,兼容性更好 chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--remote-debugging-port=9230") # 开启性能日志支持CDP事件监听 caps = DesiredCapabilities.CHROME caps['goog:loggingPrefs'] = {'performance': 'ALL'} driver = webdriver.Chrome( service=chrome_driver_service, options=chrome_options, desired_capabilities=caps, executable_path="/usr/local/bin/chromedriver" ) # 存储捕获到的目标XHR响应 target_json_responses = [] # 自定义响应捕获回调 def capture_xhr_response(event): if event['method'] == 'Network.responseReceived': resp_info = event['params']['response'] # 筛选规则可自定义,这里匹配JSON类型且包含listenSong.do特征的接口 if resp_info['mimeType'] == 'application/json' and 'listenSong.do' in resp_info['url']: request_id = event['params']['requestId'] try: # 拉取响应正文转JSON resp_body = driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': request_id}) json_data = json.loads(resp_body['body']) target_json_responses.append(json_data) logger.info(f"捕获到目标XHR响应:{json_data}") except Exception as e: logger.warning(f"读取响应失败:{e}") try: # 启用Network域监听并注册回调 driver.execute_cdp_cmd('Network.enable', {}) driver.add_listener('Network.responseReceived', capture_xhr_response) # 原有业务操作逻辑不变 driver.maximize_window() driver.get('http://example.cn/music/?page=audioPage&type=migu&name=' + music_name) driver.implicitly_wait(5) driver.find_element(By.CSS_SELECTOR, ".aplayer-list-download.iconfont.icon-xiazai").click() # 等待接口请求完成,可根据实际情况调整等待逻辑,比如判断target_json_responses是否有值 time.sleep(3) # 直接处理JSON数据即可,无需解析DOM for json_data in target_json_responses: download_url = json_data.get('data', {}).get('downloadUrl') if download_url: FetchMusic.do_save_music_download_url(download_url) except Exception as e: logger.error("scrapy impl error", e) finally: driver.stop_client() driver.close() driver.quit() chrome_driver_service.stop()
- 注意事项:如果接口返回的是JSONP格式,需要先去掉外层的函数包裹再转JSON;如果要过滤POST请求的参数,可监听
Network.requestWillBeSent事件获取请求体。
方案2:直接模拟XHR请求(适合无复杂校验的场景)
如果你抓包拿到目标XHR的请求URL、参数、请求头、Cookie规则,且接口没有复杂的签名、动态Token校验,可以直接用requests库发请求拿JSON,完全不需要启动浏览器,资源占用极低、速度更快。
该方案的前提是能搞定接口的所有校验规则,否则容易返回403、签名错误等异常,仅适合接口规则简单的场景。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

