• 大队长的Scrapy爬虫笔记(三) | 拒绝被封:揭秘中间件与 User-Agent 伪装
  • 2026-01-10 00:02:14
  • 在前两篇笔记中,我成功写出了爬虫,也搞定了数据的清洗入库。

    但在深入学习的过程中,我发现了一个严重的问题:我的爬虫太“诚实”了。

    如果不做任何配置,Scrapy 发出的每一次请求,头信息(Headers)里的 User-Agent 字段都赫然写着:

    Scrapy/2.x.x (+https://scrapy.org)

    这就好比一个人走进商店,脑门上贴着一张纸条写着:“我是机器人,我是来抄价格的。”

    很多网站只要检测到这个特征,就会直接拒绝服务(403 Forbidden)。

    这一篇,我记录一下我是如何利用 Scrapy 的配置和中间件,给我的爬虫穿上“隐身衣”的。

    一、初级伪装:修改全局 Settings

    最简单的伪装,就是直接修改全局配置文件。 Scrapy 允许我们在 settings.py 里“冒充”浏览器。

    打开 settings.py,我做了两件事:

    1. 伪装 User-Agent

    找到 USER_AGENT 变量(通常是被注释的),把它改成一个标准的 Chrome 浏览器标识。

    # 假装我是 Windows 下的 Chrome 浏览器

    USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'

    2. 关掉 Robots 协议(仅限学习)

    Scrapy 默认是遵纪守法的,它会先去查看目标网站的 robots.txt。如果网站规定“不允许爬虫访问”,Scrapy 就会直接停止。

    在学习阶段,为了防止被一些网站的规则拦在门外,我暂时关掉了这个协议(只是为了学习Scrapy临时关闭,大家在爬取网址的时候一定要遵守网址的robots.txt文件。):

    # 设为 False,无视 robots.txt 规则

    ROBOTSTXT_OBEY = False

    二、进阶伪装:为什么需要中间件?

    虽然我改了 User-Agent,但如果我爬取几千个页面,却始终用同一个 User-Agent,网站管理员还是会怀疑。

    为了解决这个问题,我需要动态切换 User-Agent(每发一个请求换一张脸)。

    这就需要用到 Scrapy 的Downloader Middleware(下载器中间件)。

    你可以把中间件理解为“安检口”。请求(Request)发出去之前,都要经过这里,我可以趁机把它的 User-Agent 偷偷换掉。

    三、实战:编写随机 UA 中间件(middlewares)

    1. 找到文件位置

    刚开始我找文件找了半天,这里给像我一样的新手画个图。我们需要编辑的是项目内层的 middlewares.py:

    my_news/ <-- 项目根目录

    scrapy.cfg

    my_news/ <-- 项目模块目录

    __init__.py

    items.py

    middlewares.py <-- 【就是它!我们要改的文件】

    pipelines.py

    settings.py

    spiders/

    2. 方法A:手写列表(笨办法)

    打开 middlewares.py,我可以自己写一个类,里面放一个列表。

    import random

    class RandomUserAgentMiddleware:

    def __init__(self):

    self.user_agents = [

    'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...', # Chrome

    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...', # Safari

    # ... 自己要把这个列表填得很长很累

    ]

    def process_request(self, request, spider):

    request.headers['User-Agent'] = random.choice(self.user_agents)

    3. 方法B:使用第三方库(聪明办法)

    写死列表太麻烦了,而且浏览器的版本更新很快。其实有一个好用的第三方库叫 fake-useragent。

    第一步:安装库

    在终端里运行:

    pip install fake-useragent

    第二步:修改代码

    在 middlewares.py 里,我可以直接调用这个库,代码瞬间变得简洁高级了:

    # 导入这个第三方库

    from fake_useragent import UserAgent

    class RandomUserAgentMiddleware:

    def __init__(self):

    # 实例化一个对象,它会自动帮我获取最新的浏览器UA

    self.ua = UserAgent()

    def process_request(self, request, spider):

    # 【核心逻辑】

    # self.ua.random 会随机返回一个真实的浏览器标识

    random_ua = self.ua.random

    # 把它塞进请求头里

    request.headers['User-Agent'] = random_ua

    # (可选) 打印出来看看,调试完记得注释掉,不然日志太多

    # spider.logger.info(f'当前伪装身份: {random_ua}')

    我的体会:

    使用第三方库的好处是,我再也不用担心我的 User-Agent 列表过期了,这个库会帮我维护数据。

    四、关键操作:再次激活开关

    这又是“Scrapy 哲学”发挥作用的时刻。

    代码写完了,但 Scrapy 根本不知道我写了这个类。我必须去 settings.py 里“挂载”它。

    找到 DOWNLOADER_MIDDLEWARES 区域(注意:别看成 Spider Middleware 了)。

    DOWNLOADER_MIDDLEWARES = {

    # 格式:'路径.类名': 优先级

    # 1. 【必须】先关闭 Scrapy 自带的默认 UA 中间件

    # 如果不关,它会用 settings 里的固定配置覆盖我的随机配置

    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,

    # 2. 开启我自己写的随机 UA 中间件

    # 数字 543 是随意填的,只要在合适范围内即可

    'my_news.middlewares.RandomUserAgentMiddleware': 543,

    }

    踩坑笔记:

    “先关原厂,再开副厂”。这一步如果不做,你在 middlewares.py 里写出花来也没用。

    五、礼貌爬取:控制语速

    最后,除了伪装身份,控制语速也是反爬的关键。

    在 settings.py 里,建议开启下载延迟:

    # 1. 下载延迟

    # 意思是每下载完一个页面,随机休息 0.5 ~ 1.5 倍的时间

    # 设置为 2 秒,意味着平均每 2 秒抓一个页面。

    DOWNLOAD_DELAY = 2

    # 2. 禁用 Cookie

    # 如果不需要登录,建议设为 False,这样每次请求都像是一个全新的访客。

    COOKIES_ENABLED = False

    总结

    这一篇笔记里,引入第三方库 fake-useragent 来增强我的爬虫。

    现在对 Scrapy 的理解更深了一层:

    middlewares.py 是放“中间插件”的地方。

    settings.py 是管理“开关”的地方。

    External Libraries (如 fake-useragent) 可以让我的插件功能更强大。

    现在,我的爬虫已经学会了“变脸”和“控制节奏”。

    但目前我写的 Spider 逻辑还是很原始:每次都要手动提取下一页的链接。 如果我要爬取一个全站有几万个链接的网站,难道要手动写正则去匹配每一个 URL 吗?