如何让Selenium-Wire捕获所需的间接GraphQL AJAX请求(TweetDetail)
解决Selenium-Wire无法捕获Twitter /TweetDetail GraphQL请求的问题
问题背景
需要获取Twitter媒体内容中标记的用户账号,无官方API支持,只能通过爬虫实现。目标页面为Twitter媒体标签弹窗对应的URL:https://twitter.com/<用户名>/status/<推文ID>/media_tags。
- 匿名访问时页面DOM为空,但网络请求中的
/TweetDetailGraphQL端点包含所需的用户账号列表 - 使用Selenium+Selenium-Wire尝试捕获该请求,但仅能抓到
TweetResultByRestId和UsersByRestId请求,始终无法捕获/TweetDetail请求,已调整多项Chrome选项无效
当前使用的脚本:
from seleniumwire import webdriver from selenium.webdriver.chrome.service import Service chrome_options = webdriver.ChromeOptions() chrome_options.add_argument("--disable-extensions") chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--headless") # for Jenkins chrome_options.add_argument("--disable-dev-shm-usage") # Jenkins chrome_options.add_argument('--start-maximized') chrome_options.add_argument('--window-size=1900,1080') chrome_options.add_argument('--ignore-certificate-errors-spki-list') chrome_options.add_argument('--ignore-ssl-errors') selenium_options = { 'request_storage_base_dir': '/tmp', # Use /tmp to store captured data 'exclude_hosts': '' } ser = Service('/usr/bin/chromedriver') ser.service_args=["--verbose", "--log-path=test.log"] driver = webdriver.Chrome(service=ser, options=chrome_options, seleniumwire_options=selenium_options) tweet_id = "1626275168157851650" twitter_media_url = f"https://twitter.com/justinwood_/status/{tweet_id}/media_tags" driver.get(twitter_media_url) driver.wait_for_request("/TweetDetail", timeout=10)
问题原因及解决步骤
核心问题是Twitter的反爬机制识别了无头Chrome和自动化工具,拒绝发送/TweetDetail请求,同时Selenium-Wire的默认配置可能遗漏了目标请求。以下是针对性调整:
关键调整点
- 替换User-Agent:使用真实浏览器的UA,避免被识别为爬虫
- 启用新版无头模式:Chrome 112+的
--headless=new模式行为更接近正常浏览器,不易被检测 - 禁用自动化检测标志:移除
navigator.webdriver等自动化特征 - 明确Selenium-Wire请求过滤规则:指定只监听包含
TweetDetail的GraphQL请求 - 优化等待逻辑:给页面足够时间加载并发送请求
调整后的完整代码
from seleniumwire import webdriver from selenium.webdriver.chrome.service import Service import time import json # 配置Chrome选项 chrome_options = webdriver.ChromeOptions() # 替换为你自己浏览器的User-Agent(可在Chrome开发者工具Network面板复制) chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") chrome_options.add_argument("--disable-extensions") chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--headless=new") # 新版无头模式,更难被检测 chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--window-size=1920,1080") chrome_options.add_argument("--ignore-certificate-errors") # 禁用自动化检测的关键设置 chrome_options.add_argument("--disable-blink-features=AutomationControlled") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) # Selenium-Wire配置:明确监听包含TweetDetail的GraphQL请求 selenium_options = { 'request_storage_base_dir': '/tmp', 'exclude_hosts': '', 'include_urls': ['.*twitter.com/graphql/.*TweetDetail.*'] } # 初始化驱动 ser = Service('/usr/bin/chromedriver') ser.service_args=["--verbose", "--log-path=test.log"] driver = webdriver.Chrome(service=ser, options=chrome_options, seleniumwire_options=selenium_options) # 移除webdriver标志,绕过Twitter检测 driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") tweet_id = "1626275168157851650" twitter_media_url = f"https://twitter.com/justinwood_/status/{tweet_id}/media_tags" driver.get(twitter_media_url) # 给页面足够时间发送请求(可根据网络情况调整) time.sleep(3) # 遍历所有请求,查找目标TweetDetail请求 target_request = None for req in driver.requests: if "/graphql/" in req.url and "TweetDetail" in req.url: target_request = req break if target_request: print(f"成功捕获TweetDetail请求:{target_request.url}") if target_request.response: # 解析响应JSON获取标记用户 response_data = json.loads(target_request.response.body.decode('utf-8')) # 从响应中提取标记的用户账号(根据实际结构调整) tagged_users = response_data.get('data', {}).get('tweetResult', {}).get('result', {}).get('legacy', {}).get('entities', {}).get('user_mentions', []) print("标记的用户账号:") for user in tagged_users: print(f"@{user.get('screen_name')}") else: print("未捕获到TweetDetail请求,当前所有请求列表:") for req in driver.requests: print(req.url) driver.quit()
验证与注意事项
- 替换代码中的User-Agent为你自己浏览器的真实UA,避免被拦截
- 如果仍无法捕获请求,可适当延长
time.sleep的时间,或使用显式等待(如等待某个元素出现) - Twitter的反爬机制会不断更新,若后续再次失效,需调整UA或添加更多模拟真实用户的行为(如滚动页面)
内容的提问来源于stack exchange,提问作者Csaba Toth
相关产品推荐
相关产品推荐

