You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Selenium-Wire捕获所需的间接GraphQL AJAX请求(TweetDetail)

解决Selenium-Wire无法捕获Twitter /TweetDetail GraphQL请求的问题

问题背景

需要获取Twitter媒体内容中标记的用户账号,无官方API支持,只能通过爬虫实现。目标页面为Twitter媒体标签弹窗对应的URL:https://twitter.com/<用户名>/status/<推文ID>/media_tags。

  • 匿名访问时页面DOM为空,但网络请求中的/TweetDetail GraphQL端点包含所需的用户账号列表
  • 使用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的默认配置可能遗漏了目标请求。以下是针对性调整:

关键调整点

  1. 替换User-Agent:使用真实浏览器的UA,避免被识别为爬虫
  2. 启用新版无头模式:Chrome 112+的--headless=new模式行为更接近正常浏览器,不易被检测
  3. 禁用自动化检测标志:移除navigator.webdriver等自动化特征
  4. 明确Selenium-Wire请求过滤规则:指定只监听包含TweetDetail的GraphQL请求
  5. 优化等待逻辑:给页面足够时间加载并发送请求

调整后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:30:58