美文网首页
Python爬虫:和我一起学scrapy(四)

Python爬虫:和我一起学scrapy(四)

作者: 小志Codings | 来源:发表于2021-03-30 19:55 被阅读0次
    image

    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)
    

    最后

    没有什么事情是可以一蹴而就的,生活如此,学习亦是如此!

    因此,哪里会有什么三天速成,七天速成的说法呢?

    唯有坚持,方能成功!

    啃书君说

    文章的每一个字都是我用心敲出来的,只希望对得起每一位关注我的人。在文章末尾点【】,让我知道,你们也在为自己的学习拼搏和努力。

    路漫漫其修远兮,吾将上下而求索

    我是啃书君,一个专注于学习的人,你懂的越多,你不懂的越多。更多精彩内容,我们下期再见!

    相关文章

      网友评论

          本文标题:Python爬虫:和我一起学scrapy(四)

          本文链接:https://www.haomeiwen.com/subject/fqoghltx.html