在前两篇笔记中,我成功写出了爬虫,也搞定了数据的清洗入库。
但在深入学习的过程中,我发现了一个严重的问题:我的爬虫太“诚实”了。
如果不做任何配置,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 吗?
