Request对象
Request(url[, callback, method='GET', headers, body, cookies, meta,
encoding='utf-8', priority=0, dont_filter=False, errback])
Response对象用来描述一个HTTP响应,Response只是一个基类,根据响应内容的不同有如下子类:
● TextResponse
● HtmlResponse
● XmlResponse
下面介绍HtmlResponse对象的属性及方法。
● url
HTTP响应的url地址,str类型。
● status
HTTP响应的状态码,int类型,例如200,404。
● headers
HTTP响应的头头部,类字典类型,可以调用get或getlist方法对其进行访问,例如:
response.headers.get('Content-Type')
response.headers.getlist('Set-Cookie')
● body
HTTP响应正文,bytes类型。
● text
文本形式的 HTTP 响应正文,str 类型,它是由 response.body 使用response.encoding 解码得到的,即
reponse.text = response.body.decode(response.encoding)
● encoding
HTTP响应正文的编码,它的值可能是从HTTP响应头部或正文中解析出来的。
● request
产生该HTTP响应的Request对象。
● meta
即response.request.meta,在构造Request对象时,可将要传递给响应处理函数的信息通过meta参数传入;响应处理函数处理响应时,通过response.meta将信息取出。
● selector
Selector对象用于在Response中提取数据(选择器相关话题在后面章节详细讲解)。
● xpath(query)
使用XPath选择器在Response中提取数据,实际上它是response.selector.xpath方法的快捷方式(选择器相关话题在后面章节详细讲解)。
● css(query)
使用CSS选择器在Response中提取数据,实际上它是response.selector.css方法的快捷方式(选择器相关话题在后面章节详细讲解)。
● urljoin(url)
用于构造绝对url。当传入的url参数是一个相对地址时,根据response.url计算出相应的绝对url。例如,response.url为http://www.example.com/a,url为b/index.html,调用response.urljoin(url)的结果为http://www.example.com/a/b/index.html。
虽然 HtmlResponse 对象有很多属性,但最常用的是以下的3个方法:
● xpath(query)
● css(query)
● urljoin(url)
前两个方法用于提取数据,后一个方法用于构造绝对 url 。
提取数据
调用 Selector 或 SelectorLis 对象的以下方法可将选中的内容提取:
● extract()
● re()
● extract_first() ( SelectorList 专有)
● re_first() ( SelectorList 专有)
Item 和 Field
● Item基类
自定义数据类(如BookItem)的基类。
● Field类
用来描述自定义数据类包含哪些字段(如 name、price 等)。
Item 支持字典接口,因此 BookItem 在使用上和Python字典类似,可按以下方式创建 BookItem 对象:
>>> from scrapy import Item, Field
>>>> class BookItem(Item):
... name = Field()
... price = Field()
>>> book1 = BookItem(name='Needful Things', price=45.0)
>>> book1
{'name': 'Needful Things', 'price': 45.0}
>>> book2 = BookItem()
>>> book2
{}
>>> book2['name'] = 'Life of Pi'
>>> book2['price'] = 32.5
{'name': 'Life of Pi', 'price': 32.5}
扩展 item
>>> class ForeignBookItem(BookItem):
... translator = Field()
...
>>> book = ForeignBookItem()
>>> book['name'] = '巴黎圣母院'
>>> book['price'] = 20.0
>>> book['translator'] = '陈敬容
Field 元数据
class ExampleItem(Item):
x = Field(a='hello', b=[1, 2, 3]) # x 有两个元数据,a是个字符串,b是个列表
y = Field(a=lambda x: x ** 2) # y 有一个元数据,a是个函数
可以通过 authors 字段的元数据告诉 CsvItemExporter 如何对 authors 字段串行化:
class BookItem(Item):
...
authors = Field(serializer=lambda x: '|'.join(x))
...
元数据的键 serializer 是 CsvItemExporter 规定好的,它会用该键获取元数据,即一个串行化函数对象,并使用这个串行化函数将 authors 字段串行化成一个字符串。
使用 Item Pipeline 处理数据
Pipeline 不需要继承特定基类,只需要实现某些特定方法,例如process_item、open_spider、close_spider。
一个 Item Pipeline 必须实现一个 process_item(item,spider) 方法,该方法用来处理每一项由Spider爬取到的数据,其中的两个参数:
- Item 爬取到的一项数据( Item 或字典)。
- Spider 爬取此项数据的 Spider 对象。
● 如果process_item在处理某项item时返回了一项数据(Item或字典),返回的数据会递送给下一级Item Pipeline(如果有)继续处理。
● 如果 process_item 在处理某项item时抛出(raise)一个 DropItem 异常(scrapy.exceptions.DropItem),该项 item 便会被抛弃,不再递送给后面的 Item Pipeline 继续处理,也不会导出到文件。通常,我们在检测到无效数据或想要过滤数据时,抛出 DropItem 异常。
除了必须实现的process_item方法外,还有3个比较常用的方法,可根据需求选择实现:
● open_spider(self, spider)
Spider 打开时(处理数据前)回调该方法,通常该方法用于在开始处理数据之前完成某些初始化工作,如连接数据库。
● close_spider(self, spider)
Spider 关闭时(处理数据后)回调该方法,通常该方法用于在处理完所有数据之后完成某些清理工作,如关闭数据库。
● from_crawler(cls, crawler)
创建 Item Pipeline 对象时回调该类方法。通常,在该方法中通过 crawler.settings 读取配置,根据配置创建 Item Pipeline 对象。
创建好 Item Pipeline 后,在 settings.py 中开启。
过滤重复数据例子
from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
self.book_set = set()
def process_item(self, item, spider):
name = item['name']
if name in self.book_set:
raise DropItem("Duplicate book found: %s" % item)
self.book_set.add(name)
return item
写入 MongoDB 的例子
from scrapy.item import Item
import pymongo
class MongoDBPipeline(object):
@classmethod
def from_crawler(cls, crawler):
# 有默认值
cls.DB_URI = crawler.settings.get('MONGO_DB_URI',
'mongodb://localhost:27017/')
cls.DB_NAME = crawler.settings.get('MONGO_DB_NAME', 'scrapy_data')
return cls()
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.DB_URI)
self.db = self.client[self.DB_NAME]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
collection = self.db[spider.name]
post = dict(item) if isinstance(item, Item) else item
collection.insert_one(post)
return item
● 增加类方法 from_crawler(cls, crawler),替代在类属性中定义 DB_URI 和 DB_NAME。
● 如果一个 Item Pipeline 定义了 from_crawler 方法,Scrapy 就会调用该方法来创建Item Pipeline对象。该方法有两个参数:
cls Item Pipeline 类的对象(这里为 MongoDBPipeline 类对象)。
crawler Crawler 是 Scrapy 中的一个核心对象,可以通过 crawler 的 settings 属性访问配置文件。
● 在 from_crawler 方法中,读取配置文件中的 MONGO_DB_URI 和 MONGO_DB_NAME (不存在使用默认值),赋给 cls 的属性,即 MongoDBPipeline 类属性。
● 其他代码并没有任何改变,因为这里只是改变了设置 MongoDBPipeline 类属性的方式。
settings.py
MONGO_DB_URI = 'mongodb://192.168.1.105:27017/'
MONGO_DB_NAME = 'liushuo_scrapy_data'
使用Exporter导出数据
在 Scrapy 中,负责导出数据的组件被称为 Exporter(导出器),Scrapy 内部实现了多个 Exporter ,每个 Exporter 实现一种数据格式的导出,支持的数据格式如下(括号中为相应的 Exporter ):
(1)JSON (JsonItemExporter)
(2)JSON lines (JsonLinesItemExporter)
(3)CSV (CsvItemExporter)
(4)XML (XmlItemExporter)
(5)Pickle (PickleItemExporter)
(6)Marshal (MarshalItemExporter)
其中,前4种是极为常用的文本数据格式,而后两种是 Python 特有的。在大多数情况下,使用 Scrapy 内部提供的 Exporter 就足够了,需要以其他数据格式(上述6种以外)导出数据时,可以自行实现 Exporter 。
● FEED_URI
导出文件路径。
FEED_URI = 'export_data/%(name)s.data'
● FEED_FORMAT
导出数据格式。
FEED_FORMAT = 'csv'
● FEED_EXPORT_ENCODING
导出文件编码(默认情况下json文件使用数字编码,其他使用utf-8编码)。
FEED_EXPORT_ENCODING = 'gbk'
● FEED_EXPORT_FIELDS
导出数据包含的字段(默认情况下导出所有字段),并指定次序。
FEED_EXPORT_FIELDS = ['name', 'author', 'price']
● FEED_EXPORTERS
用户自定义 Exporter 字典,添加新的导出数据格式时使用。
FEED_EXPORTERS = {'excel': 'my_project.my_exporters.ExcelItemExporter'}
FilesPipeline 和 ImagesPipeline3
FilesPipeline 的使用
<html>
<body>
...
<a href='/book/sg.pdf'>下载《三国演义》</a>
<a href='/book/shz.pdf'>下载《水浒传》</a>
<a href='/book/hlm.pdf'>下载《红楼梦》</a>
<a href='/book/xyj.pdf'>下载《西游记》</a>
...
</body>
</html>
步骤01 在配置文件 settings.py 中启用 FilesPipeline ,通常将其置于其他 Item Pipeline 之前:
ITEM_PIPELINES = {'scrapy.pipelines.files.FilesPipeline': 1}
步骤02 在配置文件 settings.py 中,使用 FILES_STORE 指定文件下载目录,如:
FILES_STORE = '/home/liushuo/Download/scrapy'
步骤03 在 Spider 解析一个包含文件下载链接的页面时,将所有需要下载文件的 url 地址收集到一个列表,赋给 item 的 file_urls 字段(item[‘file_urls’])。
class ExampleItem(scrapy.Item):
file_urls = scrapy.Field()
files = scrapy.Field()
FilesPipeline 在处理每一项 item 时,会读取 item[‘file_urls’] ,对其中每一个 url 进行下载,Spider 示例代码如下:
class DownloadBookSpider(scrapy.Spider):
...
def parse(response):
item = {}
# 下载列表
item['file_urls'] = []
for url in response.xpath('//a/@href').extract():
download_url = response.urljoin(url)
# 将url 填入下载列表
item['file_urls'].append(download_url)
yield item
当 FilesPipeline 下载完 item[‘file_urls’] 中的所有文件后,会将各文件的下载结果信息收集到另一个列表,赋给 item 的 files 字段 (item[‘files’])。下载结果信息包括以下内容:
● Path 文件下载到本地的路径(相对于 FILES_STORE 的相对路径)。
● Checksum 文件的校验和。
● url 文件的 url 地址。
ImagesPipeline 的使用说明
ImagesPipeline 在 FilesPipleline 的基础上针对图片增加了一些特有的功能:
● 为图片生成缩略图
开启该功能,只需在配置文件 settings.py 中设置IMAGES_THUMBS,它是一个字典,每一项的值是缩略图的尺寸,代码如下:
IMAGES_THUMBS = {
'small': (50, 50),
'big': (270, 270),
}
开启该功能后,下载一张图片时,本地会出现3张图片(1张原图片,2张缩略图),路径如下:
[IMAGES_STORE]/full/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
[IMAGES_STORE]/thumbs/small/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
[IMAGES_STORE]/thumbs/big/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
● 过滤掉尺寸过小的图片
开启该功能,需在配置文件 settings.py 中设置IMAGES_MIN_WIDTH 和 IMAGES_MIN_HEIGHT ,它们分别指定图片最小的宽和高,代码如下:
IMAGES_MIN_WIDTH = 110
IMAGES_MIN_HEIGHT = 110
开启该功能后,如果下载了一张105×200的图片,该图片就会被抛弃掉,因为它的宽度不符合标准。