如何利用Python Scrapy中间件实现下载器随机更换User-Agent突破反爬虫机制?
- 内容介绍
- 文章标签
- 相关推荐
本文共计832个文字,预计阅读时间需要4分钟。
Scrapy默认使用固定的User-Agent,一旦目标网站进行反爬虫检测,就会直接被封禁。因此,需要在下载器中间件中动态更换User-Agent,而不是仅修改settings.py中的静态配置。
实操建议:
- 写一个自定义中间件类,重写
process_request方法,在里面覆盖request.headers['User-Agent'] - UA池别硬编码——用列表或从文件读,推荐用
random.choice()选,别用random.randint()手动索引(容易越界) - 务必检查
if request.headers.get('User-Agent')是否已存在,避免重复覆盖导致调试时误以为没生效 - 中间件启用顺序很重要:
DOWNLOADER_MIDDLEWARES里数值越小越先执行,确保你的UA中间件在RetryMiddleware之前(否则重试时UA又变回默认)
为什么不能只靠settings.py的USER_AGENT
USER_AGENT配置项是全局静态值,所有请求共用同一个字符串。反爬系统只要看到连续多个请求UA完全一致,立刻打上“脚本流量”标签。
常见错误现象:
立即学习“Python免费学习笔记(深入)”;
- 明明写了
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',但抓几页就被封——因为没换 - 开了
ROTATING_PROXY却忘了换UA,代理轮着换,UA原地不动,照样被识别 - 把UA写死在
start_requests里,结果follow出来的Request不带UA,回落到默认值
根本原因:Scrapy的Request对象初始化时若未显式传headers,就继承DEFAULT_REQUEST_HEADERS或全局USER_AGENT,而这两者都是静态的。
随机UA中间件的三个易错点
很多人写了中间件但还是被封,问题常出在细节上:
-
process_request里没写return None(或直接不写return),导致Scrapy误判为“该请求已被处理完毕”,后续中间件和下载器全跳过 - UA字符串里混入不可见字符(比如从网页复制来的空格、全角符号),发出去后HTTP头格式错误,目标站直接返回400
- 用了过于冷门或版本陈旧的UA(如
Opera/9.80),触发WAF的“异常客户端指纹”规则,比不用UA还容易被拦 - 没控制UA更新频率——比如每秒换10次,但实际UA池只有5个,很快开始重复,失去随机意义
简单可用的中间件示例
以下代码可直接粘贴到middlewares.py,注意替换你的UA列表:
class RandomUserAgentMiddleware: def __init__(self): self.user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36', ] def process_request(self, request, spider): ua = random.choice(self.user_agents) request.headers['User-Agent'] = ua
然后在settings.py里启用:
DOWNLOADER_MIDDLEWARES = {'myproject.middlewares.RandomUserAgentMiddleware': 543}
数值543只是示例,只要比scrapy.downloadermiddlewares.useragent.UserAgentMiddleware(默认500)小就行,确保它先执行。
真实项目里UA池至少20+条,且应包含移动端、主流浏览器最新版,别凑数。换UA只是基础动作,真要稳定爬,还得配IP轮换、请求间隔、Referer模拟——但那是另一层的事了。
本文共计832个文字,预计阅读时间需要4分钟。
Scrapy默认使用固定的User-Agent,一旦目标网站进行反爬虫检测,就会直接被封禁。因此,需要在下载器中间件中动态更换User-Agent,而不是仅修改settings.py中的静态配置。
实操建议:
- 写一个自定义中间件类,重写
process_request方法,在里面覆盖request.headers['User-Agent'] - UA池别硬编码——用列表或从文件读,推荐用
random.choice()选,别用random.randint()手动索引(容易越界) - 务必检查
if request.headers.get('User-Agent')是否已存在,避免重复覆盖导致调试时误以为没生效 - 中间件启用顺序很重要:
DOWNLOADER_MIDDLEWARES里数值越小越先执行,确保你的UA中间件在RetryMiddleware之前(否则重试时UA又变回默认)
为什么不能只靠settings.py的USER_AGENT
USER_AGENT配置项是全局静态值,所有请求共用同一个字符串。反爬系统只要看到连续多个请求UA完全一致,立刻打上“脚本流量”标签。
常见错误现象:
立即学习“Python免费学习笔记(深入)”;
- 明明写了
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',但抓几页就被封——因为没换 - 开了
ROTATING_PROXY却忘了换UA,代理轮着换,UA原地不动,照样被识别 - 把UA写死在
start_requests里,结果follow出来的Request不带UA,回落到默认值
根本原因:Scrapy的Request对象初始化时若未显式传headers,就继承DEFAULT_REQUEST_HEADERS或全局USER_AGENT,而这两者都是静态的。
随机UA中间件的三个易错点
很多人写了中间件但还是被封,问题常出在细节上:
-
process_request里没写return None(或直接不写return),导致Scrapy误判为“该请求已被处理完毕”,后续中间件和下载器全跳过 - UA字符串里混入不可见字符(比如从网页复制来的空格、全角符号),发出去后HTTP头格式错误,目标站直接返回400
- 用了过于冷门或版本陈旧的UA(如
Opera/9.80),触发WAF的“异常客户端指纹”规则,比不用UA还容易被拦 - 没控制UA更新频率——比如每秒换10次,但实际UA池只有5个,很快开始重复,失去随机意义
简单可用的中间件示例
以下代码可直接粘贴到middlewares.py,注意替换你的UA列表:
class RandomUserAgentMiddleware: def __init__(self): self.user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36', ] def process_request(self, request, spider): ua = random.choice(self.user_agents) request.headers['User-Agent'] = ua
然后在settings.py里启用:
DOWNLOADER_MIDDLEWARES = {'myproject.middlewares.RandomUserAgentMiddleware': 543}
数值543只是示例,只要比scrapy.downloadermiddlewares.useragent.UserAgentMiddleware(默认500)小就行,确保它先执行。
真实项目里UA池至少20+条,且应包含移动端、主流浏览器最新版,别凑数。换UA只是基础动作,真要稳定爬,还得配IP轮换、请求间隔、Referer模拟——但那是另一层的事了。

