在item 被爬虫抓取后,传递给 Item Pipline 。它通过几个组件按顺序执行来处理。
每个item pipline组件(有时就是称为item pipline)是一个执行单一方法的python 类。他们接受一个item 并对他执行函数,也决定是否这个item要继续通过管道或删除不在处理。
通常使用是为了:
每个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
看看下面这个假想的例子,调整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)
下面的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。
这个例子我们使用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
这个例子展示了怎样从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,这有什么用。。。。
用来查找重复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
激活组件就要在ITEM_PIPLINES设置里加上他的类
ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}
分配的整数值决定他们执行的顺序,从低开始。习惯定义在0-1000之间。