scrapy提供了很多中間組件可以讓我們更加自定義想要的效果,比如專案管道(item pipeline),下載中間件(downloader middleware),蜘蛛中間件(spider middleware)等,通過更改或者添加的方式我們可以實作很多的功能,這種中間組件就像鉤子一樣,在完成結果之前,修改部分內容來使結果不一樣,或者只是記錄一下內容,
先來說說專案管道,專案管道處理爬蟲回傳或迭代的item,也就是爬蟲抓取的結果,最常用的也就是將結果保存在資料庫了,就比如存盤在MySQL和MongoDB,示例代碼:
import pymysql
from twisted.enterprise import adbapi
class MysqlPipeline(object):
def __init__(self, adbparams, table):
self.table = table
self.adbparams = adbparams
@classmethod
def from_crawler(cls, crawler):
adbparams = dict(
host=crawler.settings.get('MYSQL_HOST'),
port=crawler.settings.get('MSYQL_PORT'),
db=crawler.settings.get('MYSQL_DBNAME'),
user=crawler.settings.get('MYSQL_USER'),
password=crawler.settings.get('MYSQL_PASSWORD'),
chatset=crawler.settings.get('MYSQL_CHARSET'),
cursorclass=pymysql.cursors.DictCursor # 指定cursor型別
)
table = crawler.settings.get('MYSQL_TABLE')
return cls(adbparams, table)
def open_spider(self, spider):
self.dbpool = adbapi.ConnectionPool('pymysql', **self.adbparams)
def close_spider(self, spider):
self.dbpool.close()
def process_item(self, item, spider):
query = self.dbpool.runInteraction(self.do_insert, item) # 指定操作方法和操作資料
query.addCallback(self.handle_error) # 處理例外
return item
def do_insert(self, cursor, item):
# 對資料庫進行插入操作,并不需要commit,twisted會自動commit
keys = ','.join(item.keys())
values = ','.join(['%s'] * len(item))
sql = '''INSERT INTO {table} ({keys}) VALUES ({values})'''.format(table=self.table, keys=keys, values=values)
try:
cursor.execute(sql, tuple(item.values()))
except Exception:
pass
def handle_error(self, failure):
pass
存盤在MongoDB的示例代碼:
import pymongo
class MongoPipeline(object):
collection_name = 'scrapy_items'
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
self.db[self.collection_name].insert_one(dict(item))
return item
專案管道有四個內置方法:
- open_spider:蜘蛛啟動時被呼叫,一般用于打開資源
- close_spider:蜘蛛關閉時被呼叫,一般用于關閉資源
- process_item:當蜘蛛回傳item時被呼叫,一般用于處理item(保存或者舍棄)
- from_crawler: 類方法,用于獲取settings.py中的配置引數,用from_settings也是一樣
上面兩個示例有點區別,MySQL用了twisted實作異步存盤,而MongoDB只是同步的,
當然除了保存資料到資料庫之外,專案管道還有一個比較常用的功能,資料去重,scrapy雖然內置了請求去重的類scrapy.dupefilters.RFPDupeFilter,但是并沒有對抓取下來的資料進行去重,難道不同的請求會出現同樣的資料嗎?有可能,當然這需要看實際情況,不過很多情況下,可以直接使用資料庫的去重功能,比如設定某個欄位不能重復即可,只有一些不保存在資料庫,或者資料庫不方便去重和含有大量的重復資料不想增加資料庫服務器的負擔才會對資料去重,
官網去重示例代碼(這里只是簡單的使用python集合,最好使用redis):
from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/145098.html
標籤:Python
上一篇:scrapy下載中間件(downloader middleware)和蜘蛛中間件(spider middleware)
下一篇:任務25——第一次爬蟲測驗
