python-scrapy爬虫框架处理爬取图片的url储存在列表中的问题

爬虫爬取图片需要从scrapy.pipelines.images模块中调用ImagesPipeline来进行图片的下载和存取。

在爬取王者荣耀各英雄皮肤时,我将一个英雄所有皮肤图片的url存在列表中,想要把同一个英雄的皮肤爬取下来放在一个文件夹中。但是每次提交下载请求的返回值不能是列表值,也就意味着一次调用WzryImgPipeline只能下载一次图片。由于图片下载后,还需要进行更名操作,需要获取皮肤图片的英雄名和皮肤名信息。那该怎么办呢?

1.ImagesPipeline部分函数源代码

1.1get_media_requests(self, item, info)

def get_media_requests(self, item, info):
    return [Request(x) for x in item.get(self.images_urls_field, [])]

 get_media_requests用来发送下载请求,images_urls_field储存的是图片的url,需要在items.py里设置。

1.2item_completed(self, results, item, info)

def item_completed(self, results, item, info):
    if isinstance(item, dict) or self.images_result_field in item.fields:
        item[self.images_result_field] = [x for ok, x in results if ok]
    return item

 通过scrapy爬取框架爬下来的图片名是SHA1值,若要更改文件名,可通过重写item_completed实现。

item_completed函数的第二个参数results的格式是list [(DownLoad_success_or_failure,dict)],dict中含有三个键:1、'url':图片路径 2、'path':图片下载后的保存路径 3、'checksum':校验码。

下面是应用于爬取链家二手房图片的修改图片名代码:

class LianjiaImgPipeline(ImagesPipeline):
    def get_media_requests(self,item,info):
        for image_url in item['image_urls']:
            yield scrapy.Request(image_url)

    def item_completed(self,results,item,info):
        #取results图片信息里,图片路径的值
        print ('******the results is********:',results)
        image_path = [x['path'] for ok,x in results if ok]
        if not image_path:
            raise DropItem("Item contains no images")
        os.rename(images_store+image_path[0],images_store+item['title']+'.jpg')
        #os.rename(IMGS + '/' + results[0][1]['path'], IMGS + '/' + item['img_name'])
        return item

1.3file_path(self, request, response=None, info=None)

def file_path(self, request, response=None, info=None):
    image_guid = hashlib.sha1(to_bytes(request.url)).hexdigest()
    return 'full/%s.jpg' % (image_guid)

这个方法是在图片将要被储存时调用,用来获取图片存储的全部本地路径。观察代码可发现图片的存储形式是在full文件夹下,以"%s.jpg"命名的,%s为图片的sha1值。因此,修改file_path函数也可以对图片重命名。但是这个方法相对于重写item_completed来说,对程序的破坏较大,不是必须用时还是用item_completed比较好。因为在爬取王者荣耀英雄皮肤图片时,需要把不同英雄的皮肤保存到不同的文件夹,所以下面选用了重写file_path。

2.解决办法

调用父类方法,将所有列表里的元素全部提取出来,变为一个个request对象,再给对象传入hero,name参数,便于重写file_path方法改名。

class WzryImgPipeline(ImagesPipeline):
    #此方法是在发送下载请求之前调用,其实此方法本身就是去发送下载请求
    def get_media_requests(self,item,info):
        #调用原父类方法,发送下载请求并返回的结果(request的列表)
        request_objs=super().get_media_requests(item,info)
        #给每个request对象带上meta属性传入hero、name参数,并返回
        for request_obj,num in zip(request_objs,range(0,len(item['skins']))):
            request_obj.meta['hero']=item['hero']
            request_obj.meta['skin']=item['skins'][num]
        return request_objs

    #此方法是在图片将要被存储时调用,用来获取这个图片存储的全部路径
    def file_path(self,request,response=None,info=None):
        #获取request的meta属性的hero作为文件夹名称
        hero=request.meta.get('hero')
        #获取request的meta属性的skin并拼接作为文件名称
        image=request.meta.get('skin')+'.jpg'
        #获取IMAGES_STORE图片的默认地址并拼接!!!!不执行那一步
        hero_path=os.path.join(images_store,hero)
        #判断地址是否存在,不存在则创建
        if not os.path.exists(hero_path):
            os.makedirs(hero_path)
        #拼接文件夹地址与图片名存储的全部路径并返回!!!!原方法
        image_path=os.path.join(hero_path,image)
        return image_path

参考链接:https://blog.csdn.net/weixin_45335208/article/details/103351806

你可能感兴趣的:(python-scrapy爬虫框架处理爬取图片的url储存在列表中的问题)