爬虫(十六):Scrapy框架(三) Spider Middleware、Item Pipeline
1. Spider Middleware
Spider Middleware是介入到Scrapy的Spider处理机制的钩子框架。
当Downloader生成Response之后,Response会被发送给Spider,在发送给Spider之前,Response会首先经过Spider Middleware处理,当Spider处理生成Item和Request之后,Item Request还会经过Spider Middleware的处理。
Spider Middleware有三个作用:
- 我们可以在Downloader生成的Response发送给Spider之前,也就是在Response发送给Spider之前对Response进行处理。
- 我们可以在Spider生成的Request发送给Scheduler之前,也就是在Request发送给Scheduler之前对Request进行处理。
- 我们可以在Spider生成的Item发送给Item Pipeline之前,也就是在Item发送给Item Pipeline之前对Item进行处理。
1.1 使用说明
需要说明的是,Scrapy其实已经提供了许多Spider Middleware,它们被SPIDER_MIDDLEWARES_BASE这个变盘所定义。
SPIDER_MIDDLEWARES_BASE变量的内容如下:
{
'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware':50,
'scrapy spidermiddlewares offsite Of site iddleware':500,
'scrapy.spidermiddlewares.referer.RefererMiddleware':700,
'scrapy.spidermiddlewares.urllength.UrllengthMiddleware':800,
'scrapy.spidermiddlewares.depth.DepthMiddleware':900,
}
和Downloader Middleware一样,Spider Middleware首先加入到SPIDER_MIDDLEWARES设置中,该设置会和Scrapy中SPIDER_MIDDLEWARES_BASE定义的Spider Middleware合并。然后根据键值的数字优先级排序,得到一个有序列表。第一Middleware是最靠近引擎的,最后一个Middleware是最靠近Spide的。
1.2 核心方法
Scrapy内置的Spider Middleware为Scrapy提供了基础的功能。如果我们想要扩展其功能,只需要实现某几个方法即可。
每个Spider Middleware都定义了以下一个或多个方法的类,核心方法有如下4个。
- process_spider_input(response,spider)
- process_spider_output(response,result,spider)
- process_spider_exception(response,exception,spider)
- proce ss_start_requests(start_requests,spider)
只需要实现其中一个方法就可以定义一个Spider Middleware。
(1) process_spider_input(response,spider)
当Response被Spider Middleware处理时,process_spider_input()方法被调用。
process_spider_input()方法的参数有如下两个:
response,是Response对象,即被处理的Response。
spider,是Spider对象,即该Response对应的Spider。
process_spider_input()应该返回None或者抛出一个异常。
如果它返回None,Scrapy将会继续处理该Response,调用所有其他的Spider Middleware,直到Spider处理该Response。
如果它抛出一个异常,Scrapy将不会调用任何其他Spider Middleware的process_spider_input()方法,而调用Request的errback()方法。errback的输出将会被重新输入到中间件中,使用process_spider_output()方法来处理,当其抛出异常时则调用process_spider_exception()来处理。
(2) process _spider_output(response,result,spider)
当Spider处理Response返回结果时,process_spider_output()方法被调用。process_spider_output()方法的参数有如下三个:
response,是Response对象,即生成该输出的Response。
result,包含Request或Item对象的可迭代对象,即Spider返回的结果。
spider,是Spider对象,即其结果对应的Spider。
process_spider_output()必须返回包含Request或Item对象的可迭代对象。
(3) process_spider_exception(response,exception,spider)
当Spider或Spider Middleware的process_spider_input()方法抛出异常时,process_spider_exception()方法被调用。
process_spider_exception()方法的参数有如下三个:
response,是Response对象,即异常被抛出时被处理的Response。
exception,是Exception对象,即被抛出的异常。
spider,是Spider对象,即抛出该异常的Spider。
process_spider_exception()必须要么返回None,要么返回一个包含Response或Item对象的可迭代对象。
如果它返问None,Scrapy将继续处理该异常,调用其他Spider Middleware中的process_spider_exception()方法,直到所有Spider Middleware都被调用。
如果它返回一个可迭代对象,Spider Middleware的process_spider_output()方法被调用,其他的process_spider_exception()不会被调用。
(4) process_start_requests (start_requests,spider)
process_start_requests()方法以Spider启动的Request为参数被调用,执行的过程类似于process_spider_output(),只不过它没有相关联的Response并且必须返回Request。
proces s_start_requests()方法的参数有如下两个:
start_requests,是包含Request的可迭代对象,即Start Requests。
spider,是Spider对象,即Start Requests所属的Spider。
process_start_requests()必须返回另一个包含Request对象的可迭代对象。
2. Item Pipeline
Item Pipeline是项目管道。
Item Pipeline的调用发生在Spider产生Item之后。当Spider解析完Response之后,Item就会传递到Item Pipeline,被定义的Item Pipeline组件会依次调用,完成一连串的处理过程,比如数据清洗、存储等。
Item Pipeline主要功能有四点:
清理HTML数据。
验证爬取数据,检查爬取字段。
查重并丢弃重复内容。
将爬取结果保存到数据库。
我们可以自定义Item Pipeline,只需要实现指定的方法,其中必须要实现的一个方法是: process_item(item,spider)。
另外还有如下几个比较实用的方法:
open_spider(spider)
close_spider(spider)
from_crawler(cls,crawler)
2.1 常用方法
(1) process_item(item,spider)
process_item()是必须要实现的方法,被定义的Item Pipeline会默认调用这个方法对Item进行处理。比如,我们可以进行数据处理或者将数据写入到数据库等操作。它必须返回Item类型的值或者抛出一个DropItem异常。
process_itern()方法的参数有两个:
item,是Item对象,即被处理的Item。
Spider,是Spider对象,即生成该Item Spider。
process_item()方法的返回类型归纳如下:
如果它返回的是Item对象,那么此Item会被低优先级的Item Pipeline的process_item()方法处理,直到所有的方法被调用完毕。
如果它抛出的是DropItem异常,那么此Item会被丢弃,不再进行处理。
(2) open_spider(self,spider)
open_spider()方法是在Spider开启的时候被自动调用的。在这里我们可以做一些初始化操作,如开启数据库连接等。其中,参数spider就是被开启的Spider对象。
(3) close_spider(spider)
close_spider()方法是在Spider关闭的时候自动调用的。在这里我们可以做一些收尾工作,如 关闭数据库连接等。其中,参数spider就是被关闭的Spider对象。
(4) from_crawler(cls,crawler)
from_crawler()方法是一个类方法,用@classmethod标识,是一种依赖注入的方式。它的参数是crawler,通过crawler对象,我们可以拿到Scrapy的所有核心组件,如全局配置的每个信息,然后创建Pipeline实例。参数cls就是Class,最后返回一个Class实例。
2.2 管道示例
(1) 价格验证和删除没有价格的商品
调整price那些不包含增值税(price_excludes_vat属性)的项目的属性,并删除那些不包含价格的项目:
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) 将项目写入JSON文件
将所有已删除的项目存储到一个items.json文件中,每一行包含一个以JSON格式序列化的项目:
import json
class JsonWriterPipeline(object):
def open_spider(self, spider):
self.file = open('items.json', '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) 将项目写入MongoDB
在这个例子中,我们将使用pymongo将项目写入MongoDB。MongoDB地址和数据库名称在Scrapy设置中指定;MongoDB集合以item类命名。
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) 截取项目的截图
从process_item()方法返回Deferred。它使用Splash渲染项目URL的屏幕截图。Pipeline向本地运行的Splash示例发出请求。下载请求并延迟回调激活后,它会将项目保存到文件并将文件名添加到项目中。
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) 重复过滤
一个过滤器,用于查找重复项目,并删除已处理的项目。假设我们的项目具有唯一ID,但我们的spider会返回具有相同ID的多个项目:
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 ite
爬虫(十六):Scrapy框架(三) Spider Middleware、Item Pipeline的更多相关文章
- python爬虫入门(六) Scrapy框架之原理介绍
Scrapy框架 Scrapy简介 Scrapy是用纯Python实现一个为了爬取网站数据.提取结构性数据而编写的应用框架,用途非常广泛. 框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬 ...
- 第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码
第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码 打码接口文件 # -*- coding: cp936 -*- import sys import os ...
- 第三百三十四节,web爬虫讲解2—Scrapy框架爬虫—Scrapy爬取百度新闻,爬取Ajax动态生成的信息
第三百三十四节,web爬虫讲解2—Scrapy框架爬虫—Scrapy爬取百度新闻,爬取Ajax动态生成的信息 crapy爬取百度新闻,爬取Ajax动态生成的信息,抓取百度新闻首页的新闻rul地址 有多 ...
- 第三百三十三节,web爬虫讲解2—Scrapy框架爬虫—Scrapy模拟浏览器登录—获取Scrapy框架Cookies
第三百三十三节,web爬虫讲解2—Scrapy框架爬虫—Scrapy模拟浏览器登录 模拟浏览器登录 start_requests()方法,可以返回一个请求给爬虫的起始网站,这个返回的请求相当于star ...
- 第三百三十二节,web爬虫讲解2—Scrapy框架爬虫—Scrapy使用
第三百三十二节,web爬虫讲解2—Scrapy框架爬虫—Scrapy使用 xpath表达式 //x 表示向下查找n层指定标签,如://div 表示查找所有div标签 /x 表示向下查找一层指定的标签 ...
- 第三百三十一节,web爬虫讲解2—Scrapy框架爬虫—Scrapy安装—Scrapy指令
第三百三十一节,web爬虫讲解2—Scrapy框架爬虫—Scrapy安装—Scrapy指令 Scrapy框架安装 1.首先,终端执行命令升级pip: python -m pip install --u ...
- scrapy框架中Download Middleware用法
scrapy框架中Download Middleware用法 Downloader Middleware处理的过程主要在调度器发送requests请求的时候以及网页将response结果返回给sp ...
- Python爬虫进阶之Scrapy框架安装配置
Python爬虫进阶之Scrapy框架安装配置 初级的爬虫我们利用urllib和urllib2库以及正则表达式就可以完成了,不过还有更加强大的工具,爬虫框架Scrapy,这安装过程也是煞费苦心哪,在此 ...
- scrapy框架(三)
scrapy框架(三) CrawlSpider类 创建CrawlSpider # 创建项目后 $ scrapy genspider -t crawl spider_name website_doma ...
随机推荐
- Java基础知识笔记第一章:入门
java的地位: java具有面向对象,与平台无关,安全,稳定和多线程等优良特性,是目前软件设计中优秀的编程语言. java的特点: 1.简单 2.面向对象 3.平台无关 jre(java runti ...
- Linux 修改/etc/profile 出错 导致所有命令都 command not found 的解决办法
执行命令 export PATH=/usr/bin:/usr/sbin:/bin:/sbin:/usr/X11R6/bin 然后再修改/etc/profile 再执行文件: source /etc/p ...
- 58按之字形顺序打印二叉树 +队列访问使用front和back,栈才是top
题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. 思路:最暴力的方法就是使用队列进行层次遍 ...
- 1 (msql实战) 基础架构
mysql> select * from T where ID=10: 我们看到的只是输入一条语句,返回一个结果,却不知道这条语句在 MySQL 内部的执行过程. 所以今天我想和你一起把 MyS ...
- [多校联考]SLON!!!
题目描述 $SLON$是一个调皮的学生,为了让他静下心来,老师给他出了一道数学题:给定表达式$A$,$A$中含有变量$x$和$+,-,*,(,)$这些符号,括号成对出现,一个算术运算符均对应两个操作数 ...
- Scrapy 常用的shell执行命令
1.在任意系统下,可以使用 pip 安装 Scrapy pip install scrapy/ 确认安装成功 >>> import scrapy >>> scrap ...
- django-文件上传Media url的配置
一:问题 当开启一个项目的时候,通常会遇到文件(图片,音频等)上传的需要,最常见的比如图片的上传,用户头像,后台管理添加图片,而图片的在是数据库中的存储主要是以该文件的相对路径,在django中可以使 ...
- 五 RequestMapping的使用
1 设置路径映射为数组,在Controller类中一个方法对应多个映射路径,可以被多个url访问 2 分目录管理,在Controller类上添加Request Mapping注解,url访问必须添加相 ...
- 解决请求中的post、get乱码问题以及响应的乱码问题
post: get: response:
- JuJu Beta Postmortem
JuJu demo demo 项目github地址 JuJu 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 完成基于Julia语言的NER mod ...