Selenium-wire在Docker无头Chrome环境下替换请求头不生效问题排查
问题成因
- 拦截器注册时机错误:当前代码在WebDriver实例初始化完成后才绑定请求拦截器,WebDriver启动时会同步启动内置代理和浏览器进程,首次页面请求会在拦截器规则生效前发出,导致头修改没有覆盖到最早的请求。
- 旧版无头Chrome的行为限制:你使用的是91版本的旧无头模式(
--headless),该模式和普通有头Chrome行为差异较大,会默认禁用Client Hints(sec-ch系列)请求头,还会强制在User-Agent中加入HeadlessChrome标识,即使代理层面修改了请求头,浏览器内核也会在后续请求中覆盖这些配置,这也是你输出中sec-ch-ua字段为空的直接原因。 - 版本兼容性问题:Docker内安装的Chrome/Chromedriver版本为91,与你要设置的UA中93版本不匹配,也会增加头被浏览器强制修正的概率。
修复方案
- 调整拦截器注册顺序,确保WebDriver初始化时就加载拦截规则:
在初始化webdriver.Chrome时通过seleniumwire_options参数传入拦截器,不要在实例创建完成后再赋值,避免漏掉早期请求。 - 修改Chrome启动参数,匹配有头浏览器行为:
如果可以升级Chrome到96及以上版本,将--headless替换为--headless=new,新无头模式和普通有头模式行为完全一致,不会强制修改UA和禁用sec-ch系列头;如果必须使用91版本,添加以下启动参数:
chrome_options.add_argument('--user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36') chrome_options.add_argument('--enable-features=ClientHints,UserAgentClientHint') chrome_options.add_argument('--disable-features=AutomationControlled')
- 优化拦截器逻辑,删除请求头前先判断是否存在,避免抛出KeyError导致拦截器失效:
def interceptor(request): if 'User-Agent' in request.headers: del request.headers['User-Agent'] request.headers['User-Agent'] = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36' request.headers['sec-ch-ua'] = '"Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"' request.headers['sec-ch-ua-mobile'] = '?0' request.headers['sec-ch-ua-platform'] = '"Linux"'
- 统一版本:将Docker内的Chrome和Chromedriver版本升级到93及以上,和你设置的UA版本保持一致,减少兼容性问题。
内容的提问来源于stack exchange,提问作者db533
相关产品推荐
相关产品推荐

