zoukankan      html  css  js  c++  java
  • scrapy框架的中间件

    中间件的使用

    • 作用:拦截所有的请求和响应

    • 拦截请求:process_request拦截正常的请求,process_exception拦截异常的请求

      • 篡改请求的头信息

        def process_request(self, request, spider):
        	print('proces_request!!!')
        	#UA伪装
        	request.headers['User-Agent'] = random.choice(self.user_agent_list)
        	return None
        
        # user_agent_list 这个列表中是大量的浏览器信息为了给User-Agent切换信息
        
      • 代理

        #拦截发生异常的请求,目的就是为了将异常的请求进行修正,然后将修正之后的正常的请求进行重新发送
        def process_exception(self, request, exception, spider):
        	#代理操作
        	# request.meta['proxy'] = 'http://ip:port'
        	print('i am exception!!!')
        	return request
        

        注意:process_exception,return request的作用是将修正后的请求重新发送

    • 拦截响应 ------ 以爬取网易新闻为例

      • 篡改响应数据

        • 不满足需求的响应数据对应的一定是不满足需求的响应对象
        • 直接更换响应对象
      • 需求:爬取网易新闻中国内,国际,军事,航工,无人机这五个板块下所有的新闻标题和内容

        • 如何通过中间件更换不满足需求的响应对象
        • selenum如何作用到scrapy
      • 分析:每一个板块中显示的新闻标题是动态加载的

      • seleniumscrapy中的编码流程:

        • 实例化浏览器对象:爬虫类中将实例化出来的浏览器作为爬虫类的一个属性属性可以交互给中间件类
        • 编写自动化操作:写在中间件的process_response
        • 关闭浏览器:写在爬虫类的closed(self)方法中
      • 代码实现:

        爬虫文件得到代码:

        # -*- coding: utf-8 -*-
        import scrapy
        from selenium import webdriver
        from wangyiPro.items import WangyiproItem
        class WangyiSpider(scrapy.Spider):
            name = 'wangyi'
            # allowed_domains = ['www.xxx.com']
            start_urls = ['https://news.163.com/']
            #整个项目中涉及的响应对象个数:
                # - 1+5+n
            #解析:解析五个新闻板块对应的url
            five_model_urls = []
            bro = webdriver.Chrome(executable_path=r'C:UsersAdministratorDesktop爬虫+数据+算法chromedriver.exe')
            
            #方法只会被调用一次
            def closed(self,spider):
                self.bro.quit()
        
            def parse(self, response):
                li_list = response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul/li')
                model_indexs = [3,4,6,7,8]
                for index in model_indexs:
                    li_tag = li_list[index]
                    #解析出了每一个板块对应的url
                    model_url = li_tag.xpath('./a/@href').extract_first()
                    self.five_model_urls.append(model_url)
                    #对每一个板块的url进行手动的请求发送
                    yield scrapy.Request(model_url,callback=self.parse_model)
                    
            #解析:每一个板块中的新闻标题和新闻详情页的url(两个值都是动态加载出来的)
            def parse_model(self,response):
                #遇到了不满足需求的响应对象就是当前方法中的response参数
                div_list = response.xpath('/html/body/div/div[3]/div[4]/div[1]/div/div/ul/li/div/div')
                for div in div_list:
                    title = div.xpath('./div/div[1]/h3/a/text()').extract_first()
                    detail_url = div.xpath('./div/div[1]/h3/a/@href').extract_first()
                    item = WangyiproItem()
                    item['title'] = title
                    if detail_url:
                        yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})
                        
            def parse_detail(self,response):
                item = response.meta['item']
                content = response.xpath('//*[@id="endText"]//text()').extract()
                content = ''.join(content)
                item['content'] = content
        
                yield item
        

        items.py文件的代码:

        import scrapy
        
        class WangyiproItem(scrapy.Item):
            # define the fields for your item here like:
            title = scrapy.Field()
            content = scrapy.Field()
        
        

        middlewares.py文件的代码:中间件

        # -*- coding: utf-8 -*-
        
        # Define here the models for your spider middleware
        #
        # See documentation in:
        # https://docs.scrapy.org/en/latest/topics/spider-middleware.html
        
        from scrapy import signals
        from scrapy.http import HtmlResponse
        from time import sleep
        
        
        class WangyiproDownloaderMiddleware(object):
        
            def process_request(self, request, spider):
                return None
            #拦截所有的响应(1+5+n),只有5个响应不满足需求
            def process_response(self, request, response, spider):
                #1.将拦截到所有的响应中的指定5个不满足需求的响应对象找出
                    # request.url:每一个响应对应的url
                    #spider.five_model_urls:5个板块对应的url
                # print(spider.five_model_urls)
                if request.url in spider.five_model_urls:
                    #满足if条件的response就是5个板块对应的response
                    spider.bro.get(request.url)#对每一个板块对应的url进行get请求发送
                    sleep(3)
                    spider.bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
                    sleep(2)
                    spider.bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
                    sleep(2)
                    page_text = spider.bro.page_source
                    new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)
                    return new_response
                #2.将这5个响应对象删除,实例化5个新的响应对象
                #3.保证5个新的响应对象中包含动态加载出来的新闻标题数据
                #4.将满足需求的5个新的响应对象返回
                else:
                    return response
        
            def process_exception(self, request, exception, spider):
        
                pass
        
        

      ​ 注:记得在settings.py文件中开启对应的操作

  • 相关阅读:
    [Windows]wmic查看运行进程的参数
    Java8中的foreach跳出循环break/return
    Python Learning(6)字典
    SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 后端篇(三): 整合阿里云 OSS 服务 -- 上传、下载文件、图片
    SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 后端篇(四): 整合阿里云 短信服务、整合 JWT 单点登录
    SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 后端篇(五): 数据表设计、使用 jwt、redis、sms 工具类完善注册登录逻辑
    Servlet、Jsp
    BIO、NIO、AIO
    HashMap (JDK1.8) 分析
    mysql常见笔试题
  • 原文地址:https://www.cnblogs.com/zhufanyu/p/12020527.html
Copyright © 2011-2022 走看看