官方去重:
scrapy官方文檔的去重模塊,只能實現(xiàn)對當(dāng)前抓取數(shù)據(jù)的去重,并不會和數(shù)據(jù)庫里的數(shù)據(jù)做對比。也就是說如果你抓了100條數(shù)據(jù),里面有10條重復(fù)了,它會丟掉這10條,但100條里有20條和數(shù)據(jù)庫的數(shù)據(jù)重復(fù)了,它也不管,照樣存進去。
class DuplicatesPipeline(object):
def __init__(self):
self.url_seen = set()
def process_item(self, item, spider):
if item['art_url'] in self.url_seen: #這里替換成你的item['#']
raise DropItem("Duplicate item found: %s" % item)
else:
self.url_seen.add(item['art_url']) #這里替換成你的item['#']
return item
增量入庫:
官方的去重比較簡單,只要換成自己的item['#'],然后在settings里啟用DuplicatesPipeline就可以了。
而我的需求要對一個網(wǎng)站長期爬取,所以要不斷對比之前的抓取的內(nèi)容,只需要存入新增的數(shù)據(jù)即可,網(wǎng)上搜了一下,scrapy做增量爬取的資料并不多,有人列出四種方法,相對理想的方法是使用redis來解決。找到一篇使用redis去重的教程,和自己的需求很像,但之前沒用過redis,摸索了半天,終于搞明白了。下面是自己的使用心得,寫在注釋里了,供大家參考:
import mysql.connector
import pandas as pd #用來讀MySQL
import redis
redis_db = redis.Redis(host='127.0.0.1', port=6379, db=4) #連接redis,相當(dāng)于MySQL的conn
redis_data_dict = "f_url" #key的名字,寫什么都可以,這里的key相當(dāng)于字典名稱,而不是key值。
class DuplicatesPipeline(object):
conn = mysql.connector.connect(user = 'root', password='yourpassword', database='dbname', charset='utf8')
def __init__(self):
redis_db.flushdb() #刪除全部key,保證key為0,不然多次運行時候hlen不等于0,剛開始這里調(diào)試的時候經(jīng)常出錯。
if redis_db.hlen(redis_data_dict) == 0: #
sql = "SELECT url FROM your_table_name;" #從你的MySQL里提數(shù)據(jù),我這里取url來去重。
df = pd.read_sql(sql, self.conn) #讀MySQL數(shù)據(jù)
for url in df['url'].get_values(): #把每一條的值寫入key的字段里
redis_db.hset(redis_data_dict, url, 0) #把key字段的值都設(shè)為0,你要設(shè)成什么都可以,因為后面對比的是字段,而不是值。
def process_item(self, item, spider):
if redis_db.hexists(redis_data_dict, item['url']): #取item里的url和key里的字段對比,看是否存在,存在就丟掉這個item。不存在返回item給后面的函數(shù)處理
raise DropItem("Duplicate item found: %s" % item)
return item```
重點說一下,雖然redis是一個鍵值對應(yīng)的數(shù)據(jù)庫,但這里為了速度用的是哈希(hash),和一般的字典不一樣,比一般的字典多了個字段。詳細可以看這個[教程](http://www.runoob.com/redis/redis-hashes.html),重點看hexists,hset,hlen,hgetall這幾個,在終端里運行一下就明白了。教程里都是命令行運行,和python里的用法稍微有點不一樣。
redis哈希結(jié)構(gòu):
結(jié)構(gòu):key field(字段) value
對應(yīng):redis_data_dict url(實際的url) 0(代碼里設(shè)置成了0)
而item里key是'url' value是實際的url
######相當(dāng)于用key(redis_data_dict)的字段(url)來對比item['url']的值,存在為1(true),不存在就是0(false),我開始也是這里暈的,后來打印出來才明白了。
如果要用:
把conn數(shù)據(jù)庫連接換成自己的
修改sql語句,df['url']
然后把item['url']換成自己的,就可以了。
可以在程序中間加入print,把每一步打印出來,看數(shù)值是什么就容易懂了。
最后,感謝這位小伙伴的文章,幫我解決的問題~
####參考文章:
[Scrapy結(jié)合Redis實現(xiàn)增量爬取](http://www.itdecent.cn/p/7b6c1754ee73)