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

为何标准Scrapy可爬取API,而Selenium版本返回401错误?

问题

我正在使用Selenium驱动的Scrapy爬虫爬取网站,以避免被检测为机器人。该网站包含多个可调用的API,无需下载完整页面即可获取数据。但以下代码始终返回401错误:

import logging

from scrapy import Request, Spider, signals
from scrapy.crawler import Crawler, CrawlerProcess
from scrapy.http import HtmlResponse
from selenium.webdriver import Firefox, FirefoxOptions

import scrape.constants as cs


class FlashscoreMiddleware:
    @classmethod
    def from_crawler(cls, crawler: Crawler):
        middleware = cls()
        crawler.signals.connect(middleware.spider_opened, signals.spider_opened)
        crawler.signals.connect(middleware.spider_closed, signals.spider_closed)
        return middleware

    def spider_opened(self, *_) -> None:
        self.driver = Firefox()

    def spider_closed(self, *_) -> None:
        self.driver.quit()

    def process_request(self, request: Request, **_) -> None:
        self.driver.get(request.url)
        return HtmlResponse(
            request.url,
            body=self.driver.page_source,
            encoding="utf-8",
            request=request,
        )


class FlashscoreSpider(Spider):
    name = "flashscore"
    custom_settings = {
        "DOWNLOADER_MIDDLEWARES": {"selenium_scraper.FlashscoreMiddleware": 400},
        "REQUEST_FINGERPRINTER_IMPLEMENTATION": "2.7",
        "LOG_LEVEL": logging.ERROR,
    }

    def start_requests(self):
        yield Request(
            url="https://global.flashscore.ninja/5/x/feed/df_st_1_WKM03Vff",
            headers={
                "X-Fsign": "SW9D1eZo",
                "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36",
            },
            callback=self.parse,
        )

    def parse(self, response):
        if response.text.startswith("SE÷Match"):
            print(f"Successfully returned {response.url}")
        else:
            print("Unsuccessful")


if __name__ == "__main__":
    process = CrawlerProcess()
    process.crawl(FlashscoreSpider)
    process.start()

然而,若使用标准Scrapy爬虫则一切正常:

import logging

from scrapy import Request, Spider
from scrapy.crawler import CrawlerProcess


class FlashscoreSpider(Spider):
    name = "flashscore"
    custom_settings = {
        "REQUEST_FINGERPRINTER_IMPLEMENTATION": "2.7",
        "LOG_LEVEL": logging.ERROR,
    }

    def start_requests(self):
        yield Request(
            url="https://global.flashscore.ninja/5/x/feed/df_st_1_WKM03Vff",
            headers={"X-Fsign": "SW9D1eZo"},
            callback=self.parse,
        )

    def parse(self, response):
        if response.text.startswith("SE÷Match"):
            print(f"Successfully returned {response.url}")
        else:
            print("Unsuccessful")


if __name__ == "__main__":
    process = CrawlerProcess()
    process.crawl(FlashscoreSpider)
    process.start()

为什么Selenium版本无法返回正确结果?

原因分析与解决办法
  • 自定义请求头未传递:你在Scrapy Request里设置的X-Fsign和自定义User-Agent并没有被Selenium的浏览器请求带上。driver.get(request.url)只会用浏览器默认的请求头发起请求,缺少API要求的X-Fsign验证字段,直接导致401未授权错误。
  • 请求特征不匹配:Selenium驱动的浏览器自带的请求头、指纹特征和标准Scrapy请求不一致,也可能被网站的反爬机制拦截。

解决步骤

  1. 给Selenium请求添加自定义请求头
    Selenium本身不支持直接修改请求头,可通过Chrome DevTools Protocol(CDP)实现(推荐改用Chrome驱动)。示例修改中间件:
    from selenium.webdriver import Chrome, ChromeOptions
    
    class FlashscoreMiddleware:
        # ... 其他方法不变 ...
        def spider_opened(self, *_) -> None:
            options = ChromeOptions()
            # 可选:启用无头模式
            # options.add_argument("--headless=new")
            self.driver = Chrome(options=options)
    
        def process_request(self, request: Request, **_) -> None:
            # 通过CDP注入自定义请求头
            headers = {}
            for key, value in request.headers.items():
                headers[key.decode()] = value.decode()
            self.driver.execute_cdp_cmd('Network.setExtraHTTPHeaders', {'headers': headers})
            # 启用网络监听
            self.driver.execute_cdp_cmd('Network.enable', {})
            self.driver.get(request.url)
            return HtmlResponse(
                request.url,
                body=self.driver.page_source,
                encoding="utf-8",
                request=request,
            )
    
  2. 调整Scrapy配置确保中间件接管请求
    在Spider的custom_settings里禁用无关的默认下载中间件,避免干扰:
    custom_settings = {
        "DOWNLOADER_MIDDLEWARES": {
            "scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware": None,
            "selenium_scraper.FlashscoreMiddleware": 400,
        },
        "REQUEST_FINGERPRINTER_IMPLEMENTATION": "2.7",
        "LOG_LEVEL": logging.ERROR,
    }
    
  3. 验证请求头是否正确传递
    运行Selenium爬虫时打开浏览器开发者工具(可添加options.add_argument("--auto-open-devtools-for-tabs")),在Network面板查看请求头,确认X-Fsign和User-Agent与标准Scrapy请求一致。

内容的提问来源于stack exchange,提问作者Jossy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:05:56