Code前端首页关于Code前端联系我们

Scrapy pipeline 管道:清理、验证和存储数据

terry 2年前 (2023-09-24) 阅读数 54 #后端开发

在了解 Item Pipeline 之前,我们先看一下下图。 Scrapy管道piplines:清洗、验证和存储数据您可以看到项目管道位于上图的最左侧。 Item pipeline的主要任务是处理Spider从网页检索到的item。因此,Item Pipeline的主要任务是清理、验证和存储数据。一旦页面被Spider解析,它将被发送到Item管道。 Item Pipeline 检索 Items 中的数据并执行相应的方法,决定是继续进行 item pipeline 中的下一步还是丢弃而不进行处理。

所以对于Item Pipline来说,主要功能包括以下几个:

清理HTML数据。
验证扫描数据并检查扫描字段。
检查并丢弃重复的内容。
将抓取结果保存到数据库中。

核心方法介绍

项目管道主要有4个方法,分别是:

1)open_spider(spider)
2)close_spider(spider))_搜索程序,)4 ) process_item(item,spider)

open_spider (spider) 【参数spider为打开的spider对象】

spider时触发,常用于初始化,包括:打开数据库连接、打开文件等)。该方法不需要实现,可以根据需求定义。

close_spider (spider) 【参数spider为关闭的spider对象】

在spider关闭时自动调用。这里我们可以做一些后期工作,比如关闭数据库连接等。这个方法是非常必需的,可以根据需求定义实现。

from_crawler(cls,crawler) 【参数1:类参数2:爬虫对象】

该方法在Spider激活时调用,早于open_spider()方法,是类方法。用@classmethod标记,是一个依赖注入的方法。参数为crawler。通过crawler对象,我们可以获取Scrapy的所有核心组件,比如全局配置的各个信息,然后创建一个Pipeline实例。参数cls为Class,最终返回一个Class实例。默认为 2 此方法处理 Item。例如,我们可以进行数据处理或者将数据写入数据库。它必须返回 Item 类型的值或抛出 DropItem 异常。

如果返回一个item对象,则该item将由低优先级item管道的process_item()方法处理,直到调用所有方法。
如果抛出 DropItem 异常,该项目将被丢弃并且不再被处理。

扩展:ImagesPipline

爬虫程序通常不仅会爬取文本资源,还会爬取图像资源。这就涉及到如何高效下载图片的问题。这里的高效下载是指可以将图片下载到本地电脑,而不会对网站服务器造成任何压力。此时,您不需要自己实现管道中的图像下载逻辑。您可以使用Scrapy提供的图像管道ImagesPipeline,可以更高效地下载图像。

ImagesPipeline具有以下功能:

将所有下载的图像转换为通用格式(JPG)和模式(RGB)
避免重新下载最近下载的图像检测图像宽度/高度并确保它们满足最小约束

使用说明:

可以在pipline.py中定义一个新的类,如:xxImagePipline,是Scrapy生成的类,默认继承Object。对该类进行修改,继承ImagesPipeline。然后,两个函数 eGet_Media_requests

Item_completed 实现 Get_media_requests 为每个函数生成请求。和 item_completed(self, results, item, info)当单个项目中的所有图像请求完成时调用此方法。

处理结果会以元组的形式返回给函数item_completed(),即参数:结果。

result参数的结果为:(success, image_info_or_failure) 其中success表示图片是否已经下载; image_info_or_failure 是一个包含三个属性的字典:

1.url - 图像下载的 url。这是从 get_media_requests() 方法返回的请求 URL。
2.path - 图片存储路径(类似IMAGES_STORE)
3.checksum - 图片内容的MD5哈希值

如果需要erequest_path =None)

请求代表当前下载对应的request对象(request.dict视图属性),该方法用于返回文件名

response返回None

info,同样返回一个对象(info.dict视图)

处同时设置必须结合settings.py的配置,比如设置和配置图片保存路径、自定义下载图片管道等。

# 可以避免下载最近已经下载的图片,90天的图片失效期限
IMAGES_EXPIRES = 90  
IMAGES_STORE = '设置存放图片的路径'

# 如果需要也可以设置缩略图
# IMAGES_THUMBS = {
#   'small': (50, 50),   # (宽, 高)
#   'big': (270, 270),
# }

# 配置自定义下载的图片管道, 默认是被注释的
ITEM_PIPELINES = {
  # yourproject.middlewares(文件名).middleware类
  '项目名.pipelines.xxImagePipeline': 数值,  
}

而Scrapy框架会用到这个Python Imaging Library (PIL)图像库,所以这个库也必须事先安装。

pip安装垫

案例

