9.4 Scrapy的項(xiàng)目管道

image
image

這些組件最重要的思路就是攔截,即過(guò)濾

item管道:作用一:入庫(kù)

image

校驗(yàn):一是可以在管道,但主要是在item定義字段校驗(yàn)

管道是什么

Item管道(Item Pipeline):

  • 主要負(fù)責(zé)處理有蜘蛛從網(wǎng)頁(yè)中抽取的Item,主要任務(wù)是清洗、驗(yàn)證和存儲(chǔ)數(shù)據(jù)。
  • 當(dāng)頁(yè)面被蜘蛛解析后,將被發(fā)送到Item管道,并經(jīng)過(guò)幾個(gè)特定的次序處理數(shù)據(jù)。
  • 每個(gè)Item管道的組件都是有一個(gè)簡(jiǎn)單的方法組成的Python類(lèi)。
  • 它們獲取了Item并執(zhí)行它們的方法,同時(shí)還需要確定是否需要在Item管道中繼續(xù)執(zhí)行下一步或是直接丟棄掉不處理。

類(lèi)(Class): 用來(lái)描述具有相同的屬性和方法的對(duì)象的集合。它定義了該集合中每個(gè)對(duì)象所共有的屬性和方法。對(duì)象是類(lèi)的實(shí)例。

image

數(shù)據(jù)去重在管道里面做是下策。在管道里面去重只是預(yù)防。好的去重是在請(qǐng)求url和解析url時(shí)候就去重,清洗html建議在spider里面做。

image

每一個(gè)管道都是一個(gè)類(lèi),每個(gè)類(lèi)里面都有這幾種方法。

一個(gè)管道一個(gè)管道,一層濾網(wǎng)一層濾網(wǎng)

最后一個(gè)方法少修改初始化。

image

必須return item 不然下面的管道就接不上了。給價(jià)格增加增值稅。

image

item去重,見(jiàn)到粗暴,不推薦。要么拋異常,要么返回item,不要?jiǎng)e的。

set集合是不重復(fù)的。

image

打開(kāi)一個(gè)文件名。

序列號(hào),寫(xiě)進(jìn)去一系列字符串

image

加入了mongodb的兩個(gè)參數(shù),并且用init初始化。mongouri和數(shù)據(jù)庫(kù)名兩個(gè)參數(shù)。

image

向mongodb里面插入數(shù)據(jù)。


Item管道主要函數(shù):

1. process_item(self, item, spider) —— 必須實(shí)現(xiàn)(也是用的最多的方法);

每個(gè) Item Pipeline 組件都需要調(diào)用該方法,這個(gè)方法必須返回一個(gè) Item (或任何繼承類(lèi))對(duì)象, 或是拋出 DropItem 異常,被丟棄的 item 將不會(huì)被之后的 pipeline 組件所處理

需要傳入的參數(shù)為:

  • item (Item 對(duì)象) : 被爬取的 item
  • spider (Spider 對(duì)象) : 爬取該 item 的 spider

該方法會(huì)被每一個(gè) item pipeline 組件所調(diào)用,process_item 必須返回以下其中的任意一個(gè)對(duì)象:

  • 一個(gè) dict
  • 一個(gè) Item 對(duì)象或者它的子類(lèi)對(duì)象
  • 一個(gè) Twisted Deferred 對(duì)象
  • 一個(gè) DropItem exception;如果返回此異常,則該 item 將不會(huì)被后續(xù)的 item pipeline 所繼續(xù)訪問(wèn)

注意:該方法是Item Pipeline必須實(shí)現(xiàn)的方法,其它三個(gè)方法(open_spider/close_spider/from_crawler)是可選的方法

舉例說(shuō)明1

以下假設(shè)的管道,它調(diào)整 price那些不包括增值稅(price_excludes_vat屬性)的項(xiàng)目的價(jià)格,并刪除那些不包含價(jià)格的項(xiàng)目

from scrapy.exceptions import DropItem

class PricePipeline(object):

vat_factor = 1.15

def process_item(self, item, spider):

if item['price']: #是否有價(jià)格

if item['price_excludes_vat']: #如果價(jià)格不包括增值稅,則把價(jià)格乘上一個(gè)增值稅系數(shù)

item['price'] = item['price'] * self.vat_factor

return item

else: #如果沒(méi)有價(jià)格,則拋棄這個(gè)item

