熟悉Django的人会注意到 Scrapy Items 的声明类似于Django Models,只是 Scrapy Items 更简单,因为没有不同字段类型的概念。
Item 提供了类似dict 的 API 以及其他功能,使其成为功能最完整的项目类型:
一、使用 Item 对象
声明项目子类
项目子类使用简单的类定义语法和 Field 对象来声明。这是一个例子:
import scrapy
class Product(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field()
stock = scrapy.Field()
tags = scrapy.Field()
last_updated = scrapy.Field(serializer=str)
创建项目
>>> product = Product(name='Desktop PC', price=1000)
>>> print(product)
{'name': 'Desktop PC', 'price': 1000}
获取字段值
>>> product['name']
Desktop PC
>>> product.get('name')
Desktop PC
>>> product['price']
1000
>>> product['last_updated']
Traceback (most recent call last):
...
KeyError: 'last_updated'
>>> product.get('last_updated', 'not set')
not set
>>> product['lala']
Traceback (most recent call last):
...
KeyError: 'lala'
>>> product.get('lala', 'unknown field')
'unknown field'
>>> 'name' in product
True
>>> 'last_updated' in product
False
>>> 'last_updated' in product.fields
True
>>> 'lala' in product.fields
False
设置字段值
>>> product['last_updated'] = 'today'
>>> product['last_updated']
today
>>> product['lala'] = 'test'
Traceback (most recent call last):
...
KeyError: 'Product does not support field: lala'
访问所有填充的值
要访问所有填充的值,只需使用典型的dict API:
>>> product.keys()
['price', 'name']
>>> product.items()
[('price', 1000), ('name', 'Desktop PC')]
复制项目
要创建项目的浅表副本,您可以调用 copy() 现有项目 实例化项目类。
product2 = product.copy()
要创建深层副本,请deepcopy() 改为调用。
product2 = product.deepcopy()
从item创建字典:
>>> dict(product)
{'price': 1000, 'name': 'Desktop PC'}
从字典创建item:
>>> Product({'name': 'Laptop PC', 'price': 1500})
Product(price=1500, name='Laptop PC')
>>> Product({'name': 'Laptop PC', 'lala': 1500})
Traceback (most recent call last):
...
KeyError: 'Product does not support field: lala'
二、使用ItemLoader
我们上面的item其实就上面的功能来看,emmm,是吧,和字典没啥区别,甚至更加的繁琐了
我们有了itemloader就知道,这样写是为了后期的维护。
from scrapy.loader import ItemLoader
from myproject.items import Product
def parse(self, response):
l = ItemLoader(item=Product(), response=response)
l.add_xpath('name', '//div[@class="product_name"]')
l.add_xpath('name', '//div[@class="product_title"]')
l.add_xpath('price', '//p[@id="price"]')
l.add_css('stock', 'p#stock]')
l.add_value('last_updated', 'today')
return l.load_item()
三、Item Pipeline
在Spider 中返回一个Item 后,这个Item 将会被发送给Item Pipeline ,每个Item Pipeline 都是一个Python类,实现了几个简单的方法。其主要有以下几种作用:
- 清洗数据
- 验证抓取下来的数据(检查是否含有某些字段)
- 检查去重
- 存储数据
process_item(self, item, spider)
每一个Item Pipeline都会调用这个方法,用来处理Item,返回值为item或dict。
这个方法还可以抛出一个DropItem异常,这样将会不再继续调用接下来的Item Pipeline。
参数item(Item对象或者Dict) 是parse方法传来的。
参数spider(Spider对象) - 抓取这个Item的Spider。
open_spider(self, spider)
这个方法将会在Spider打开时调用。
close_spider(self, spider)
这个方法将会在Spider关闭时调用。
四、实例
我们这里举个例子,存储item的实例
class Job2_Tenxun(scrapy.Spider):
name = 'job2'
start_urls = ['https://hr.tencent.com/position.php?keywords=python',]
def parse(self, response):
item = MyItem()
res = response.xpath("//tr[@class='even']|//tr[@class='odd']")
for tr in res:
item['job_name'] = tr.xpath("./td[1]/a/text()").extract_first()
item['job_label'] = tr.xpath("./td[2]/text()").extract_first()
item['num'] = tr.xpath("./td[3]/text()").extract_first()
yield item
next_url = response.xpath("//a[@id='next']/@href").extract_first()
yield scrapy.Request('https://hr.tencent.com/%s'%next_url)
class MyItem(scrapy.Item):
job_name = scrapy.Field()
job_label = scrapy.Field()
num = scrapy.Field()
import json
class MyPipeline(object):
def open_spider(self,spider):
self.f = open('job2.json','w',encoding='utf-8')
def process_item(self, item, spider):
self.f.write(json.dumps(dict(item),ensure_ascii=False))
self.f.write('\n')
return item
def close_spider(self,spider):
self.f.close()
|