爬虫中间件
- 特点 :主要处理蜘蛛(
Spider
)和下载器(Downloader
)之间的请求和响应。可以对蜘蛛生成的请求进行拦截、修改或过滤,也可以对下载器返回给蜘蛛的响应进行处理。 - 适用场景 :
- 请求过滤与修改:当需要根据蜘蛛的某些条件对生成的请求进行过滤或修改时,例如根据蜘蛛的状态、爬取深度等决定是否发送某个请求,或者修改请求的参数、URL 等。
- 响应处理:对下载器返回的响应进行统一的预处理,比如检查响应的状态码,根据不同的状态码进行不同的处理;或者对响应内容进行初步的清洗、解析,提取一些公共信息供蜘蛛后续使用。
- 实现分布式爬虫:在分布式爬虫场景中,用于协调不同节点之间的爬取任务,例如根据节点的负载情况分配请求,或者对分布式环境下的请求和响应进行特殊处理,确保爬取任务的高效执行。
下载中间件
- 特点 :主要作用于下载器层面,用于处理
HTTP
请求和响应。可以在请求发送到服务器之前对请求进行修改,如添加请求头、代理设置等;也可以在响应返回后对响应进行处理,如解压、解码等操作。 - 适用场景 :
- 请求头设置 :像前面提到的随机设置
User-Agent
,以及添加其他自定义的请求头信息,以伪装请求来源或满足网站的特定要求。 - 代理设置:当需要使用代理服务器来发送请求时,下载中间件是设置代理的合适位置。可以根据不同的条件动态选择代理服务器,或者对代理的使用进行管理和监控,如处理代理的认证、检测代理的可用性等。
- 响应处理:对响应进行一些与数据传输和格式相关的处理,例如对压缩的响应进行解压(如处理gzip压缩的响应),对编码后的响应进行解码,确保蜘蛛接收到的是正确格式的响应内容。
- 请求头设置 :像前面提到的随机设置
在实际的爬虫项目中,通常会同时使用爬虫中间件和下载中间件。下载中间件用于处理与 HTTP
请求和响应相关的底层操作,而爬虫中间件则更侧重于处理与蜘蛛逻辑相关的请求和响应,两者结合可以满足复杂的爬虫需求。例如,在一个爬取电商网站的项目中,可能会使用下载中间件来设置代理和随机User-Agent
,以避免被网站封禁;同时使用爬虫中间件来根据商品的分类过滤请求,只爬取特定类别的商品信息,并对响应中的通用信息进行提取和处理。
python
DOWNLOADER_MIDDLEWARES = {
# 其他中间件...
'your_project_name.middlewares.ProxyMiddleware': 543,
}
543
:这是中间件的优先级,数值越小,中间件越先被执行。
代理中间件
python
import random
import base64
class ProxyMiddleware:
def __init__(self):
self.proxy_list = [
'http://proxy1.example.com:8080',
'http://proxy2.example.com:8080',
]
self.username = 'your_username'
self.password = 'your_password'
def process_request(self, request, spider):
proxy = random.choice(self.proxy_list)
request.meta['proxy'] = proxy
# 添加代理认证信息
if self.username and self.password:
auth = f'{self.username}:{self.password}'
auth_encoded = base64.b64encode(auth.encode('utf-8')).decode('utf-8')
request.headers['Proxy-Authorization'] = f'Basic {auth_encoded}'
return None
def process_exception(self, request, exception, spider):
# 处理代理失败的情况
proxy = request.meta.get('proxy')
if proxy in self.proxy_list:
self.proxy_list.remove(proxy)
return request
在 Scrapy
的下载器中间件中,process_request
方法的返回值有特定的含义:
return None
:这是最常见的返回值。当返回None
时,Scrapy 会继续处理这个请求,也就是会将请求发送给下一个中间件(如果有的话),最终由下载器去执行请求操作。return Response
:若返回一个Response
对象,Scrapy 会停止处理这个请求的后续中间件,并且直接将这个Response
对象作为请求的响应返回给蜘蛛(Spider)进行处理。return Request
:要是返回一个新的Request
对象,Scrapy 会停止处理当前请求,然后将新的Request对象重新加入到请求队列中,等待后续处理。
UserAgent中间件
python
class UserAgentMiddleware:
def process_request(self, request, spider):
user_agant = random.choice(USER_AGENT_LIST)
# 添加请求头
request.headers['User-Agent'] = user_agant
return None
Selenium中间件
python
from DrissionPage import Chromium
class SeleniumMiddleware:
def __init__(self, crawler):
self.crawler = crawler
# 连接 spider_closed 信号和 spider_closed 方法
self.crawler.signals.connect(self.spider_closed, signal=signals.spider_closed)
self.browser = Chromium()
self.tab = self.browser.latest_tab
@classmethod
def from_crawler(cls, crawler):
return cls(crawler)
def process_request(self, request, spider):
self.tab.get(request.url)
body = self.tab.html
return HtmlResponse(url=request.url, body=body, request=request, encoding='utf-8')
def spider_closed(self, spider):
self.tab.close()
self.browser.quit()