Middleware
SpiderMiddleware
这是项目中间件(可通过 spider 访问到对应的属性)
- spider_start:爬虫启动时干什么
- spider_error:爬虫出错时干什么
- spider_close:爬虫结束时干什么(必定会执行,一般用来资源回收)
- spider_end:爬虫结束时干什么(分布式时只执行一次,一般用来发送信息)
结构
import palp
from loguru import logger
class SpiderMiddleware(palp.SpiderMiddleware):
def spider_start(self, spider) -> None:
"""
spider 开始时的操作
:param spider:
:return:
"""
def spider_error(self, spider, exception: Exception) -> None:
"""
spider 出错时的操作
:param spider:
:param exception: 错误的详细信息
:return:
"""
logger.error(exception)
def spider_close(self, spider) -> None:
"""
spider 结束的操作
:param spider:
:return:
"""
def spider_close(self, spider) -> None:
"""
spider 结束的操作(分布式时只执行一次)
:param spider:
:return:
"""
设置
注意:这里的 1 代表顺序
SPIDER_MIDDLEWARE = {
1: 'middlewares.middleware.SpiderMiddleware',
}
RequestMiddleware
这是请求中间件(可通过 spider 访问到对应的属性)
- request_in:请求创建时干什么
- request_error:请求出错时干什么(默认重试 3 次 settings.REQUEST_RETRY_TIMES)
- request_failed:请求失败时干什么(3 次后还失败,走这里)
- request_close:请求结束时干什么(执行完毕后走这里)
- request_record:请求结束的结果记录(执行完毕后走这里,分布式只走一次,JumpSpider 不走该函数)
注意:
- request_failed 和 request_close 只有走其中一个
- 不要的请求可直接抛出 DropRequestException 错误
- 请求可以原地修改
- request_error 可以判断错误进行修改,或者直接 return 新的请求,旧请求自动丢弃
- request_close 可以判断响应是否符合预期,或者直接 return 新的请求,旧请求自动丢弃
提示:
- 分布式爬虫时,设置开启以下两个选项,即可自动保存错误请求,并存放 redis,下次请求自动继续
- REQUEST_FAILED_SAVE = True # 分布式时保存失败的请求(重试之后仍然失败的)
- REQUEST_RETRY_FAILED = True # 分布式时启动重试失败请求
结构
import palp
from typing import Union
from palp import settings
from loguru import logger
from palp.network.request import Request
class RequestMiddleware(palp.RequestMiddleware):
def request_in(self, spider, request) -> None:
"""
请求进入时的操作
:param spider:
:param request:
:return:
"""
if settings.REQUEST_PROXIES_TUNNEL_URL:
request.proxies = {
'http': settings.REQUEST_PROXIES_TUNNEL_URL,
'https': settings.REQUEST_PROXIES_TUNNEL_URL,
}
def request_error(self, spider, request, exception: Exception) -> Union[Request, None]:
"""
请求出错时的操作
:param spider:
:param request: 该参数可返回(用于放弃当前请求,并发起新请求)
:param exception: 错误的详细信息
:return: [Request, None]
"""
logger.error(exception)
return
def request_failed(self, spider, request) -> None:
"""
超过最大重试次数时的操作
:param spider:
:param request:
:return:
"""
logger.warning(f"失败的请求:{request}")
def request_close(self, spider, request, response) -> Union[Request, None]:
"""
请求结束时的操作
:param spider:
:param request: 该参数可返回(用于放弃当前请求,并发起新请求)
:param response:
:return: [Request, None]
"""
return
def request_record(self, spider, record: dict) -> None:
"""
请求结果记录(在 spider 结束时调用)
:param spider:
:param record:
:return:
"""
logger.info("{} 执行完毕,请求量统计:{}", spider.spider_name, record)
设置
注意:这里的 1 代表顺序
REQUEST_MIDDLEWARE = {
1: "middlewares.middleware.RequestMiddleware",
}
添加代理
注意:这里基于默认的 ResponseDownloaderByRequests 请求器(requests)
class RequestMiddleware(palp.RequestMiddleware):
def request_in(self, spider, request) -> None:
"""
请求进入时的操作
:param spider:
:param request:
:return:
"""
# 给所有 url 都添加代理
if settings.REQUEST_PROXIES_TUNNEL_URL and not request.proxies:
request.proxies = {
'http': settings.REQUEST_PROXIES_TUNNEL_URL,
'https': settings.REQUEST_PROXIES_TUNNEL_URL,
}
# 指定域名添加代理
allow_domains = ['xxx']
if settings.REQUEST_PROXIES_TUNNEL_URL and not request.proxies:
if request.domain in allow_domains:
request.proxies = {
'http': settings.REQUEST_PROXIES_TUNNEL_URL,
'https': settings.REQUEST_PROXIES_TUNNEL_URL,
}