实现增量式爬虫

scrapy流程的新理解

  1. start_urls谁构造的请求?

     def start_requests(self):
         for url in self.start_urls:
             yield Request(url, dont_filter=True)
    
  2. 当爬虫开始运行时,首先引擎会调用爬虫类的start_requests()方法将start_urls列表中的所有url构造成请求对象,放入请求队列

  3. start_requests()方法yield的请求,不经过爬虫中间件,不过滤域名是否超出allowed_domains

是不是所有的请求,放入调度器之前,都会经过爬虫中间件?
  1. start_urls构造的请求不经过
  2. 下载器中间件返回的request请求不经过

scrapy之模拟登陆

  1. 携带Cookie

    def start_requests(self):
         for url in self.start_urls:
             yield Request(url, dont_filter=True,cookies=cookie_dict)
    
  2. 发送post请求

    yield scrapy.FormRequest(
                url="https://github.com/session",
                formdata=formdata,
                callback=self.parse_login
            )
    
  3. form表单请求

    formdata = {
                "login": "noobpythoner",
                "password": "zhoudawei123"
            }
    # 发送请求
    yield scrapy.FormRequest.from_response(
            response,
            formdata=formdata,
            callback=self.parse_login
        )
    

scrapy_redis

pip install scrapy_redis

scrapy_reids 只是scrapy的一个组件

  1. 增量式爬虫 ,请求持久化,下次接着爬取
  2. 分布式爬虫 ,reids共享

实现增量式爬虫

在settings.py中添加如下代码

# 指定了去重的类
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

# 指定了调度器的类
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# 调度器的内容是否持久化
SCHEDULER_PERSIST = True

# redis的url
REDIS_URL = "redis://127.0.0.1:6379"

# 如果数据需要保存到redis中,选配的
ITEM_PIPELINES = {
    'scrapy_redis.pipelines.RedisPipeline': 400,
}

生成指纹

RFPDupeFilter.py

 def request_seen(self, request):
        """
        生成请求指纹,并判断请求在不在指纹集合中
        如果返回True,表示已经放入请求队列中了
        返回False,表示该请求还未做过
        """
        fp = self.request_fingerprint(request) #生成指纹
        # This returns the number of values added, zero if already exists.
        # 尝试将指纹放入指纹集合中,如果返回值为0,代表已经存在
        added = self.server.sadd(self.key, fp)
        return added == 0
def request_fingerprint(request):
    """
    对请求生成指纹,利用hashlib的sha1对象,对request的url、method、body进行哈希,会产生一个40位16进制的字符串,作为request的指纹
    """
    fp = hashlib.sha1()
    fp.update(to_bytes(request.method))
    fp.update(to_bytes(canonicalize_url(request.url)))
    fp.update(request.body or b'')
    return fp.hexdigest()

进入队列

def enqueue_request(self, request):
    if not request.dont_filter and self.df.request_seen(request):
        return False
     self.queue.push(request)
     return True
  1. 如果请求设置的过滤并且请求的指纹在指纹集合中存在的,不进入队列

  2. 其他情况会进入队列

  3. start_url中由于yield请求时,默认设置了dont_filter为True,不过滤,所以肯定会进入队列

为啥设置start_urls为不过滤?

start_url是起始页,其他请求需要靠start_url对应的响应才能保证抓取

如何对数据进行去重?

  1. 数据存入mongodb的时候,可以对关键字段建立复合索引,实现去重
  2. 可以对数据的关键字段进行哈希映射,生成的指纹判断是否存在与指纹集合中,如果存在,说明数据重复
  3. 布隆过滤器,实现大数据量的去重

猜你喜欢

转载自blog.csdn.net/weixin_44090435/article/details/86601329