在scrapy中我们可以利用Item进行保存数据,但是都是由代码构造而成,例如在spider中对需要提取的字段逐个提取并进行解析,数量少可以,但是数量过大不利于后期维护。而Item Loaders给我们提供了更便捷的机制。可以理解为Item是保存数据的容器,Item Loaders是填充数据的机制。
item:Item对象。可以利用add_xpath,add_css,add_value等方法填充Item
selector:Selector对象。提取填充数据的选择器
response:Response对象。提取的响应对象
#实例化
l = ItemLoader(item=Product(), response=response)
#添加数据
l.add_xpath('字段','xpath')
l.add_css('字段','css')
l.add_value('字段','值')
#替换数据 replace_css,replace_xpath,replace_value
l.replace_value('字段','替换的值')
#返回给定字段的值
l.get_collected_values('字段')
#字段处理,
l.get_css('css',re)
l.get_xpath('xpath',re)
l.get_value('值',re)
#嵌套加载器,用于同一位置的数据放置在一个字段中,例如提取class="name"的所有标签,
l.nested_css('css')
#在spider中编写
#1.引入
from scrapy.loader import ItemLoader
from myproject.items import Product #已提前在item中写了Product
def parse(self, response):
#2对ItemLoader实例化.
l = ItemLoader(item=Product(), response=response)
#3.调用方法进行数据提取
l.add_xpath('name', '//div[@class="product_name"]')#xpath方式,提取到后会对应字段的input_processor()进行处理,然后暂存在itemloader中。
l.add_xpath('name', '//div[@class="product_title"]') #我们从不同位置提取数据也写入了name字段中。
l.add_xpath('price', '//p[@id="price"]')
l.add_css('stock', 'p#stock')#css方式
l.add_value('last_updated', 'today') # value方式,直接将字符串填入
#4.调用load_item()方法将上面收集到的数据分配到Item中
return l.load_item()
我们可以通过两种方式定义处理器
#创建loaders.py文件,声明项目处理器
from itemloaders.processors import TakeFirst, MapCompose, Join
from scrapy.loader import ItemLoader
class ProductLoader(ItemLoader):
'''
default_output_processor,default_input_processor是默认处理器
_in:输入处理器
_out:输出处理器
'''
default_output_processor = TakeFirst()
name_in = MapCompose(str.title)
name_out = Join()
price_in = MapCompose(str.strip)
……
#在item中声明输入输出处理器
import scrapy
from itemloaders.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(),
)
from itemloaders.processors import Join, MapCompose, TakeFirst,Compose,Identity,SelectJmes
#(一)Identity:不进行处理,返回原来的数据
#(二)TakeFirse:返回列表第一个非空值,类似于原来的ertract_first,一般用于output_processor
processor = TackFirst()
processor(['',1,2])
print(processor) #结果是1
#(三)Join:将列表内容拼接,默认空格连接
processor = Join()#可设置连接符
processor(['1','2','3'])
print(processor) #结果:1 2 3
#(四)Compose:多个函数构成的处理器。我们可以传给他多个函数,输入的值将依次经过这些函数处理输出
#遇到None,会停止处理,我们可以添加参数更改:stop_on__none = True
processor = Compose(str.upper,lambda s: s.strip)
processor(' hello world')
print(processor) #结果:HELLO WORLD
#(五)MapCompose:与compose类似,但是可以迭代处理列表值
processor = Compose(str.upper,lambda s: s.strip)
processor([' hello',' world'])
print(processor) #结果:['HELLO','WORLD']
#(六)SelectJmes: 给定key值,查询json中对应的value值,需要安装jsonpath库
from itemloaders.processors import SelectJmes
proc = SelectJmes("foo")
proc({'foo': 'bar'})
print(proc) #结果:'bar'
Item Loader Context是任意键值的字典,它可以被所有input/output处理器之间共享,可以修改input/output处理器的行为。
下面是一个例子,假如我们爬取多个网站,在数据中我们想定义数据源来自那个网站,此时我们可以使用content。
#spider.py
#在实例化时添加content
l = ItemLoader(item,site = response.url)
#我们可以通过l.context查看返回的值
#items.py
def source(value,loader_context):
site = loader_context.get('site')
if site == '第一个网站的url':
return '第一个网站名称'
else:
return '第二个网站名称'
#我们可以在输入/输出处理器中使用,这里我们写一个项目处理器
class TestItemLoader(ItemLoader):
site_in = MapCompose(source)
当我们熟练使用Item Loaders 后,就会发现,它是多么的强大,他可以时我们的逻辑更清晰,维护更方便。
官方文档:Item Loaders