Downloader Middleware的工作流程
Downloader Midderware即下载中间件,它是处于Scrapy的Request和Response之间的处理模块。我们先来看看它的架构,Scheduler从队列中拿出一个Request发送给Downloader执行下载。这个过程会经过Downloader MIddleware的处理。另外,当Downloader将Request下载完成的Response返回给Spider时会再次经过Downloader MIddleware处理,也就是说Downloader Middleware在整个框架中起作用的位置有两个:
- 在Scheduler调出队列的Request发送给Downloader下载之前,也就是说我们可以在Request执行下载之前对其进行修改。
- 在下载后生成的Response发送给Spider之前,也就是我们可以生成Response被Spider解析之前时对其进行修改。
Downloader Middleware的简单介绍
-
Downloader Middleware中间件的功能十分的强大;可以修改User-Agent、处理重定向、设置代理、失败重试、设置cookies等。
-
Downloader Middleware在整个框架中起到作用的位置是以下两个:
1、在Scheduler调度出队列的Requests发送给Downloader下载之前,也就是我们可以在Request执行下载之前对其进行修改。
2、在下载后生成的Response发送给Spider之前,也就是我们可以生成Response被Spider解析之前对其进行修改
-
在Scrapy中已经提供了许多Downloader MIddleware,如:负责失败重试、自动重定向等中间件;
-
它们都被定义到DOWNLOADER_MIDDLEWARES_BASE变量中。
# 在python3.8/site-packages/scrapy/settings/default_settings.py默认配置中
DOWNLOADER_MIDDLEWARES_BASE = {
# Engine side
'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
# Downloader side
}
这是一种字典格式,字典的键名是scrapy内置的Downloader Middleware的名称,键值代表了调用的优先级,优先级是一个数字,数字越小代表越靠近Scrapy引擎,数字越大就越靠近Downloader,数字小的Downloader Middleware会被优先调用。
如果自己定义的Downloader MIddleware要添加到项目,DOWNLOADER_MIDDLEWARE_BASE变量不能直接修改。Scrapy提供了另一个设置变量DOWNLOADER_MIDDLEWARES,我们直接修改这个变量就可以添加到自己定义的Downloader Middleware,用来禁用DOWNLOADER_MIDDLEWARE_BASE。
接下来我们来具体看看Downloader Middleware的使用方法。
自定义Downloader Middleware中间件
我们通过项目的DOWNLOADER_MIDDLEWARES变量设置来添加自己定义的Downloader Middleware。
其中Downloader MIddleware有三个核心语法:
- process_request(request,spider)
- process_response(request, response, spider)
- process_exception(request, exception, spider)
process_request(request, spider)
当每一个request通过下载中间件时,该方法被调用,这里有一个请求,该方法必须返回以下三种的任意一种:
None、Response对象、Request对象或raise IgnoreRequest,三种返回值的作用是不同的。
None:Scrapy将继续处理该Request,执行其他中间件的相应方法,直到合适的下载处理器函数(download handler)被调用,该Request被执行(其Response被下载)
Response对象:Scrapy将不会调用任何其他的process_request()函数或process_exception()函数,或相应地址下载函数;其将返回该Response。已安装中间件的process_response()函数则会在每个Response返回时被调用。
Request对象:Scrapy则停止调用process_request()函数并重新调度返回的request。当新返回的request被执行后,相应的中间件将会根据下载的response被调用。
raise IgnoreRequest:安装在下载中间件的process_exception()函数会被调用。如果没有任何一个方法处理该异常,则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常,则该异常被忽略且不记录。
process_response(request, response, spider)
process_response()函数的返回值同样也是有三种:response对象、request对象、或者raise IgnoreRequest异常。
如果返回一个Response(可以与传入的response相同,也可以是全新的对象),该response会被在链中的其他中间件的process_response()方法处理。
如果返回的是一个Request对象,则中间件停止,返回的request会被重新加载调度。
如果抛出一个IgnoreRequest异常,则调用request的errback(Request.errback).
process_exception(request, exception, spider)
当下载处理器(download handler)或process_request()(下载中间件)抛出异常(包括IgnoreRequest异常)时,Scrapy调用process_exception()。
process_exception()也是返回三者中的None、一个Response对象、一个Request对象。
如果返回None,Scrapy将会继续处理该异常,接着调用已安装的其他中间件的process_exception()方法,直到所有的中间件都被调用完毕,则调用默认的异常处理。
如果返回一个Response对象,则已安装的中间件链的process_response()方法被调用。Scrapy将不会调用任何其他中间件的process_exception()方法。
项目实战
新建一个项目,命令如下:
scrapy startproject middletest
cd middletest
scrapy genspider test httpbin.org
在该项目中已经创建了一个spider文件,名为test.py,源代码如下:
import scrapy
class TestSpider(scrapy.Spider):
name = 'test'
allowed_domains = ['httpbin.org']
start_urls = ['http://httpbin.org/']
def parse(self, response):
pass
接下来我们对代码进行,简单的修改,具体代码如下所示:
import scrapy
class TestSpider(scrapy.Spider):
name = 'test'
allowed_domains = ['httpbin.org']
start_urls = ['http://httpbin.org/get']
def parse(self, response):
print('响应:', response.url)
print('状态', response.status)
print(response.body.decode('utf-8'))
接下来运行,该test.py这个文件
scrapy crawl test --nolog
Scrapy的运行结果包含Scrapy发送的Request信息,内容如下所示:
响应: http://httpbin.org/get
状态 200
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en",
"Host": "httpbin.org",
"User-Agent": "Scrapy/2.4.1 (+https://scrapy.org)",
"X-Amzn-Trace-Id": "Root=1-60630132-58b2fe4309e16a803367003e"
},
"origin": "120.236.204.4",
"url": "http://httpbin.org/get"
}
我们来观察一下Headers,Scrapy发送的Request使用的user-agent其实是scrapy内置的。我们可以在setings.py进行快速的修改:
image只要将上图中代码的注释打开即可。
为了使其生效,我们还得去setings.py这个文件,将DOWNLOADER_MIDDLEWARES打开,如下图所示:
image如果想要设置的更加灵活,比如说设置随机的User-Agent,那就需要借助Downloader Middleware,所以接下来我们就用Downloader Middleware实现一个随机的user-agent的设置。
在middlewares.py这个文件中,这样来写:
def process_request(self, request, spider):
# Called for each request that goes through the downloader
# middleware.
user_agent = [
'Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)',
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2',
'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1'
]
request.headers['user-agent'] = random.choice(user_agent)
最后
没有什么事情是可以一蹴而就的,生活如此,学习亦是如此!
因此,哪里会有什么三天速成,七天速成的说法呢?
唯有坚持,方能成功!
啃书君说:
文章的每一个字都是我用心敲出来的,只希望对得起每一位关注我的人。在文章末尾点【赞】,让我知道,你们也在为自己的学习拼搏和努力。
路漫漫其修远兮,吾将上下而求索。
我是啃书君,一个专注于学习的人,你懂的越多,你不懂的越多。更多精彩内容,我们下期再见!
网友评论