zoukankan      html  css  js  c++  java
  • 爬虫2.4-scrapy框架-图片分类下载

    scrapy框架-图片下载

    python小知识:

    map函数:将一个可迭代对象的每个值,依次交给一个函数处理,返回一个生成器。

    urls = uibox.xpath(".//ul/li/a/img/@src").getall()
    urls = list(map(lambda url: 'https:'+url, urls))
    

    urls本身是一个列表,使用map函数,将urls中的每一项传递给url ,并让url执行‘https:’+url的操作。 lambda则是一个无名函数,方便一行内写完函数。最后用list函数将map返回的生成器转成列表

    1 传统下载方法:

    pipelines.py
    def process_item(self, item, spider):
        category = item['category']  # 一个字符串
        urls = item['urls']  # 一个列表
        local_path = os.path.abspath('.') # 获取绝对路经
        os.mkdir(r'{}images{}'.format(local_path, category)) #分类创建images/category文件夹
        for url in urls:
            filename = url.split('_')[-1]  # 获取图片名
            request.urlretrieve(url, '{}images{}{}'.format(local_path, category, filename))  # 将图片下载到/images/category/filename
    

    缺点是非异步,图片是一张一张按顺序下载的,数量较大时效率低

    2 scrapy框架的下载方法

    scrapy.pipelines中提供了两个下载文件的子类

    一个是scrapy.pipelines.files 中的FilesPipeline,另一个是scrapy.pipelines.images 中的ImagesPipeline

    其中ImagesPipeline专门用于下载图片,是继承自FilesPipeline

    ImagesPipeline使用方法

    1)在items.py中定义好image_urls和images,image_urls是用来存储需要下载的图片的url,需要给一个列表,images中需要保存图片的属性,如下载路径、url、图片的校验码等

    2)当图片下载完成后,会把文件下载的相关信息存储到item中的images属性中。

    3)在配置文件settings.py中配置IMAGES_STROE,这个配置是用来设置图片下载路径的

    4)启动pipeline,在ITEM_PIPELINES中注释原来的pepeline设置'scrapy.pipelines.images.ImagesPipeline':1

    FilesPipeline使用方法类似

    定义好file_urls和file,设置好FILES_STORE,以及ITEM_PIPELINES中的scrapy.pipelines.files.FilesPipeline:1

    2.1 将图片全部下载到full文件夹下

    本来高高兴兴来到实验室,2分钟就把需要整的步骤整完了,如何折腾了一个小时都没想通为什么爬虫无法执行parse()函数,各种百度,最后对比之前写的爬虫发现,我睡了午觉起来迷迷糊糊将start_urls 改成了start_image_urls 这样的话scrapy框架一检查,没有开始点啊,那直接就结束了。。。。

    1)修改setttings.py 注释掉原来的ITEM_PIPELINES中的内容,添加'scrapy.pipelines.images.ImagesPipeline': 1

    并添加图片存储路径IMAGES_STORE = os.path.join(os.path.abspath('.'), 'images')

    ~ settings.py
    ITEM_PIPELINES = {
       # 'bmw.pipelines.BmwPipeline': 300,
     'scrapy.pipelines.images.ImagesPipeline': 1
    }
    IMAGES_STORE = os.path.join(os.path.abspath('.'), 'images')  # 爬虫项目根目录/images
    

    2)修改items.py 添加或修改 image_urls和images

    image_urls = scrapy.Field()
    images = scrapy.Field()
    

    3)修改[spider.py] yield image_urls

    item = BmwItem(category=category, image_urls=image_urls)  # 重点在于image_urls
    yield item
    

    执行,得到结果:./images/full 目录下下载了一堆没有分类的图片

    这个时候就想怎么讲图片分类下载好,比如车身图片(实验代码以汽车之家宝马5x图片进行下载)就在/images/车身,内部图片在/images/内部,这样强迫症才舒服

    2.2 将图片分类到不同目录

    这里就需要重写scrapy.pipelines.images.ImagesPipeline里面的一些方法了。

    这里需要注意:parse()函数中yield 抛出的数据格式为 category: ‘xxx’ image_urls: ['url', 'url'....] images: ''

    所以在之后操作时,每次抛出的image_urls 都对应着同一个category

    1)继承ImagesPipeline,并改写一些返回值

    from bmw import settings  # bmw是项目名
    import os  # 2)中需要用到
    class BMWImagesPipeline(ImagesPipeline):  # 新定义一个子类,继承ImagesPipeline
        def get_media_requests(self, item, info):
            request_objs = super(BMWImagesPipeline, self).get_media_requests(item, info)
            for request_obj in request_objs:
                request_obj.item = item  # 为每个request_obj对象添加item属性,里面包含了category
            return request_objs  # 父类中必须返回这个列表,给其他函数使用
    

    get_media_requests函数原本返回的是[Request(x) for x in item.get(self.images_urls_field, [])],即返回了一个Request(url)的列表,这里改造一下,使用super重复父类中的方法,得到一个返回值,并添加了item属性,方便下一步使用。

    2)重写file_path()方法

    def file_path(self, request, response=None, info=None):
        # path获取父类中file_path方法返回的值即‘full/hash.jpg' hash是图片的哈希值
        path = super(BMWImagesPipeline, self).file_path(request, response, info)
        #request即前一个函数返回的列表中的每一项,所以有item属性
        category = request.item.get('category')
        images_store = settings.IMAGES_STORE  # IMAGES_STORE是需要下载到的路径,例如c:/images
        category_path = os.path.join(images_store, category) # 创建每个种类的路径并判断是否已存在
        if not os.path.exists(category_path):
            os.mkdir(category_path)
        image_name = path.replace('full/', '')  # 去掉原本的'full/' 只留下文件名
        image_path = os.path.join(category_path, image_name) 
        # 图片完整的路径和文件名c:/images/aaa/js451v88225F45sd42f4y4.jpg
        return image_path
    

    3)修改settings.py中的配置

    ITEM_PIPELINES = {
       # 'bmw.pipelines.BmwPipeline': 300, 注释掉原有的pipeline
        'bmw.pipelines.BMWImagesPipeline': 1
    }
    IMAGES_STORE = os.path.join(os.path.abspath('.'), 'images')  # 添加图片保存地址
    

    完工,重写之后每个图片的路径就包含了自己的种类,下载完成后目录格式如下:

    images
       车头
           41312r322r2234.jpg
           1425flj5l2.jpg
       车身
       。。
    

    3 分类下载完整代码

    项目名:bmw 爬虫名:bmw5x

    bmw5x.py

    import scrapy
    from bmw.items import BmwItem
    
    
    class Bmw5xSpider(scrapy.Spider):
        name = 'bmw5x'
        allowed_domains = ['car.autohome.com.cn']
        start_urls = ['https://car.autohome.com.cn/pic/series/65.html#pvareaid=2042209']
    
        def parse(self, response):
            uiboxs = response.xpath("//div[@class='uibox']")[1:]
            for uibox in uiboxs:
                category = uibox.xpath("./div/a/text()").get()
                image_urls = uibox.xpath(".//ul/li/a/img/@src").getall()
                image_urls = list(map(lambda url: 'https:'+url, image_urls))
                item = BmwItem(category=category, image_urls=image_urls)
                yield item
    

    items.py

    import scrapy
    class BmwItem(scrapy.Item):
        category = scrapy.Field()
        image_urls = scrapy.Field()
        images = scrapy.Field()
    

    pipelines.py

    import os
    from scrapy.pipelines.images import ImagesPipeline
    from bmw import settings
    
    
    class BMWImagesPipeline(ImagesPipeline):
        def get_media_requests(self, item, info):
            request_objs = super(BMWImagesPipeline, self).get_media_requests(item, info)
            for request_obj in request_objs:
                request_obj.item = item
            return request_objs
    
        def file_path(self, request, response=None, info=None):
            path = super(BMWImagesPipeline, self).file_path(request, response, info)
            category = request.item.get('category')
            images_store = settings.IMAGES_STORE
            category_path = os.path.join(images_store, category)
            if not os.path.exists(category_path):
                os.mkdir(category_path)
            image_name = path.replace('full/', '')
            image_path = os.path.join(category_path, image_name)
            return image_path
    

    settings.py

    import os
    ROBOTSTXT_OBEY = False
    DEFAULT_REQUEST_HEADERS = {
      'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
      'Accept-Language': 'en',
      'User-Agent': 'xxx',
      'Referer': 'xxx',
      'Cookie': 'xxx'
    }
    ITEM_PIPELINES = {
        'bmw.pipelines.BMWImagesPipeline': 1
    }
    IMAGES_STORE = os.path.join(os.path.abspath('.'), 'images')
    

    作者:bitterz
    本文版权归作者和博客园所有,欢迎转载,转载请标明出处。
    如果您觉得本篇博文对您有所收获,请点击右下角的 [推荐],谢谢!
  • 相关阅读:
    HDU 5835 Danganronpa 贪心
    HDU 5842 Lweb and String 水题
    HDU 5832 A water problem 水题
    Codeforces Beta Round #14 (Div. 2) A. Letter 水题
    Western Subregional of NEERC, Minsk, Wednesday, November 4, 2015 Problem K. UTF-8 Decoder 模拟题
    Western Subregional of NEERC, Minsk, Wednesday, November 4, 2015 Problem I. Alien Rectangles 数学
    Western Subregional of NEERC, Minsk, Wednesday, November 4, 2015 Problem H. Parallel Worlds 计算几何
    Western Subregional of NEERC, Minsk, Wednesday, November 4, 2015 Problem F. Turning Grille 暴力
    Western Subregional of NEERC, Minsk, Wednesday, November 4, 2015 Problem C. Cargo Transportation 暴力
    Western Subregional of NEERC, Minsk, Wednesday, November 4, 2015 Problem G. k-palindrome dp
  • 原文地址:https://www.cnblogs.com/bitterz/p/10202197.html
Copyright © 2011-2022 走看看