scrapy框架之Pipeline管道类

Item Pipeline简介

Item管道的主要责任是负责处理有蜘蛛从网页中抽取的Item,他的主要任务是清洗、验证和存储数据。
当页面被蜘蛛解析后,将被发送到Item管道,并经过几个特定的次序处理数据。
每个Item管道的组件都是有一个简单的方法组成的Python类。
他们获取了Item并执行他们的方法,同时他们还需要确定的是是否需要在Item管道中继续执行下一步或是直接丢弃掉不处理。

项目管道的执行过程

清理HTML数据
验证解析到的数据(检查Item是否包含必要的字段)
检查是否是重复数据(如果重复就删除)
将解析到的数据存储到数据库中

编写自己的Item Pipeline

每个项目管道组件是一个Python类,必须实现以下方法:

process_item(self, item, spider)

对于每个项目管道组件调用此方法。process_item() 必须返回一个带数据的dict,返回一个Item (或任何后代类)对象,返回一个Twisted Deferred或者raise DropItemexception。丢弃的项目不再由其他管道组件处理。

参数:

  • item(Itemobject或dict) - 剪切的项目
  • Spider(Spider对象) - 抓取物品的蜘蛛

另外,它们还可以实现以下方法:

# 当蜘蛛打开时调用此方法。
open_spider(self, spider)   # 参数spider打开的蜘蛛

# 当蜘蛛关闭时调用此方法。
close_spider(self, spider)   # 参数spider被关闭的蜘蛛

# 如果存在,则调用此类方法以从a创建流水线实例Crawler。它必须返回管道的新实例。Crawler对象提供对所有Scrapy核心组件(如设置和信号)的访问; 它是管道访问它们并将其功能挂钩到Scrapy中的一种方式。 
from_crawler(cls, crawler)  # 参数crawler(Crawlerobject) - 使用此管道的crawler

将抓取的items以json格式保存到文件中

从spider抓取到的items将被序列化为json格式,并且以每行一个item的形式被写入到items.jl文件中

import json 
  
class JsonWriterPipeline(object): 
  
  def __init__(self): 
    self.file = open('items.jl', 'wb') 
  
  def process_item(self, item, spider): 
    line = json.dumps(dict(item)) + "\n"
    self.file.write(line) 
    return item

删除重复项

假设在spider中提取到的item有重复的id,那么我们就可以在process_item函数中进行过滤

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

激活ItemPipeline组件

在settings.py文件中,往ITEM_PIPELINES中添加项目管道的类名,就可以激活项目管道组件

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

图像管道

items

定义过滤字段

import scrapy

class ImgpilelineproItem(scrapy.Item):
    # define the fields for your item here like:
    img_src = scrapy.Field()

spider

只是用来获取图片的下载地址并提交至itme

import scrapy
from imgPileLinePro.items import ImgpilelineproItem

class ImgSpider(scrapy.Spider):
    name = 'img'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://pic.netbian.com/4kmeinv/']
    url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
    page = 2

    def parse(self, response):
        li_list = response.xpath('//*[@id="main"]/div[3]/ul/li')
        for li in li_list:
            img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src').extract_first()
            item = ImgpilelineproItem()
            item['img_src'] = img_src

            yield item

        if self.page <= 2:  # 爬取前两页
            new_url = format(self.url%self.page)
            self.page += 1
            yield scrapy.Request(url=new_url,callback=self.parse)

pipelines

from scrapy.pipelines.images import ImagesPipeline
import scrapy

# 用来下载图片的管道类
class ImgPileLine(ImagesPipeline):
    #接收item且将item中存储的img_src进行请求发送
    def get_media_requests(self,item,info):
        yield scrapy.Request(url=item['img_src'])

    #指定数据存储的路径(文件夹【在配置文件中指定】+图片名称【该方法中返回】)
    def file_path(self,request,response=None,info=None):
        img_name = request.url.split('/')[-1]
        return img_name

    #就是将item传递给下一个即将被执行的管道类
    def item_completed(self,result,item,info):
        return item

settings中的配置

# 指定文件的下载路径
IMAGES_STORE = './imgsLib'   # 该文件会自动创建
# 启用管道
ITEM_PIPELINES = {
   'imgPileLinePro.pipelines.ImgPileLine': 300,
}

将item写入到mongodb

import pymongo

class MongoPipeline(object):

    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')
        )
    # 爬虫开始建立与mongodb的连接
    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]
    # 爬虫结束断开与mongodb的连接
    def close_spider(self, spider):
        self.client.close()
    # 数据存储
    def process_item(self, item, spider):
        # update 去重,以url_token为查找条件更新数据
        self.db["user"].update({"url_token":item["url_token"]},{"$set":item},True)
        return item
MONGO_URI = "localhost"
MONGO_DATABASE = "zhihu"

 

posted @ 2019-08-25 14:57  叫我大表哥  阅读(4631)  评论(0编辑  收藏  举报