使用Scrapy爬取DNB网站遭遇403封禁,Selenium/Requests可正常访问的问题咨询
我来帮你捋捋为什么会出现这种差异,以及对应的解决思路:
可能的核心原因
1. 请求头的完整性差异
DNB的反爬系统大概率会校验请求头的细节。Scrapy默认的请求头缺少很多浏览器特有的字段(比如Accept-Language、Sec-Fetch-*系列、Referer等),而Requests在默认情况下会自动补充部分贴近浏览器的头,Selenium则完全复刻浏览器的请求头,所以能绕过检测。
2. 代理IP质量或配置问题
你配置的代理列表里的IP可能已经被DNB拉黑,或者scrapy_proxies中间件的配置存在问题(比如PROXY_MODE=0的随机代理逻辑没生效,部分代理本身无法访问目标站点)。另外,重试次数设置为10次,反而可能触发反爬系统的恶意请求判定,加重封锁。
3. Cookie会话逻辑不匹配
浏览器访问时会先加载DNB的首页或搜索页,生成必要的会话Cookie,而Scrapy直接请求详情页,缺少这些关键的会话标识。即使开启了COOKIES_ENABLED,Scrapy的CookieJar也无法模拟浏览器的Cookie生成流程(比如需要通过JS生成的Cookie)。
4. 并发请求触发反爬
你的Scrapy配置中CONCURRENT_REQUESTS_PER_DOMAIN=10,即使有随机延迟,单域名的并发请求量也远高于正常浏览器的访问频率,很容易被反爬系统识别为爬虫。而Selenium和Requests都是单请求模式,不会触发并发限制。
5. 下载中间件的优先级冲突
虽然你配置了UA和代理中间件,但优先级设置可能存在问题,导致UA或代理没有正确应用到请求上。比如RetryMiddleware的优先级是90,可能在代理生效前就重试了请求,导致无效的重试请求暴露了真实IP。
分步解决办法
1. 完全复刻浏览器请求头
在Spider中手动设置和浏览器一致的请求头,或者在settings.py中全局配置:
# 在Spider的parse方法或start_requests中设置 headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Referer': 'https://www.dnb.com/business-directory', 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-Site': 'same-origin', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' } yield scrapy.Request(url=target_url, headers=headers, callback=self.parse)
2. 验证并更换高质量代理
先手动测试代理列表中的IP是否有效:
import requests proxy = 'http://your-proxy-ip:port' try: response = requests.get(target_url, proxies={'http': proxy, 'https': proxy}, timeout=10) print(f"Proxy {proxy} works, status code: {response.status_code}") except Exception as e: print(f"Proxy {proxy} failed: {str(e)}")
如果大部分代理失效,更换为高匿、稳定的代理IP池。同时调整配置:
'RETRY_TIMES': 3, # 减少重试次数,避免触发反爬 'PROXY_MODE': 1, # 每个请求更换代理
3. 模拟浏览器的Cookie生成流程
先请求DNB的首页,获取会话Cookie后再请求目标页面:
def start_requests(self): # 先访问首页建立会话 yield scrapy.Request(url='https://www.dnb.com/', callback=self.fetch_target_page) def fetch_target_page(self, response): # 携带首页的Cookie请求目标页面 yield scrapy.Request(url=target_url, callback=self.parse)
4. 降低并发与调整访问频率
修改settings.py中的并发和延迟配置,贴近正常用户的访问行为:
'DOWNLOAD_DELAY': 2.5, 'CONCURRENT_REQUESTS': 2, 'CONCURRENT_REQUESTS_PER_DOMAIN': 1, 'RANDOMIZE_DOWNLOAD_DELAY': True,
5. 调整下载中间件的优先级
确保中间件的执行顺序正确,比如代理中间件先于UA中间件生效,参考官方文档调整优先级:
'DOWNLOADER_MIDDLEWARES': { 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, 'scrapy_proxies.RandomProxy': 100, 'scrapy_user_agents.middlewares.RandomUserAgentMiddleware': 200, 'scrapy.downloadermiddlewares.retry.RetryMiddleware': 90, 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110, }
6. 集成Selenium到Scrapy中
如果以上方法都无效,可以使用scrapy-selenium中间件,让Scrapy通过浏览器发送请求,完全模拟你的手动访问流程:
# 安装scrapy-selenium后,在settings中配置 'DOWNLOADER_MIDDLEWARES': { 'scrapy_selenium.SeleniumMiddleware': 800 }, 'SELENIUM_DRIVER_NAME': 'chrome', 'SELENIUM_DRIVER_EXECUTABLE_PATH': '/path/to/chromedriver', 'SELENIUM_DRIVER_ARGUMENTS': ['--headless=new']
内容的提问来源于stack exchange,提问作者Ahmed Ellaban

