Scrapy : Item Pipeline

Item Pipeline

在item 被爬虫抓取后,传递给 Item Pipline 。它通过几个组件按顺序执行来处理。

每个item pipline组件(有时就是称为item pipline)是一个执行单一方法的python 类。他们接受一个item 并对他执行函数,也决定是否这个item要继续通过管道或删除不在处理。

通常使用是为了:

  • 清理HTML 数据
  • 证明抓取的数据(检查items 包含某些字段)
  • 检查重复项,并删除他们
  • 将抓取的item 保存在数据库中。

Writing your own item pipeline

每个item pipline 组件是一个python类,必须包含以下方法。

  • process_item(self, item, spider)

这个方法被每个item pipline组件调用,process_item()必须:返回数据的字典,返回一个item(或子类)对象,返回 Deferred 或引发 DropItem 异常。删除的item不在被其他pipline组件处理。

Parameters

item (Item object or a dict) – the item scraped

spider (Spider object) – the spider which scraped the item

Additionally, they may also implement the following methods:

  • open_spider(self, spider)

这个方法在爬虫开始时调用

  • close_spider(self, spider)

爬虫结束时调用。

  • from_crawler(cls, crawler)

    如果存在,这个类方法从crawler 中创建一个Pipline的实例。必须返回一个新的pipline的实例。Crawler 对象提供了对所有scrapy 核心组件像设置和signals的访问,这是pipline访问他们并将其功能连接到Scrapy的一种方式.

    Parameters

    crawler (Crawler object) – 这个管道使用的crawler

Item pipeline example

Price validation and dropping items with no prices

看看下面这个假想的例子,调整price属性的那些不包括VAT并删除不含有price的。

from scrapy.exceptions import DropItem

class PricePipeline:

    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)

Write items to a JSON file

下面的pipline保存所有抓取的数据进一个items.js 文件,将item的每行序列化成JSON 格式

import json

class JsonWriterPipeline:

    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

Note

JSONWriterPipline的目的只是接受如何写item piplines。如果你真的想将所有item保存为json 文件,应该使用 Feed exports。

Write items to MongoDB

这个例子我们使用pymongo将item 写入MongoDB.mongodb地址和数据库名被指定在scrapy 设置里,在item 类后mongodb集合被命名。

这个例子主要时展示如何使用from_crawler()方法和怎样正确的清理资源。

import pymongo

class MongoPipeline:

    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

Take screenshot of item

这个例子展示了怎样从process_item()方法返回一个deferred。使用Splash来渲染item url的截屏。pipline向本地运行的Splash实例发送请求,在请求下载后,保存截屏到文件里并添加文件名进item里。

import scrapy
import hashlib
from urllib.parse import quote


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

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

    async 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)
        response = await spider.crawler.engine.download(request, spider)

        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                    # so,这有什么用。。。。

Duplicates filter

用来查找重复items 的过滤器,删除已经处理的items。假如我们的items 有唯一的id,但是我们爬虫返回多个有相同id 的items。

from scrapy.exceptions import DropItem

class DuplicatesPipeline:

    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

Activating an Item Pipeline component

激活组件就要在ITEM_PIPLINES设置里加上他的类

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

分配的整数值决定他们执行的顺序,从低开始。习惯定义在0-1000之间。

你可能感兴趣的:(爬虫)