Item的基本使用
Item是保存结构数据的地方,Scrapy可以将解析结果以字典形式返回,但是Python中字典缺少结构,在大型爬虫系统中很不方便。 Item提供了类字典的API,并且可以很方便的声明字段,很多Scrapy组件可以利用Item的其他信息。基本的使用方法如下:
import scrapy
class MovieItem(scrapy.Item):
# define the fields for your item here like:
name = scrapy.Field()
Field对象可用来对每个字段指定元数据。例如上面last_updated的序列化函数指定为str,可任意指定元数据,不过每种元数据对于不同的组件意义不一样。
访问item中的值,就如访问字典值一样,如下:
#设置值的方法
product['last_updated'] = 'today'
#访问值得方法
>>> product['last_updated']
today
>>> product.keys()
['price', 'name']
>>> product.items()
[('price', 1000), ('name', 'Desktop PC')]
>>> product.get('name')
Desktop PC
Item Loader的基本使用
Item Loader为我们提供了生成Item的相当便利的方法。Item为抓取的数据提供了容器,而Item Loader可以让我们非常方便的将输入填充到容器中。
Item Loaders(项目加载器),意义,当项目很大的时候,提取的字段数以百计,做维护是很困难的。
所以scrapy就提供了ItemLoader这样一个容器,在这个容器里面可以配置item中各个字段的提取规则。可以通过函数分析原始数据,并对Item字段进行赋值,非常的便捷。参考网站:https://blog.csdn.net/zwq912318834/article/details/79530828
可以这么来看 Item 和 Itemloader:Item提供保存抓取到数据的容器,而 Itemloader提供的是填充容器的机制。
Itemloader提供的是一种灵活,高效的机制,可以更方便的被spider或source format (HTML, XML, etc)扩展并重写,更易于维护,尤其是分析规则特别复杂繁多的时候。
一般地使用方法,在爬虫.py文件中使用:
from scrapy.loader import ItemLoader
#从items中调用Product的类
from myproject.items import Product
def parse(self, response):
#ItemLoader中的参数包含两个参数,第一个是引入的类,第二个是浏览器响应的结果
l = ItemLoader(item=Product(), response=response)
#这个是三种字段的添加方法
l.add_xpath('name', '//div[@class="product_name"]')
l.add_css('stock', 'p#stock]')
l.add_value('last_updated', 'today') # you can also use literal values
#添加load_item()来提交字段
return l.load_item()填充到容器中
在item.py中可以自定义字段:
有两种方法,第一种是在item自定义Itemloader类中添加
from scrapy.loader import ItemLoader
#Identity、TakeFirst、Join、Compose、MapCompose、SelectJmes都是内置的处理器
from scrapy.loader.processors import TakeFirst, MapCompose, Join
class ProductLoader(ItemLoader):
#定义默认的ItemLoader.default_input_processor和ItemLoader.default_input_processor
default_output_processor = TakeFirst()
#通过_in和_out后缀来定义输入和输出处理器
name_in = MapCompose(unicode.title)
name_out = Join()
price_in = MapCompose(unicode.strip)
第二种方式是在item文件Field方法定义中添加
import scrapy
#Identity、TakeFirst、Join、Compose、MapCompose、SelectJmes都是内置的处理器
from scrapy.loader.processors import Join, MapCompose, TakeFirst
from w3lib.html import remove_tags
def filter_price(value):
if value.isdigit():
return value
class Product(scrapy.Item):
name = scrapy.Field(
input_processor=MapCompose(remove_tags),
output_processor=Join(),
)
price = scrapy.Field(
input_processor=MapCompose(remove_tags, filter_price),
output_processor=TakeFirst(),
)
ItemLoader的存入item的方式,以及输出到pipeline的方式
ItemLoader 包含的两个东西:
(1)输入处理器(input_processor) ,当这个item,title这个字段的值传过来时,可以在传进来的值上面做一些预处理。
(2)输出处理器(output_processor) , 当这个item,title这个字段被预处理完之后,输出前最后的一步处理。
总结一下,每个字段的数据的处理过程是:
第一步, 通过 add_xpath(), add_css() 或者 add_value() 方法),提取到数据。
第二步,将提取到的数据,传递到输入处理器(input_processor)中进行处理,处理结果被收集起来,并且保存在ItemLoader内(但尚未分配给该Item)。
第三步,最后调用输出处理器(output_processor)来处理之前收集到的数据(这是最后一步对数据的处理)。然后再存入到Item中,输出处理器的结果是被分配到Item的最终值。
第四步,收集到所有的数据后, 调用ItemLoader.load_item() 方法来填充,并得到填充后的 Item 对象。
实例1: 关于ItemLoader中的输入输出问题,如果itemloader存入的是一个列表型数据,类似['字符串','字符串','字符串','字符串'],输入方式如下:
# -*- coding: utf-8 -*-
import scrapy
import re
from scrapy.loader import ItemLoader
from LianjiaScrapy.items import Lianjia1scrapyItem
class TestSpider(scrapy.Spider):
name = 'test'
#allowed_domains = ['www.lianjia.com']
start_urls = ['https://sh.lianjia.com/zufang/jingan/rt200600000001l0/#contentList']
def parse(self, response):
item1Loader=ItemLoader(item=Lianjia1scrapyItem(),response=response)
item1Loader.add_xpath('area','.//p[@class="content__list--item--des"]/a[1]//text()')
item1Loader.add_xpath('Community','.//p[@class="content__list--item--des"]/a[2]//text()')
item1Loader.add_xpath('village','.//p[@class="content__list--item--des"]/a[3]//text()')
item1Loader.add_xpath('price','.//span[@class="content__list--item-price"]/em//text()')
item1Loader.add_xpath('Content','.//p[@class="content__list--item--des"]')
yield item1Loader.load_item()
print("成功啦")
当输入的时候,在items.py中
from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, MapCompose, Join
import scrapy
import re
def zufang(value):
#value=value.encode("utf-8")
value= str(value)
value=re.sub('<.*?>',"",value) #去除html标签
value=value.replace('/n',"") #去除换行键
value=re.sub('\s+','',value).strip()#去除空格
return value
def outzufang(value):
print("这里是输出")
print(value)
return value
class Lianjia1scrapyItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
area=scrapy.Field(
input_processor = MapCompose(zufang),
output_processor=MapCompose(outzufang)
)
输出的结果如下,可见当我们用ItemLoader来输入输出的时候,它们是把数据单独提取出来传递的,就是把一个列表内容单独拆分出来输出。
当数据进入pipeline.py中,也就是最终输出形态的时候,数据是以怎么样的形式出现的,假设pipeline.py输出代码如下:
import pymysql
# 使用twsited异步IO框架,实现数据的异步写入。
from pymysql import cursors
from openpyxl import Workbook
from twisted.enterprise import adbapi
class ZufangscrapyPipeline(object):
def __init__(self):
self.wb = Workbook()
self.ws = self.wb.active
self.ws.append(['地区', '社区', '小区', '价格','内容' ])# 设置表头
def process_item(self, item, spider): # 具体内容
# line = [item['area'],item['Community'], item['village'], item['price'], item['Content']] # 把数据中项整理出来
# self.ws.append(line) # 将数据需要保存的项以行的形式添加到xlsx中
# self.wb.save('web.xlsx') # 保存xlsx文件
print("这里是pipeline")
print(item['area'])
#print("pipeline中的item['area']是"+item['area'])
return item
这里的关于Excel操作的内容可以忽略,只看print输出的item['area']结果,结果如下:
这些数据在进入ItemLoader之前是以列表存在的,进入后是以列表中每一个元素依次进行处理,然后被output_processor输出的时候是重新自动被转化成一个列表进行输出的。ItemLoader相当于一个放大细节的item处理程序,也就是你以什么形式进入的,就会以什么形式输出出来。这点当你存入excel的时候要非常的注意。