zoukankan      html  css  js  c++  java
  • scrapy框架4——下载中间件的使用

    一、下载中间件

    下载中间件是scrapy提供用于用于在爬虫过程中可修改Request和Response,用于扩展scrapy的功能;比如:

    1. 可以在请求被Download之前,请求头部加上某些信息(例如:user-agent,proxy);
    2. 完成请求之后,回包需要解压等处理;(selenium)

    process_request(request, spider)

    当每个Request对象经过下载中间件时会被调用,优先级越高的中间件,越先调用;该方法应该返回以下对象:None/Response对象/Request对象/抛出IgnoreRequest异常;

    1. 返回None:scrapy会继续执行其他中间件相应的方法;
    2. 返回Response对象:scrapy不会再调用其他中间件的process_request方法,也不会去发起下载,而是直接返回该Response对象;
    3. 返回Request对象:scrapy不会再调用其他中间件的process_request()方法,而是将其放置调度器待调度下载;
    4. 抛出IgnoreRequest异常:已安装中间件的process_exception()会被调用,如果它们没有捕获该异常,则Request.errback会被调用;如果再没被处理,它会被忽略,且不会写进日志。

    process_response(request, response, spider)

    当每个Response经过下载中间件会被调用,优先级越高的中间件,越晚被调用,与process_request()相反;该方法返回以下对象:Response对象/Request对象/抛出IgnoreRequest异常。

    1. 返回Response对象:scrapy会继续调用其他中间件的process_response方法;
    2. 返回Request对象:停止中间器调用,将其放置到调度器待调度下载;
    3. 抛出IgnoreRequest异常:Request.errback会被调用来处理函数,如果没有处理,它将会被忽略且不会写进日志。

    process_exception(request, exception, spider)

    process_exception()process_request()抛出异常时会被调用,应该返回以下对象:None/Response对象/Request对象;

    1. 如果返回None:scrapy会继续调用其他中间件的process_exception()
    2. 如果返回Response对象:中间件链的process_response()开始启动,不会继续调用其他中间件的process_exception()
    3. 如果返回Request对象:停止中间器的process_exception()方法调用,将其放置到调度器待调度下载。

    from_crawler(cls, crawler)

    如果存在该函数,from_crawler会被调用使用crawler来创建中间器对象,必须返回一个中间器对象,通过这种方式,可以访问到crawler的所有核心部件,如settingssignals等。

    先在setting.py中开启下载中间件

    DOWNLOADER_MIDDLEWARES = {
        'douban.middlewares.DoubanDownloaderMiddleware': 543,
    }
    

    ​ 下载中间件开启后,resquest和response都会经过下载中间件;在下载器发起网络请求之前,下载中间件对resquest拦截,对其中的user-agent和ip代理进行设置。

    二、通过下载中间件设置UA池和代理池

    打开middlewares.py(其他未进行设置的相关代码可删除)

    import random
    class DoubanDownloaderMiddleware(object):
        user_agent_list = [
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
            "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
            "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
            "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "
            "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
            "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "
            "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
            "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "
            "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "
            "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
            
    ]
        PROXY_http = [
        '153.180.102.104:80',
        '195.208.131.189:56055',]
        PROXY_https = [
        '120.83.49.90:9000',
        '95.189.112.214:35508',]
        def process_request(self, request, spider):
            resquest.headers['User-Agent'] = random.choice(self.user_agent_list)
            return None
    
        def process_response(self, request, response, spider):
            
            return response
    
        def process_exception(self, request, exception, spider):
            h = request.url.split(':')[0]  
            if h == 'https':
                ip = random.choice(PROXY_https)
                request.meta['proxy'] = 'https://'+ip
            else:
                ip = random.choice(PROXY_http)
                request.meta['proxy'] = 'http://' + ip
            return resquest
     
    

    三、处理动态加载的数据

    使用requests模块获取一张页面中动态加载的数据,需要先找到真正的url,向真正的url发送请求。而使用selenium驱动浏览器,使用起始url就可以获取整张页面的所有数据。在scrapy中如何使用selenium:
    

    ​ 在spider文件中,照常书写代码,使用每张页面的起始url,忽略动态加载的问题。

    在下载中间件中,对含有动态加载页面的url的response进行拦截,用selenium对该url发送请求,使用得到的数据对response进行‘‘篡改“,这样spider就能正常解析数据了。

    import scrapy
    from wangyi.items import WangyiItem
    from selenium import webdriver
    class WyspiderSpider(scrapy.Spider):
        name = 'wyspider'
        start_urls = ['https://news.163.com/']
        chrome_options = webdriver.chrome.options.Options()
        chrome_options.add_experimental_option('excludeSwitches', ['enable-automation']) #规避检测
        path = 'D:爬虫chromedriver.exe'
        chrome = webdriver.Chrome(executable_path=path,options = chrome_options)
        check_list = []
        def parse(self, response):
            url_list = response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul//a/@href').extract()
            for i in [3,4,6,8]:       
                block = url_list[i]
                self.check_list.append(block)   #收集含有动态加载页面的url
                yield scrapy.Request(callback=self.parse_title,url=block)
        def parse_title(self,response):
            temp = response.xpath('/html/body/div[1]/div[3]/div[4]/div[1]/div/div/ul/li/div/div/div/div[1]/h3')
            for i in temp:
                title = i.xpath('./a/text()').extract_first()
                content_url = i.xpath('./a/@href').extract_first()
                item = WangyiItem()
                item['title'] = title
                yield scrapy.Request(callback=self.parse_content,url=content_url,meta={'item':item})
        def parse_content(self,response):
            item = response.meta['item']
            content_list = response.xpath('//*[@id="endText"]/p/text()').extract()
            content = ''.join(content_list).replace(' ','')
            content = content.replace('
    ','')
            item['content'] = content
            print(content)
            yield item
        def closed(self,spider):  # 重写父类,结束后关闭
            self.chrome.close()
    

    在middlewares.py中

    from scrapy import signals
    from scrapy.http import HtmlResponse
    
    class WangyiDownloaderMiddleware(object):
       
        def process_response(self, request, response, spider):
            if request.url in spider.check_list:   
       # 判断是否为含有动态加载页面的url,含有则使用spider中的浏览器对象进行get重新发送
                spider.chrome.get(url = request.url)   
        #将selenium的浏览器对象在Spider中进行实例化和关闭,减少开启和关闭。
                #spider.chrome.execute_script('window.scrollTo(0,document.body.scrollHeight)')
                #time.sleep(2)
                page = spider.chrome.page_source
                return HtmlResponse(url=request.url,body=page,
                                    encoding='utf8',request=request) 
                              # HtmlResponse的对象,response此时才包含要解析的数据(body=page)
            else:
                return response
    
    
  • 相关阅读:
    [置顶] windows player,wzplayerV2 for windows
    wzplayer 近期将会支持BlackBerry和WinPhone8
    wzplayerEx for android(真正硬解接口,支持加密的 player)
    ffmpeg for ios 交叉编译 (支持i686 armv7 armv7s) 包含lame支持
    ffmpeg for ios 交叉编译 (支持i686 armv7 armv7s) 包含lame支持
    编译cegcc 0.59.1
    wzplayer 近期将会支持BlackBerry和WinPhone8
    wzplayerEx for android(真正硬解接口,支持加密的 player)
    windows player,wzplayerV2 for windows(20140416)更新
    编译cegcc 0.59.1
  • 原文地址:https://www.cnblogs.com/notfind/p/11640518.html
Copyright © 2011-2022 走看看