Scrapy08:scrapy-deltafetch,让爬虫有了记忆

deltafetch,让爬虫有记忆

前言

”我化作人鱼,只有七秒钟的记忆“。

很多时候,爬虫程序跑着跑着,因为网络故障或者程序异常就宕掉了。无奈之下只能重启重新爬取。为了避免这种每次重头再来的情况,我们都会利用mysql、redis、文本等方式,来记录一下爬取过的url。

这也提高了程序整体的复杂度。而scrapy提供了一个模块来解决了这个痛点,仅仅两行配置就解决了这个问题。

断点续爬

在Scrapy系列的第一篇,我就写了一个爬虫常见断点续爬问题。

假如有1000个页面需要爬取,爬到第999个页面,进度条马上满格的时候,程序咯噔一下挂了,就差一个,但是还是没爬完啊,咋整?我选择重新启动程序,那么你说我怎么样才能直接从第999个开始爬取呢?

这里先讲讲我写的第一个爬虫:爬取10+个地市的poi信息。

17年实习,第一次开发爬虫,也不知道有高德poi接口啥的,于是就找了个网站来爬取poi信息。当时那个网站估计还在起步阶段,服务器带宽应该不高,访问速度是真的慢,而且动不动维护停站,所以我的程序也得跟着停止。如果每次启动都重新爬取,估计几年也爬不完,于是我想了个办法。

我先将所有地市下所有区县数据的条数(网站上有)先手动录入到数据库表中,每次重新启动爬虫程序的时候,先统计结果数据表中各个区县已经爬取的条数,与总条数进行对比。如果小于的话,说明还没有爬取完,然后通过某区县已爬取条数 / 网站每页展示条数计算出我已经爬取到此区县的页数,再通过余数定位到我爬到了此页面的第几个。通过这种方法,最后无丢失爬取了163w条数据。

换种思路,将爬取的url放到表中,重启程序开始爬取url的时候,先去判断url是否存在于数据表中,如果存在就不进行爬取,这样也能实现断点续爬。也是沿用了原始的url的去重的思路。

而今天,要讲的scrapy-deltafetch,完全不用考虑上面的这些问题!

Scrapy-deltafetch

上面的两种思路有两个共同点:

  1. 手动实现断点逻辑代码
  2. 依赖外部存储/数据库

这样就加大了开发的工作量。所以我们这里就引入了scrapy-deltafecth模块,两行配置就可以完美解决上面的两个问题。

原理

deltch在Scrapy中是作为一个Spider中间件存在的。原理就是内置一个内嵌式KV数据库BerkeleyDB,在执行yield item的时候,将response.request加密作为key存储到内嵌式数据库中。

这样,每次爬取的时候,都会去内嵌数据库中判断这个url是否已存在,存在就不再爬取。

这时候就有人要说了,这不还是用到了数据库吗?

内嵌式数据库和数据库是有区别的:

  1. 内嵌式数据库嵌入到了应用程序进程,同应用程序在相同的地址空间中运行,所以数据库操作不需要进程间的通讯
  2. 嵌入数据库是一种具备了基本数据库特性的数据文件,提供了一套API去访问、管理一个数据库文件,采用程序方式直接驱动,而非引擎响应方式驱动

简言之,就是内嵌式数据库不会像MySQL这种数据库一样,有属于自己的后台服务,自己的执行引擎。

安装deltafetch

deltafetch在Windows和Linux环境下的安装方式不一样的,Linux下的安装比较复杂。

deltafech模块依赖于bsddb3模块,bsddb3又需要依赖BerkeleyDB。

Windows安装

Win下的安装比较简单,不需要单独安装BerkeleyDB。直接使用pip安装bsddb3,如果安装失败,就去下载whl安装版单独安装。然后再安装scrapy-deltafetch即可。

具体方法就不做阐述了,主要讲讲Llinux下的安装。

Linux安装

Linux下的安装比较麻烦一点,需要自己去oracle官网下载Berkeley DB,然后进行编译安装。

1.下载安装Berkeley DB

亲测,不要下载Berkeley DD的v18版本,我使用的是6.2.23版本。

# ,18版本不行,18.1.40会安装失败,18低版本在安装bsddb3时会报错
cd build_unix
../dist/configure --prefix=/usr/local/berkeleyDb
make & make install 

2.安装bsddb3

export BERKELEYDB_DIR=/usr/local/berkeleyDb
export YES_I_HAVE_THE_RIGHT_TO_USE_THIS_BERKELEY_DB_VERSION=yes   
pip3 install bsddb3             

3.安装scrapy-deltafetch

pip3 install  scrapy-deltafetch

使用scrapy-deltafetch

1. 修改settings.py

在settings.py中,添加deltafetch中间件并激活。

SPIDER_MIDDLEWARES = { 
     'scrapy_deltafetch.DeltaFetch': 100 
   } 

# 开启
DELTAFETCH_ENABLED = True

这里要注意的点是,deltafetch是一个spider中间件,根据架构图,spider只有yield item到pipeline的时候才会触发,所以只有yield item才能让deltafetch生效。

2.重置DeltaFetch

当我们第一次启动爬虫的时候,它会从头开始爬取,如果再次重启,那么爬取过的url则不会再重新爬取。那么我们需要在启动时添加参数,告诉爬虫我要重新爬取。

scrapy crawl name -a deltafetch_reset=1

3.成功标志

如何判断deltafetch生效了呢

在程序的根目录下的隐藏目录.scrapy中,找到deltafetch目录,里面会根据crawler_name生成db文件,这个就是berlekeyDB的数据库文件,里面记录着已经爬取过的url信息。

之前提到的的deltafetch_reset=1参数,就是清空对应的db文件。

demo

先不加参数启动爬虫,启动了两次程序,相同的url都进行了数据爬取。

配置了deltefetch之后。第二次启动时,就会提示忽略已经爬取的url,不再进行爬取。

如果想要重新爬取之前爬取过的url,启动前添加deltafetch_reset=1参数即可。

核心源码

DeltaFetch类为核心代码。

def process_spider_output(self, response, result, spider):
    for r in result:
        if isinstance(r, Request):
            key = self._get_key(r)
            if key in self.db:
                logger.info("Ignoring already visited: %s" % r)
                if self.stats:
                    self.stats.inc_value('deltafetch/skipped', spider=spider)
                continue
        elif isinstance(r, (BaseItem, dict)):
            key = self._get_key(response.request)
            self.db[key] = str(time.time())
            if self.stats:
                self.stats.inc_value('deltafetch/stored', spider=spider)
        yield r

结语

个人觉得deltafetch安装是比较容易遇到问题的,还是要多查阅一些资料。下一篇就是scrapy-splash,一个网页渲染的插件,可以替换selenium。

感谢每一份关注

猜你喜欢

转载自blog.csdn.net/CatchLight/article/details/127093923