python3的爬蟲筆記17——Scrapy中Item Pipeline的用法

Item Pipeline(項(xiàng)目管道)

在一個(gè)項(xiàng)目被spider抓取后茄螃,它被發(fā)送到Item Pipeline气筋,Item Pipeline通過順序執(zhí)行的幾個(gè)組件處理它拆内,決定該項(xiàng)目是否應(yīng)該繼續(xù)通過Pipeline或被丟棄并且不再處理。

Item Pipeline的典型用途是:

  • 清理HTML數(shù)據(jù)
  • 驗(yàn)證已刪除的數(shù)據(jù)(檢查項(xiàng)目是否包含某些字段)
  • 檢查重復(fù)項(xiàng)(并刪除它們)
  • 將已刪除的項(xiàng)目存儲(chǔ)在數(shù)據(jù)庫中

編寫自己的項(xiàng)目管道

每個(gè)項(xiàng)管道組件都是一個(gè)必須實(shí)現(xiàn)以下方法的Python類:
process_item(self, item, spider)
為每個(gè)Item Pipeline組件調(diào)用此方法宠默。process_item()必須:返回帶數(shù)據(jù)的dict麸恍,返回Item(或任何后代類)對(duì)象,返回Twisted Deferred或引發(fā)DropItem異常搀矫。 丟棄的項(xiàng)目不再由其他管道組件處理抹沪。

open_spider(self, spider) 打開spider時(shí)會(huì)調(diào)用此方法。

close_spider(self, spider) 當(dāng)spider關(guān)閉時(shí)調(diào)用此方法瓤球。

from_crawler(cls, crawler)
如果存在融欧,則調(diào)用此類方法以從a創(chuàng)建管道實(shí)例Crawler。它必須返回管道的新實(shí)例卦羡。Crawler對(duì)象提供對(duì)所有Scrapy核心組件的訪問蹬癌,如設(shè)置和信號(hào); 它是管道訪問它們并將其功能掛鉤到Scrapy的一種方式权她。

激活I(lǐng)tem Pipeline組件

要激活I(lǐng)tem Pipeline組件,必須將settings.py中的ITEM_PIPELINES設(shè)置打開逝薪,如下例所示:

ITEM_PIPELINES = {
    'myproject.pipelines.PricePipeline': 300,
    'myproject.pipelines.JsonWriterPipeline': 800,
}

此設(shè)置中為類分配的整數(shù)值決定了它們運(yùn)行的??順序:較低值優(yōu)先級(jí)高隅要。習(xí)慣上在0-1000范圍內(nèi)定義這些數(shù)字。

項(xiàng)目管道示例

1董济、 價(jià)格驗(yàn)證和丟棄物品沒有價(jià)格

調(diào)整 price那些不包含增值稅(price_excludes_vat屬性)的項(xiàng)目的屬性步清,并刪除那些不包含價(jià)格的項(xiàng)目:

from scrapy.exceptions import DropItem

class PricePipeline(object):

    vat_factor = 1.15

    def process_item(self, item, spider):
        if item.get('price'):
            if item.get('price_excludes_vat'):
                item['price'] = item['price'] * self.vat_factor
            return item
        else:
            raise DropItem("Missing price in %s" % item)

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

以下管道將所有已刪除的項(xiàng)目(來自所有蜘蛛)存儲(chǔ)到一個(gè)items.jl文件中虏肾,每行包含一個(gè)以JSON格式序列化的項(xiàng)目:

import json

class JsonWriterPipeline(object):

    def open_spider(self, spider):
        self.file = open('items.jl', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item

3廓啊、將項(xiàng)目寫入MongoDB

在這個(gè)例子中,我們將使用pymongo將項(xiàng)目寫入MongoDB封豪。MongoDB地址和數(shù)據(jù)庫名稱在Scrapy設(shè)置中指定谴轮;MongoDB集合以item類命名。
這個(gè)例子的要點(diǎn)是展示如何使用from_crawler() 方法以及如何正確地清理資源:

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

4吹埠、截取項(xiàng)目的截圖

此示例演示如何從process_item()方法返回Deferred第步。它使用Splash渲染項(xiàng)目URL的屏幕截圖。Pipeline向本地運(yùn)行的Splash實(shí)例發(fā)出請求缘琅。下載請求并延遲回調(diào)激活后粘都,它會(huì)將項(xiàng)目保存到文件并將文件名添加到項(xiàng)目中。

import scrapy
import hashlib
from urllib.parse import quote


class ScreenshotPipeline(object):
    """Pipeline that uses Splash to render screenshot of
    every Scrapy item."""

    SPLASH_URL = "http://localhost:8050/render.png?url={}"

    def process_item(self, item, spider):
        encoded_item_url = quote(item["url"])
        screenshot_url = self.SPLASH_URL.format(encoded_item_url)
        request = scrapy.Request(screenshot_url)
        dfd = spider.crawler.engine.download(request, spider)
        dfd.addBoth(self.return_item, item)
        return dfd

    def return_item(self, response, item):
        if response.status != 200:
            # Error happened, return item.
            return item

        # Save screenshot to file, filename will be hash of url.
        url = item["url"]
        url_hash = hashlib.md5(url.encode("utf8")).hexdigest()
        filename = "{}.png".format(url_hash)
        with open(filename, "wb") as f:
            f.write(response.body)

        # Store filename in item.
        item["screenshot_filename"] = filename
        return item

5刷袍、重復(fù)過濾

一個(gè)過濾器翩隧,用于查找重復(fù)項(xiàng)目,并刪除已處理的項(xiàng)目呻纹。假設(shè)我們的項(xiàng)目具有唯一ID堆生,但我們的spider會(huì)返回具有相同ID的多個(gè)項(xiàng)目:

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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市雷酪,隨后出現(xiàn)的幾起案子淑仆,更是在濱河造成了極大的恐慌,老刑警劉巖太闺,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘁圈,居然都是意外死亡省骂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門最住,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钞澳,“玉大人,你說我怎么就攤上這事涨缚≡冢” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長兰吟。 經(jīng)常有香客問我通惫,道長,這世上最難降的妖魔是什么混蔼? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任履腋,我火速辦了婚禮,結(jié)果婚禮上惭嚣,老公的妹妹穿的比我還像新娘遵湖。我一直安慰自己,他們只是感情好晚吞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布延旧。 她就那樣靜靜地躺著,像睡著了一般槽地。 火紅的嫁衣襯著肌膚如雪迁沫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天闷盔,我揣著相機(jī)與錄音弯洗,去河邊找鬼。 笑死逢勾,一個(gè)胖子當(dāng)著我的面吹牛牡整,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溺拱,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼逃贝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了迫摔?” 一聲冷哼從身側(cè)響起沐扳,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎句占,沒想到半個(gè)月后沪摄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纱烘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年杨拐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擂啥。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哄陶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哺壶,到底是詐尸還是另有隱情屋吨,我是刑警寧澤蜒谤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站至扰,受9級(jí)特大地震影響鳍徽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渊胸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一旬盯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧翎猛,春花似錦胖翰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疫稿,卻和暖如春培他,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背遗座。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國打工舀凛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人途蒋。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓猛遍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親号坡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懊烤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容