美文网首页
Scrapy框架-图片下载功能

Scrapy框架-图片下载功能

作者: 中乘风 | 来源:发表于2018-07-13 16:16 被阅读0次

    其实文件下载也差不多

    前言

    在日常爬取的过程中,图片下载还是挺多的,有时候可能纯粹是爬取图片,比如妹子图、动态图、表情包、封面图等,还有些时候是要进行验证码识别,所以需要用到图片下载功能。很高兴的是Scrapy为用户提供了图片下载功能,具体使用方法这里记录一下,它的逻辑是:

    spider获取图片url --> 交给item进行处理 --> 然后根据setting的配置(开启图片下载以及设置路径)进行下载
    具体的代码实现为:
    Spider代码获取url,传递到item:

            telnums = response.css('.address tr:first-child img::attr(src)').extract_first("")
            loaders.add_value("image_urls", telnums)  # 企业联系电话(下载图片)
    

    item对值进行预处理:

    default_output_processor = TakeFirst()  # itemloader
    
    image_urls = scrapy.Field()  #item
    

    然后根据settings.py的配置:

    IMAGES_URLS_FIELD = "image_urls"  # 对应item里面设定的字段,取到图片的url
    prodir = os.path.abspath(os.path.dirname(__file__))
    IMAGES_STORE = os.path.join(prodir,"images")  # 设置图片保存path
    

    进行下载,即可完成下载功能。其中IMAGES_URLS_FIELD是固定写法,通过它来获取item中设定的图片url;IMAGES_STORE也是固定写法,设置图片保存路径。


    这是一个坑

    保存运行后得到一个报错:

    Traceback (most recent call last):
      File "/home/ranbo/anaconda3/envs/pspiders/lib/python3.6/site-packages/twisted/internet/defer.py", line 653, in _runCallbacks
        current.result = callback(current.result, *args, **kw)
      File "/home/ranbo/anaconda3/envs/pspiders/lib/python3.6/site-packages/scrapy/pipelines/media.py", line 79, in process_item
        requests = arg_to_iter(self.get_media_requests(item, info))
      File "/home/ranbo/anaconda3/envs/pspiders/lib/python3.6/site-packages/scrapy/pipelines/images.py", line 155, in get_media_requests
        return [Request(x) for x in item.get(self.images_urls_field, [])]
      File "/home/ranbo/anaconda3/envs/pspiders/lib/python3.6/site-packages/scrapy/pipelines/images.py", line 155, in <listcomp>
        return [Request(x) for x in item.get(self.images_urls_field, [])]
      File "/home/ranbo/anaconda3/envs/pspiders/lib/python3.6/site-packages/scrapy/http/request/__init__.py", line 25, in __init__
        self._set_url(url)
      File "/home/ranbo/anaconda3/envs/pspiders/lib/python3.6/site-packages/scrapy/http/request/__init__.py", line 62, in _set_url
        raise ValueError('Missing scheme in request url: %s' % self._url)
    ValueError: Missing scheme in request url: h
    

    网上查资料得知:

     return [Request(x) for x in item.get(self.images_urls_field, [])]
    

    scrapy下载图片的类传参数是list,而不是'http://www.baidu.com/123.jpg'这种str格式,在item传递的时候默认是所有数据都是list,但是之前在itemloaders加了TakeFirst:

    class GxrcItemLoader(ItemLoader):
        """ 广西人才网企业信息itemloader """
        default_output_processor = TakeFirst()
    

    所以才会被处理成str。


    脱坑

    现在只需要将它变成list即可,在item编写一个预处理的方法:

    def keep_list(value):
        """
        scrapy的图片下载url默认处理列表list格式,str会报错
            由于下方itemloaders设置了default_output_processor为TakeFirst
            所以这里需要定义一个直接返回的函数来覆盖output_processor,这样就可以保持list格式
        """
        return value
    

    然后在item代码里覆盖output_processor:

    image_urls = scrapy.Field(output_processor=MapCompose(keep_list))

    同时spider也得到解放,代码改成:

    loaders.add_css("image_urls", ".address tr:first-child img::attr(src)")  # 企业联系电话(下载图片)
    

    就可以下载图片了,而且代码风格有条理,舒服。


    文件名和路径

    下载后要获得图片的文件名和存放路径,毕竟下载完了之后不能不管。

    scrapy下载的时候默认用hash加密图片url得到固定长度的值作为文件名,我要是想获得的话有两个方式,第一是自己加密图片url,生成文件名,路径就用setting里面配置的路径即可;第二个方式是重载ImagePipeline,在生成的时候就进行处理,这里演示第二种:
    这个ImagePipeline写在pipelines.py文件中

    它重载的是:

    from scrapy.pipelines.images import ImagesPipeline

    并且里面有很多的方法可以让我们在settings中进行配置,比如过滤图片的格式、图片大小等(文档有记录,以后翻文档)。

    在pipelines.py文件中编写代码:

    class ImagePathPipeline(ImagesPipeline):
        """
        继承ImagesPipeline,重载方法
            以实现处理图片下载路径的目的
        """
        def item_completed(self, results, item, info):
    
            pass   # (这里打断点,等下调试)
    

    然后到settings.py中将之前使用的默认ImagesPipeline替换成自定的:

    ITEM_PIPELINES = {
        #'scrapy.contrib.pipeline.images.ImagesPipeline': 1,
        'rspider.pipelines.ImagePathPipeline': 1,# 开启图片下载
    }
    

    然后debug运行,进行调试,看看 item_completed方法里面的results是什么样的数据结构:

    <class 'list'>: [(True, {'url': 'http://vip.gxrc.com/Public/Phone/F4D1D4B0-DABB-4E83-BC54-5153BC44AA33', 'path': 'full/82cf733279ebc25c4de892e531018644e77aed67.jpg', 'checksum': 'b14c3fcdeb93209bc835d2d3dfdefb57'})]
    

    可以看到,results是一个list,然后里面嵌套了一个tuple,再嵌套一个dict,dict存放有三个值,url/path/checksum,其中的path就是文件的路径,所以整个代码为:

    class ImagePathPipeline(ImagesPipeline):
        """
        继承ImagesPipeline,重载item_completed方法
            以实现处理图片下载路径的目的
        """
        def item_completed(self, results, item, info):
            """ 循环results,将里面的path取出,然后赋值到item中的image_path字段,最后返回item """
            for ok, value in results:
                image_path = value["path"]
            item["image_path"] = image_path
            return item
    

    总而言之

    要给Scrapy增加图片下载功能,只需要编写Pipelines并且在Settings.py文件中开配置item中对应的图片url字段、设置图片保存地址以及开启pipeliens即可

    相关文章

      网友评论

          本文标题:Scrapy框架-图片下载功能

          本文链接:https://www.haomeiwen.com/subject/ozqspftx.html