🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟
📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主!
👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"挖山不止"的毅力为开发者们搬开知识道路上的重重阻碍!
💎【行业认证·权威头衔】
✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家
✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主
✔ 技术生态共建先锋:横跨鸿蒙、云计算、AI等前沿领域的技术布道者
🏆【荣誉殿堂】
🎖 连续三年蝉联"华为云十佳博主"(2022-2024)
🎖 双冠加冕CSDN"年度博客之星TOP2"(2022&2023)
🎖 十余个技术社区年度杰出贡献奖得主
📚【知识宝库】
覆盖全栈技术矩阵:
◾ 编程语言:.NET/Java/Python/Go/Node…
◾ 移动生态:HarmonyOS/iOS/Android/小程序
◾ 前沿领域:物联网/网络安全/大数据/AI/元宇宙
◾ 游戏开发:Unity3D引擎深度解析
每日更新硬核教程+实战案例,助你打通技术任督二脉!
💌【特别邀请】
正在构建技术人脉圈的你:
👍 如果这篇推文让你收获满满,点击"在看"传递技术火炬
💬 在评论区留下你最想学习的技术方向
⭐ 点击"收藏"建立你的私人知识库
🔔 关注公众号获取独家技术内参
✨与其仰望大神,不如成为大神!关注"愚公搬代码",让坚持的力量带你穿越技术迷雾,见证从量变到质变的奇迹!✨ |
🚀前言
在之前的文章中,我们已经深入学习了 Scrapy 的基本应用和数据处理方法,这一次,我们将带大家一起探索 Scrapy 中的一个高级特性——自定义中间件。
在爬虫开发中,中间件是连接各个组件的重要桥梁,Scrapy 提供了一个灵活的中间件机制,可以在爬虫请求和响应的处理过程中插入自定义的逻辑。通过自定义中间件,我们能够实现各种高级功能,如代理池管理、请求重试、修改请求头、处理验证码等。
在本篇文章中,我们将会学习到:
- 中间件的基本概念:理解 Scrapy 中间件的作用及其工作流程。
- 如何编写自定义中间件:从创建到实现自定义功能,让中间件在请求和响应过程中发挥作用。
- 常见的中间件应用场景:如何使用自定义中间件处理代理、请求头、限速等。
- 配置和启用中间件:如何在 Scrapy 项目中配置并启用中间件,保证其正常工作。
- 调试与优化中间件:如何测试和调试自定义中间件,确保爬虫的高效与稳定。
通过本篇文章的学习,你将能够灵活运用 Scrapy 自定义中间件,解决爬虫开发中的各种复杂需求,提升爬虫的功能和性能。如果你已经在爬虫项目中遇到了一些瓶颈,或者希望使爬虫更强大,那么自定义中间件将是你不可或缺的工具。
🚀一、Scrapy 自定义中间件
Scrapy内置的中间件可能无法满足特殊需求,自定义中间件可通过重写关键方法实现特定功能。以下是三种典型场景的实现:
🔎1.随机请求头中间件
需求背景:防止请求头特征被识别导致封禁
实现步骤:
-
创建项目与爬虫
scrapy startproject header cd header scrapy genspider headerSpider quotes.toscrape.com
-
安装依赖
pip install fake-useragent
-
编写爬虫(headerSpider.py)
import scrapy class HeaderSpider(scrapy.Spider): name = "headerSpider" def start_requests(self): urls = [ "http://quotes.toscrape.com/page/1/", "http://quotes.toscrape.com/page/2/" ] for url in urls: yield scrapy.Request(url=url, callback=self.parse) def parse(self, response): print("请求头信息:", response.request.headers.get('User-Agent'))
-
自定义中间件(middlewares.py)
from fake_useragent import UserAgent class RandomHeaderMiddleware: def __init__(self, crawler): self.ua = UserAgent() self.type = crawler.settings.get("RANDOM_UA_TYPE", "chrome") @classmethod def from_crawler(cls, crawler): return cls(crawler) def process_request(self, request, spider): request.headers['User-Agent'] = getattr(self.ua, self.type)
-
配置(settings.py)
DOWNLOADER_MIDDLEWARES = { 'header.middlewares.RandomHeaderMiddleware': 400, 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None } RANDOM_UA_TYPE = "random" # 可选:random/chrome/firefox/ie
🔎2.Cookies模拟登录中间件
需求背景:实现免登录访问需要认证的页面
实现步骤:
-
爬虫代码(cookieSpider.py)
import scrapy class CookiespiderSpider(scrapy.Spider): name = 'cookieSpider' # 爬虫名称 allowed_domains = ['douban.com'] # 域名列表 start_urls = ['http://www.douban.com'] # 请求初始化列表 def start_requests(self): # 发送网络请求,请求地址为start_urls列表中的第一个地址 yield scrapy.Request(url=self.start_urls[0],callback=self.parse) # 响应信息 def parse(self, response): # 打印登录后的用户名信息 print(response.xpath('//*[@id="db-global-nav"]/div/div[1]/ul/li[2]/a/span[1]/text()').extract_first()) pass
-
Cookies中间件(middlewares.py)
# 自定义cookies中间件 class CookiesdemoMiddleware(object): # 初始化 def __init__(self,cookies_str): self.cookies_str = cookies_str @classmethod def from_crawler(cls, crawler): return cls( # 获取配置文件中的cookies信息 cookies_str = crawler.settings.get('COOKIES_DEMO') ) cookies = {} # 保存格式化以后的cookies def process_request(self, request, spider): for cookie in self.cookies_str.split(';'): # 通过;分割cookies字符串 key, value = cookie.split('=', 1) # 将key与值进行分割 self.cookies.__setitem__(key,value) # 将分割后的数据保存至字典中 request.cookies = self.cookies # 设置格式化以后的cookies
-
随机请求头中间件(middlewares.py)
from fake_useragent import UserAgent # 导入请求头类 # 自定义随机请求头的中间件 class RandomHeaderMiddleware(object): def __init__(self, crawler): self.ua = UserAgent() # 随机请求头对象 # 如果配置文件中不存在就使用默认的Google Chrome请求头 self.type = crawler.settings.get("RANDOM_UA_TYPE", "chrome") @classmethod def from_crawler(cls, crawler): # 返回cls()实例对象 return cls(crawler) # 发送网络请求时调用该方法 def process_request(self, request, spider): # 设置随机生成的请求头 request.headers.setdefault('User-Agent', getattr(self.ua, self.type))
-
配置(settings.py)
DOWNLOADER_MIDDLEWARES = { # 启动自定义cookies中间件 'cookiesDemo.middlewares.CookiesdemoMiddleware': 201, # 启动自定义随机请求头中间件 'cookiesDemo.middlewares.RandomHeaderMiddleware':202, # 禁用默认生成的配置信息 'cookiesDemo.middlewares.CookiesdemoDownloaderMiddleware': None, } COOKIES_STR = "从浏览器获取的真实Cookie字符串" # 格式:key1=value1; key2=value2
🔎3.随机代理IP中间件
需求背景:避免IP被封锁,提升请求成功率
实现步骤:
-
爬虫代码(ipSpider.py)
# -*- coding: utf-8 -*- import scrapy class IpspiderSpider(scrapy.Spider): name = 'ipSpider' allowed_domains = ['httpbin.org/get'] start_urls = ['http://httpbin.org/get/'] # # 发送网络请求 # def start_requests(self): # return [scrapy.Request('http://httpbin.org/get',callback = self.parse, # meta={'proxy':'http://117.88.177.0:3000'})] #发送网络请求 def start_requests(self): return [scrapy.Request('http://httpbin.org/get',callback = self.parse)] # 响应信息 def parse(self, response): print(response.text) # 打印返回的响应信息 pass # 导入CrawlerProcess类 from scrapy.crawler import CrawlerProcess # 导入获取项目设置信息 from scrapy.utils.project import get_project_settings # 程序入口 if __name__=='__main__': # 创建CrawlerProcess类对象并传入项目设置信息参数 process = CrawlerProcess(get_project_settings()) # 设置需要启动的爬虫名称 process.crawl('ipSpider') # 启动爬虫 process.start()
-
代理中间件(middlewares.py)
class IpRandomProxyMiddleware(object): # 定义有效的代理ip列表 PROXIES = [ '117.88.177.0:3000', '117.45.139.179:9006', '202.115.142.147:9200', '117.87.50.89:8118'] # 发送网络请求时调用 def process_request(self, request, spider): proxy = random.choice(self.PROXIES) # 随机抽取代理ip request.meta['proxy'] = 'http://'+proxy # 设置网络请求所使用的代理ip
-
配置(settings.py)
DOWNLOADER_MIDDLEWARES = { # 激活自定义随机获取代理ip的中间件 'ipDemo.middlewares.IpRandomProxyMiddleware':200, # 禁用默认生成的中间件 'ipDemo.middlewares.IpdemoDownloaderMiddleware': None }
🔎4.关键说明
- 中间件执行顺序:通过数字权重控制(范围100-900),数值越小越早执行
- 调试技巧:通过
scrapy shell
测试中间件效果 - 最佳实践:
- 代理IP需定期验证有效性
- Cookies需通过浏览器登录后获取真实值
- 请求头类型建议优先使用"random"
完整项目结构应包含:
project/
├── scrapy.cfg
└── project/
├── __init__.py
├── middlewares.py
├── settings.py
└── spiders/
├── __init__.py
├── headerSpider.py
├── cookieSpider.py
└── ipSpider.py