raise DropItem("Missing price in %s" % item)

舉例說(shuō)明2

此例主要是用于查找重復(fù)Item并刪除已處理的Item的過(guò)濾器。假設(shè)我們的Item具有唯一的ID,但是我們的Spider會(huì)返回具有相同id的多個(gè)Item:

from scrapy.exceptions import DropItem

class DuplicatesPipeline(object):

def init(self):

self.ids_seen = set() #初始化中,創(chuàng)建一個(gè)空集合

def process_item(self, item, spider):

查看id是否在ids_seen中,如果在,就拋棄該Item,如果不在就添加到ids_seen中,下一次其它Item有相同的id就拋棄那個(gè)Item

if item['id'] in self.ids_seen:

raise DropItem("Duplicate item found: %s" % item)

else:

self.ids_seen.add(item['id'])

return item #記住一定要返回Item

2.open_spider(self, spider) —— 非必需,為爬蟲(chóng)啟動(dòng)的時(shí)候調(diào)用;

當(dāng) spider 被開(kāi)啟時(shí),這個(gè)方法被調(diào)用??梢詫?shí)現(xiàn)在爬蟲(chóng)開(kāi)啟時(shí)需要進(jìn)行的操作,比如說(shuō)打開(kāi)一個(gè)待寫(xiě)入的文件,或者連接數(shù)據(jù)庫(kù)等

需要傳入的參數(shù):

  • spider (Spider 對(duì)象) : 被開(kāi)啟的 spider

3. close_spider(self, spider) —— 非必需, 為爬蟲(chóng)關(guān)閉的時(shí)候調(diào)用;

當(dāng) spider 被關(guān)閉時(shí),這個(gè)方法被調(diào)用??梢詫?shí)現(xiàn)在爬蟲(chóng)關(guān)閉時(shí)需要進(jìn)行的操作,比如說(shuō)關(guān)閉已經(jīng)寫(xiě)好的文件,或者關(guān)閉與數(shù)據(jù)庫(kù)的連接

需要傳入的參數(shù):

  • spider (Spider 對(duì)象) : 被關(guān)閉的 spider

舉例說(shuō)明:

將項(xiàng)目寫(xiě)入JSON文件

以下管道將所有抓取的Item(來(lái)自所有蜘蛛)存儲(chǔ)到單個(gè)items.json文件中,每行包含一個(gè)項(xiàng)目,以JSON格式序列化:

import json

class JsonWriterPipeline(object):

def open_spider(self, spider):

在爬蟲(chóng)開(kāi)始時(shí)打開(kāi)文件

self.file = open('items.json', 'w')

def close_spider(self, spider):

在爬蟲(chóng)結(jié)束時(shí)關(guān)閉文件

self.file.close()

def process_item(self, item, spider):

把爬取到的item轉(zhuǎn)換為json格式,保存進(jìn)文件

line = json.dumps(dict(item)) + "\n"

self.file.write(line)

return item #注意要返回item

4. from_crawler(cls, crawler) —— 非必需,也是在啟動(dòng)的時(shí)候調(diào)用,比 open_spider早。

該類(lèi)方法用來(lái)從 Crawler 中初始化得到一個(gè) pipeline 實(shí)例;它必須返回一個(gè)新的 pipeline 實(shí)例;Crawler 對(duì)象提供了訪問(wèn)所有 Scrapy 核心組件的接口,包括 settings 和 signals

需要傳入的參數(shù):

  • crawler (Crawler 對(duì)象) : 使用該管道的crawler

舉例說(shuō)明:

此例主要使用pymongo將項(xiàng)目寫(xiě)入MongoDB。MongoDB地址和數(shù)據(jù)庫(kù)名稱(chēng)在Scrapy設(shè)置中指定; MongoDB集合以item類(lèi)命名

from_crawler()方法是創(chuàng)建通往Crawler的pipeline,返回一個(gè)新的pipeline實(shí)例

這個(gè)例子的要點(diǎn)是顯示如何使用from_crawler()方法和如何正確清理資源

通過(guò)類(lèi)方法 from_crawler() 在內(nèi)部初始化得到了一個(gè) pipeline 實(shí)例,初始化的過(guò)程中,使用了 mongo_uri 以及 mongo_db 作為構(gòu)造參數(shù)


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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容