想要爬去一个名单上的姓名及其照片,通过scrapy可以很轻易的分别完成这两样工作,然而想要在一个scrapy项目中完成这两个项目还是有些麻烦,一是使用imagepipeline需要额外在item中定义image_url images属性,且爬取职员名单和爬取职员照片是分别在两个parse函数中进行的,这样对item的赋值会出现问题,因为在两个parse函数中相当于分别定义并赋值了两个item。二是我需要对输出的json文件进行处理,用scrapy crawl xxx -o xx.json 指令输出的json文件也会因为对item这种额外的添加key额外的进行初始化并赋值产生各种各样的错误。所以我想定义两个item,一个用来储存职员的姓名信息并输出为JSON文件,另一个就储存image_urls等信息专门用作图片爬取。
所以就在items中定义了两个item
class namelistItem(scrapy.Item):
department=scrapy.Field()
firstname=scrapy.Field()
surname=scrapy.Field()
class urlItem(scrapy.Item):
image_paths=scrapy.Field()
image_urls=scrapy.Field()
images=scrapy.Field()
spider爬取完网页内容返回item送给pipeline处理,在这里我们需要对两个item进行分别用以不同的处理,如对图片url的处理我们可以用isinstance对item的class进行鉴别
class NewsImagePipeline(ImagesPipeline):
def get_media_requests(self,item,info):
if isinstance(item,urlItem):
title=item['title']
yield scrapy.Request(url=item['image_urls'],meta={'title':title})
def item_completed(self,results,item,info):
image_path=[x['path'] for ok,x in results if ok]
if not image_path:
raise DropItem("Item contains no images")
return item
注意此时在pipeline文件开头要
from projectname.items import urlItem,namlistItem
否则会报错无法识别urlitem或namelistitem
之后在setting文件中设置图片储存路径,开启imagepipeline不在话下了
然而对我们最重要的还是想要输出一个JSON文件,在多个item存在的情况下,在命令行使用-o的命令是无法输出正确的JSON的,因此我们要在pipeline里自己定义一个JsonItemExporterPipeline
from scrapy.exporters import JsonItemExporter
class JsonPipeline(object):
def __init__(self):
self.file = open('employeelist.json', 'wb')
self.exporter = JsonItemExporter(self.file, encoding="utf-8", ensure_ascii=False)
self.exporter.start_exporting()
def close_spider(self, spider):
self.exporter.finish_exporting()
self.file.close()
def process_item(self, item, spider):
if isinstance(item,namelistitem):
self.exporter.export_item(item)
return item
之后再setting中开启JsonPipeline即可,这样使用scrapy crawl project就可以自动产生一个JSON文件了