如何让python爬虫实现断点续爬

    当采集一个大型网站时,一般栏目非常多,而python爬虫一天又不可能采集完,就算能采集完当前整个网站的数据,如果要采集明天的或未来更新的数据,就不可能一天完成了,这个时间就要记录采集点,例如,采集到哪个栏目了,采集到哪个子栏目,采集到哪一个页面了等,这些都是最基本的重要信息。


    若没有记录这些信息,第二天采集的时候难道要重新从头采集?这就像下载软件似的,当我们下载一个几G的视频,如果不小心关闭了下载软件,而下载的软件会“记住”下载了多少,等再次打开软件软件会继续下载,而不是从零开始从头下载。

    
    这就需要我们写的爬虫必须具备断点续爬的功能,当然我们可以使用分布式scrapy-redis来解决这个问题,但是,很多时候我们用不到分布式爬虫,例如,使用selenium来写爬虫,这时就要自己手动去设计断点续爬,根据爬虫之家设计并采集了约1200多万条数据的经验,现在把本人设计的方法分享给大家。


    若要让爬虫下次爬取数据时,从上次断开的地方开始爬虫,就要根据我们项目的需求来设计,不同的爬虫项目需要设计的点不一样。


    但是记住下面几点是我们必须的:


    1)栏目


    采集往往通过一个栏目一个栏目的采集,这样做主要是因为人家目标网站都已经分好栏目了,我们也跟着目标网站来创建栏目,然后把栏目数据采集到本地相应栏目即可,所以,记住栏目是非常有必要的。


    2)页数


    采集到哪一页了也比较重要,如果一个栏目有几千页,哪怕是几百页如果不对页数进行记录的话,每次采集都要从头采集,这样导致的结果就是浪费不少时间,采集的越多越广爬虫断开的可能性越高,所以有必要记住页数,在记录页数时也不一定非要精确到采集到了那一条数据,只需要记录将要采集的网页即可,最好故意有一点误差少记几页,例如,现在采集到了20页,我们记录时让程序知道我们采集到18,19页都可以,这样做的目的是如果网站更新,也可以有一定余地。


    3) 采集次数


    每个栏目全部采集完最好从头再采集一次,所以有必要设计一个程序记住这个栏目采集多少次了,毕竟第一遍采集时有可能出现各种各样的问题,例如,网络不稳定,网页打开出问题等,这样采集完一个栏目再采集一遍可以保证采集的数据不会丢失,即使第一次丢失了第二次采集时可以补上。


    4)跳过采集过的数据


    当第二次采集一个栏目时,如何跳过采集过的数据,最好的方法是在采集前先把当前栏目数据查询出来,然后放到文件中,当采集数据时先从文件中查询出数据库中已经存在的数据,把要采集的数据跟查询出来的数据对比,看看是否已经采集过,若采集过了则跳过。


    5) 其它


    要记住哪些重要信息为断点续爬服务,还需要根据自己爬虫项目来决定,不同的项目采集的目标网站不一样,具体要记住的数据也有区别,这里不一一列举了,只用上面几点来说明。


设计断点续爬


    断点续爬方法:每次重启爬虫时,查询相应的文件,文件可以是txt,也可以是py格式的文件,根据这里面记住的信息定位到相应位置,然后接着采集数据。


    爬虫之家是把要记住的信息都保存到了.txt文件里面,当下次再次爬取数据时,先查询这些文件看是否有值,若值为空或为0,则说明要从头开始爬数据。


    具体方法:若type.txt文件中不空,而是保存了某个栏目则去找这个栏目,然后再看这个栏目对应的网页文件page.txt看里面是否为0,若不是零则在刚找到的这个栏目下面,一步步查找栏目对应的页数,一直定位到页数为止,这样就实现了断点续爬,当然,在查找栏目时可以先查询爬虫爬行次数文件times.txt看是否为1,若为1则说明此栏目已经爬完了,就去爬其它的栏目,若此文件内容为0则说明还没有采集,然后再看栏目文件和页数文件。


    下面是我设计的代码,是从项目中直接抠出来的,无法直接运行,只做说明使用:

    #定义文件:

        self.title_file_name = './record/'+type_name+'/'+type_name+'_title.txt'        self.type_file_name = './record/'+type_name+'/'+type_name+'_type.txt'        self.page_file_name = './record/'+type_name+'/'+type_name+'_page.txt'        self.year_file_name = './record/'+type_name+'/'+type_name+'_year.txt'


        # 断点续爬判断

        self.keep_type_name = db.getFromFile(self.type_file_name,False)        self.keep_on = False        if len(self.keep_type_name) >= 4:            self.keep_on = True


    通过keep_on是否为True来判断是否需要断续爬,这样后面第一次启动爬虫后在遍历栏目时,需要判断一下keep_on值是否为True,若是True则查询type.txt表中的栏目是哪一个,然后去找这个栏目。

    遍历栏目时判断是从头开始,还是断点续爬

    keep_type_name = db.getFromFile(self.type_file_name,False)                if self.keep_on:                    #这里是代码                    if keep_type == which_type:                        which_type = keep_type                    else:                        continue                    if which_type_len == type_len:                        self.keep_on = False


    上面只是处理栏目伪代码,等到确定要爬哪个栏目后,再确定要爬取哪个页面,处理方法跟上面几乎完全一样,先从保存页数的文件page.txt里面查询出数据,看值是否为0,若不为0则在当前栏目下面点击页数,一直找到文件中保存的页数值,这样就相当定位到上次爬虫爬的位置了。


    通过上面的方法就实现了断点续爬,当然项目中哪个地方要断点续爬要根据自己的需求而定,实际使用要复杂的多。


    如果小项目需要手动去设计断点续爬,而大项目如果使用框架的话,很多爬虫框架都集成了这个功能,只要设置一下即可,而对于中小项目可能就需要我们手动来设计这个功能。