scrapy入门(二)请求传参和中间件

  1. scrapy的请求传参

    作用 : 实现深度爬取

    使用场景 : 爬取的数据没有在同一张页面

    例如, 爬取电影首页全部电影的详情页信息

    #请求传参: 让Request将一个数据值(字典)传递给回调函数
    #在第一页中将item对象的第一个属性赋值,然后通过请求传参将item对象传过去
    #手动发送get请求:
    model_index = [3,4,6,7,8]
    for index in model_list:
     li =li_list[index]
     model_url = li.xpath('xxxxxxx').extract_first()
     self.model_urls.append(model_url)
    #for li in li_list:  #这种适用于所有的li标签都需要的情况下,当只需要某几个标签时,选用上面的方式
     #...
       yield scrapy.Request(url=, callback=my_parse, meta={'item':item})
    if self.page < 5:
     self.page += 1
     new_url = format(self.url%self.page)
     yield scrapy.Request(url=new_url,callback=parse)
    
    
    
    def my_parse(self, response):
     #接受请求传参的数据,还原出item对象
     item = response.meta['item']
       #解析item对象需要的第二个属性
     xxx = respnse.xpath('').extract_first()
     #给item对象的第二个属性赋值
     item['xxx'] = xxx
     #还可以接着请求传参,这里不再演示
     yield item
  2. scrapy的中间件, 和管道一样, 需要在配置文件中开启中间件

    下载中间件 : 批量拦截requests和response

    作用:

    • 修改请求的头信息
    • 修改请求的ip地址 (代理模式)
    • 修改响应对象(数据)

    middlewares.py文件: 修改成如下形式

    import scrapy
    
    #构建UA池,这样可以不在settings文件中写死
    user_agent_list = [
        'xxxxxx',
        'xxxxxxxxx',
        'xxxxxxxxxxxxxxxxxxx'
    ]
    class SecondtestDownloaderMiddleware(object):
        #拦截正常请求
        def process_request(self, request, spider):
           #进行UA伪装,构建UA池
            request.headers['User-Agent'] = random.choice(user_agent_list)
            
            #代理,也可以构建自己的代理池
            request.meta['proxy'] = 'xxxxxxxxxxxx'
            return None
       #拦截所有的响应
        def process_response(self, request, response, spider):
           #拦截由于动态加载得到的不符合需求的响应对象
            #request表示请求对应的??对象
            #response表示所有的响应对象
            #spider是SecondSpider类(爬虫源文件对应的类)的实例化对象
            if request.url in spider.model_urls:
                #body 有selenium中的page_source返回
                browser = spider.browser
                browser.get(request.url)
                sleep(3)
                page_text = browser.page_source
                new_response = HtmlResponse(url=request.url,body=page_text,encoding ='utf-8',request=request)
                return new_response
            else:
                return response
            return response
       #拦截发生异常的请求对象
        def process_exception(self, request, exception, spider):
           #对异常的url请求进行修正
            return request     #重新发送

    源文件中进行修改

    #在爬虫类中定义一个属性model_urls =[]用来保存解析得到的li标签的url
    #
    from selenium import webdriver
    
    class xxx(scrapy.Spider):
        name = ''
        model_urls =[]
        browser = webdriver.Chrome(executable_path ='')
        #下面三个函数调用过程中可能出现请求传参的情况
        def parse(self,response):
            pass
        def parse_model(self,response):
            pass
        def parse_new_detail(self,response):
            content = response.xpath('xxxx//text()').extract()#解析所有的文本内容,跨标签,返回的是列表
            content = ''.jion(content)
            pass
      #该方法只会在程序结束时调用一次
      def closed(self,spider):
        self.browser.quit()
  3. 提升爬取效率

    • 增加并发: 32---->100
    • 降低日志等级
    • 不需要cookie的时候可以禁止,默认是开启. 设置为COOKIES_ENABLED = False为禁止
    • 禁止重试RETRY_ENABLED = False
    • DOWNLOAD_TIMEOUT = 1