我们这次浏览的网站是一个有很多治愈系图片的网站,更重要的是,它是免费的。链接是:http://www.designerspics.comScrapy管道piplines:清洗、验证和存储数据我们想要实现的是将图片的名称和下载地址存储在MongoDB中,并将图片下载到本地。由于我们之前没有使用过 MongoDB 或 Redis 等非关系型数据库进行存储,因此本例中我们将使用 MongoDB 存储。

首先使用以下命令创建一个新项目:

scrapy startproject designerspics

然后使用以下命令创建一个新的spider:

scrapy genspider designer www.designerspics.com

这样我们就创建了一个spider。

然后使用PyCharm打开爬虫项目,开始编写爬虫。Scrapy管道piplines:清洗、验证和存储数据所以我们的爬虫代码是(当然现在只爬第一页,如果爬多个页面就需要重写start_requests(self)方法):

import scrapy
from designerspics.items import DesignerspicsItem

class DesignerSpider(scrapy.Spider):
   name = 'designer'
   allowed_domains = ['www.designerspics.com']
   start_urls = ['http://www.designerspics.com/']

   def parse(self, response):
       title = response.xpath('//div[@class="photograph-wrapper"]/div/h5[1]/text()').extract()
       image_url = response.xpath('//div[@class="photograph-wrapper"]/div/div/a/img/@src').extract()
       for index, t in enumerate(title):
           item = DesignerspicsItem()
           item['title'] = t[2:]
           item['image_url'] = image_url[index]
           yield item

如果爬多个页面可以这样写像这样,因为除了第一页之外,每个页面的地址都是这样的

第一页:http://www.designerspics.com/
第二页:http://www.designerspics。 com/page/2 /
第三页:http://www.designerspics.com/page/3/
...

import scrapy
from scrapy import Request
from designerspics.items import DesignerspicsItem

class DesignerSpider(scrapy.Spider):
   name = 'designer'
   allowed_domains = ['www.designerspics.com']

   # start_urls = ['http://www.designerspics.com/']

   def start_requests(self):
       # 爬取10页内容
       for i in range(1, 11):
           if i == 1:
               url = "http://www.designerspics.com/"
               yield Request(url, self.parse)
           else:
               url = 'http://www.designerspics.com/page/' + str(i)+"/"
               yield Request(url, self.parse)

   def parse(self, response):
       title = response.xpath('//div[@class="photograph-wrapper"]/div/h5[1]/text()').extract()
       image_url = response.xpath('//div[@class="photograph-wrapper"]/div/div/a/img/@src').extract()
       for index, t in enumerate(title):
           item = DesignerspicsItem()
           item['title'] = t[2:]
           item['image_url'] = image_url[index]
           yield item

DesignerspicsItem类的代码如下:

import scrapy


class DesignerspicsItem(scrapy.Item):
   # define the fields for your item here like:
   # name = scrapy.Field()
   collection = 'designerimages'
   title = scrapy.Field()
   image_url = scrapy.Field()

在至此,开始定义Element Pipline,打开piplines .py文件

import pymongo
from scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline


class DesignerspicsPipeline:
   def __init__(self, mongo_uri, mongo_db, mongo_port):
       self.mongo_uri = mongo_uri
       self.mongo_db = mongo_db
       self.mongo_port = mongo_port

   @classmethod
   def from_crawler(cls, crawler):
       return cls(mongo_uri=crawler.settings.get('MONGO_URI'),
                  mongo_db=crawler.settings.get('MONGO_DB'),
                  mongo_port=crawler.settings.get('MONGO_PORT')
                  )

   def open_spider(self, spider):
       self.client = pymongo.MongoClient(host=self.mongo_uri, port=self.mongo_port)
       self.db = self.client[self.mongo_db]

   def process_item(self, item, spider):
       self.db[item.collection].insert(dict(item))
       return item

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


class ImagePipeline(ImagesPipeline):
   def file_path(self, request, response=None, info=None):
       url = request.url
       file_name = url.split('/')[-1]
       return file_name

   def item_completed(self, results, item, info):
       image_paths = [x['path'] for ok, x in results if ok]
       if not image_paths:
           raise DropItem('Image Downloaded Failed')
       return item

   def get_media_requests(self, item, info):
       yield Request(item['image_url'])

此时需要在settings.py中进行配置:

MONGO_URI = '127.0.0.1'
MONGO_DB = 'designerimages'
MONGO_PORT = 27017

# 需要设置存储图片的路径
IMAGES_STORE = './images'

启动爬虫:

scrapy crawl designer

我们来看看结果吧! Scrapy管道piplines:清洗、验证和存储数据显示Mongo数据库的数据:Scrapy管道piplines:清洗、验证和存储数据

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门