Scrapy实现去重,使用Redis实现增量爬取

一、使用场景:

定时爬取某网站的数据,每次爬取只爬取并保存新增的数据到数据库中,之前存过的数据不再入库。

scrapy官方文档的去重模块,只能实现对当前抓取数据的去重,并不会和数据库里的数据做对比。当有一天需求变了,在你向mysql 数据库保存的时候,发现已经有一部分已经存在,有一部分新的数据,你又需要添加到mysql数据库中,这时候你就需要通过redis来作为中间件,通过url来确保爬过的数据不会再爬,做到增量爬取。

二、准备工作:

1、电脑端安装和启动Redis服务:(参考http://www.runoob.com/redis/redis-install.html) 不启动将无法访问redis服务器

2、安装python的Redis模块:pip install Redis

三、需要知道的知识点

1、pymysql 如何连接、操作数据库

2、Pandas  如何读取mysql数据       

 pandas.read_sql(sql,connection)

3、Redis hash 如何保存数据的以及一些方法

Redis是一个键值对的数据库;Redis hash 是一个string类型的field和value的映射表,是redis提供的一种数据结构存储方式。

redis哈希结构:

结构:key field(字段) value

对应:redis_data_dict   url(实际的url)   0(代码里设置成了0)

key field value三者的关系:把key想象成一个字典的名称,field想象成键,value想象成值,不过这里我们关心的是field字段,也就是关心的是键。这个value值设置有什么用处没搞清楚。

还需要搞清楚flushdb、Hlen、Hset、hexists。参考http://www.runoob.com/redis/redis-hashes.html

四、代码实现

Redis数据库其实就是一个中间件,因为爬虫爬取的数据并不能直接拿去和mysql中的数据进行比较。

实现原理就相当于将mysql数据库现有数据备份出来保存在一个有键值对的Redis数据库中,再将爬取到的数据和redis数据库中的数据进行比较,若redis数据库中的已经存在数据则丢弃,若redis数据库中不存在该条数据则保存进入mysql数据库。每执行一次redis数据库就会被重置一次。

分为几个步骤:

  • 导入模块

  • 连接redis  

  • 连接mysql

  • 清空redis里的key,将mysql数据库中的现有数据写入redis

  • 将新爬到的数据与redis中的数据进行比对,如重复则丢弃,如不重复则写入mysql数据库。

import pymysql
import redis
import pandas

redis_db = redis.Redis(host='127.0.0.1',port=6379,db=1) # 连接本地redis,db数据库默认连接到0号库,写的是索引值
redis_data_dict = ''  # key的名字,里面的内容随便写,这里的key相当于字典名称,而不是key值。为了后面引用而建的


class MysqlRemovePipeline(object):
    def __init__(self):
        self.conn = pymysql.connect('localhost','root','Abcd1234','test')  # 连接mysql
        self.cursor = self.conn.cursor()  # 建立游标
        # print(redis_db)
        redis_db.flushdb()  # 清空当前数据库中的所有 key,为了后面将mysql数据库中的数据全部保存进去
        # print(redis_db)
        if redis_db.hlen(redis_data_dict) == 0:  # 判断redis数据库中的key,若不存在就读取mysql数据并临时保存在redis中
            sql = 'select url from test_zxf'  # 查询表中的现有数据
            df = pandas.read_sql(sql,self.conn)  # 读取mysql中的数据
             # print(df)
            for url in df['url'].get_values():
                redis_db.hset(redis_data_dict,url,0) # 把每个url写入field中,value值随便设,我设置的0  key field value 三者的关系

    def process_item(self,item,spider):
        """
        比较爬取的数据在数据库中是否存在,不存在则插入数据库
        :param item: 爬取到的数据
        :param spider: /
        """
        if redis_db.hexists(redis_data_dict,item['url']): # 比较的是redis_data_dict里面的field
            print("数据库已经存在该条数据,不再继续追加")
        else:
            self.do_insert(item)

    def do_insert(self, item):
        insert_sql = """
                insert into test_zxf(quote,author,tags,url,born_date,born_location) VALUES(%s,%s,%s,%s,%s,%s)
                            """
        self.cursor.execute(insert_sql, (item['quote'], item['author'], item['tags'], item['url'],
                                         item['born_date'], item['born_location']))
        self.conn.commit()  # 提交操作,提交了才真正保存到数据库中
        return item

    def close_spider(self,spider):
        self.cursor.close()  # 关闭游标
        self.conn.close()    # 关闭连接

再配置一下settings文件即可。

这里每次抓取数据都需要保存下url,尽管不是你所需要的数据。然后去比对url来判断是否重复爬取,爬取过的url将不再爬取。

实现增量爬取的方式还有很多,其它的有时间再研究,后续还需要比较下这些方式的不同之处,使用场景分别是什么。加油,吼

源码地址:https://github.com/fang-king/spider/tree/master/quotes_toscrape

猜你喜欢

转载自blog.csdn.net/loner_fang/article/details/81086018