scrapy 引擎,调度器出入队列及去重原理及几个构造request方法

scrapy -engine

1.engine.py

    # 调度四个模块
    def _start(self):
        request = self.spider.start_request()  spider把起始url得到的request 交给 engine

        request = self.spider_mid.process_request(request)  爬虫中间件:在spider交给 engine之前 做事情 *******

        self.scheduler.add_request(request)  engine把request 交给 调度器 入队列

        request = self.scheduler.get_request()  调度器出队列 又交给 engine

        request = self.down_mid.process_request(request)  下载中间件:engine 把request交给下载器之前做事情  *******

        response = self.downloader.get_response(request)  engine 把 request 交给下载器之后得到的响应对象

        response = self.down_mid.process_response(response)  下载中间件:下载器把response交给engine 之前替换新的 *******

        response = self.spider_mid.process_response(response)  爬虫中间件:engine把response交给spider之前做事情 *******

        result = self.spider.parse(response)   spider拿到的响应对象处理解析

        if isinstance(result, Request):  engine 把解析结果中的url request判断出来分别给 调度器 和 管道
            self.scheduler.add_request(result) 类型是request 交给调度器
        else:
            self.pipeline.process_item(result)  类型是数据 交给管道 

 2.调度器的出入队列 queue及去重原理

from six.moves.queue import Queue
class Scheduler(object):
    def __init__(self):
        self.queue=Queue()
        self.filter_container=set()
    # 入队列
    def add_request(self,request):
        if not self.fillter_request(request): #重复
            self.queue.put(request)
            self.filter_container.add(request.url)
    # 出队列
    def get_request(self):
        try:
            return self.queue.get(False)
        except Exception as e:
            return None
    #过滤
    def fillter_request(self,request):
        if request.url in self.filter_container:
            return True
        else:
            return False

     2.指纹结合去重  

    def _creat_fp(self,request):
        # 1.排序
        url=w3lib.url.canonicalize_url(request.url)
        # 2.method大小写
        method=request.method.upper()
        # 3.params
        params=sorted(request.params.items())
        data=sorted(request.data.items())
        fp_str=url+method+str(params)+str(data)
        # 4.生成指纹
        fp=hashlib.sha1()
        fp.updte(fp_str.encode())

        return fp_str.hexdigest()

      

 3.scrapy中构造requests的几个方法

          1.yield response.follow(

            )                 当next_url不全时,自动补全net_url

            next_url = response.xpath('//a[@class="pn-next"]/@href').extract_first()
             yield response.follow(
                next_url,
                callback=self.parse_book,
                meta={'book': item}
            )

         2.scrapy.Request() 

         3.中间件中的process_exception

             当中间件中的process_exception 捕获到 超时异常 或其他 代理原因时 可使用 process_exception捕获异常

    def process_exception(self, request, exception, spider):
        # pass
        self.logger.debug('捕获到超时异常!!!!!')
        self.logger.debug('重试')
        request.meta['proxy'] = 'https:60.235.28.165:8088'       #更换代理或其他
        return request
 
 #在爬虫文件中重写父类  处理捕获到的 异常重新构造一个请求
    def make_requests_from_url(self, url):
        return scrapy.Request(url=url, meta={'download_timeout': 5}, callback=self.parse)

        4.start_requests()和make_requests_from_url()的区别

           有start_requests时不会执行另一个                           作用:  构造url  为请求对象   url 可以自己指定

           make_requests_from_url  构造 start_urls列表中的url 为请求对象  

 

2.from copy import deepcopy

scrapy 中循环嵌套循环时 使用 deepcopy(item)开启一个新的内存空间 使得item中的数据不会被覆盖, 

from copy import deepcopy
class JingdSpider(scrapy.Spider):
    name = 'jingd'
    start_urls = ['https://book.jd.com/booksort.html']
    def parse(self, response):
        dt_list = response.xpath('//*[@id="booksort"]/div[2]/dl/dt[1]')  #
        for dt in dt_list:
            item = JdongItem()
            item['big_name'] = dt.xpath('./a/text()').extract_first()
            for em in em_list:
                item['small_name'] = em.xpath('./a/text()').extract_first()
                yield scrapy.Request(url=small_link, callback=self.parse_book, meta={'book': deepcopy(item)})
#for循环下的item
    def parse_book(self, response):
        item = response.meta['book']
        book_list = response.xpath('//*[@id="plist"]/ul/li[1]')  #
        for book in book_list:
            item['img_url'] = 'https:' + book.xpath
            yield scrapy.Request(url=price_url, callback=self.parse_price, meta={'book': deepcopy(item)})
#for 循环下的item
    def parse_price(self, response):
        item = response.meta['book']
        item['book_price'] = loads(response.body.decode())[0]['p']
        #没有在循环下
        yield item

在for 循环下有多个item['***']数据时使用

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值