Scrapy自带的图片和文件下载器


前言

我们在使用Scrapy爬取资料时,除了获取页面看得到的文本信息外,经常会遇到需要下载图片或文件的情况,这个时候就可以使用Scrapy自带的下载起来下载,下面我们来学习一下Scrapy里面图片和文件下载器的使用。

应用案例

简书上有对FilesPipeline和ImagesPipeline简单明了的介绍,如下引用

FilesPipeline的工作流如下:

  1. spider中爬取要下载的文件链接,将其放置于item中的file_urls
  2. spider将其返回并传送至pipeline链;
  3. FilesPipeline处理时,它会检测是否有file_urls字段,如果有的话,会将url传送给scarpy调度器和下载器;
  4. 下载完成之后,会将结果写入item的另一字段filesfiles包含了文件现在的本地路径(相对于配置FILE_STORE的路径)、文件校验和checksum、文件的url

从上面的过程可以看出使用FilesPipeline的几个必须项:

  1. Item要包含file_urlsfiles两个字段;

  2. 打开FilesPipeline配置;

  3. 配置文件下载目录FILE_STORE

    ……

IMagesPipeline的过程与FilePipeline差不多,参数名称和配置不一样;如下:

FilesPipelin ImagesPipeline
Package scrapy.pipelines.files.FilesPipeline scrapy.pipelines.images.ImagesPipeline
Item file_urls ,files image_urls ,images
存储路径配置参数 FILES_STROE IMAGES_STORE

除此之外,ImagesPipeline还支持以下特别功能:

  1. 生成缩略图,通过配置IMAGES_THUMBS = {'size_name': (width_size,heigh_size),}

  2. 过滤过小图片,通过配置IMAGES_MIN_HEIGHTIMAGES_MIN_WIDTH来过滤过小的图片。

本项目既有文件下载,也有图片下载,先配置item和settings:

item中必须包含files_urls、files或image_urls、images:

#下载文件的item
class GetAisItem_Sound(scrapy.Item):
    # define the fields for your item here like:
    sd_name = scrapy.Field()
    sd_xq_url = scrapy.Field()
    sd_type = scrapy.Field()
    sd_pf = scrapy.Field()
    sd_createdate = scrapy.Field()
    #文件下载地址
    file_urls = scrapy.Field()
    files = scrapy.Field()
#下载图片的item
class GetAisItem_Img(scrapy.Item):
    # define the fields for your item here like:
    img_name = scrapy.Field()
    img_xq_url = scrapy.Field()
    img_type = scrapy.Field()
    img_pf = scrapy.Field()
    img_createdate = scrapy.Field()
    #文件下载地址
    image_urls = scrapy.Field()
    images = scrapy.Field()

settings中启用下载器,并配置文件或图片存储目录,下载器优先级排在前面:

ITEM_PIPELINES = {
    #'scrapy.pipelines.files.FilesPipeline':1,
    'get_ais.pipelines.DownFilesPipeline':2,
    'get_ais.pipelines.DownImagesPipeline':3,
    'get_ais.pipelines.GetAisPipeline': 300,
}
#文件下载路径
FILES_STORE = basedir +'/filedata/sound'
#避免下载90天内下载过的文件
FILES_EXPIRES =  90

IMAGES_STORE = basedir +'/filedata/img'
#避免下载90天内下载过的图片
IMAGES_EXPIRES =  90
#单文件大小限制kb
DOWNLOAD_WARNSIZE=3355443200

可以看到启用的下载器并不是FilesPipeline和ImagesPipeline,是因为下载器为了避免重名文件覆盖会按照一个加密方式重新生成文件名来保存文件,而重新生成的文件名非常不直观,因此我们集成FilesPipeline和ImagesPipeline写了新的下载器类,用来重命名文件,具体如下:

#在Pipelines.py里面继承并重写下载文件的类   
class DownFilesPipeline(FilesPipeline):
    #本函数返回文件保存路径和名字,修改此方法可以修改文件名
    def file_path(self, request, response=None, info=None):
        #request是下载连接的请求,request.url就是file_urls
        try:
            #从下载连接中提取域名后的文件名
            file_path = "".join(re.findall("https://mmssxs1.com/([\w\W]+)",request.url))
            #由于中文作为url时会被quote成url的格式,因此需要unquote变回中文
            file_path_name = unquote(file_path,encoding='utf-8')
            #替换掉不能作为文件名的字符
            filename = re.sub(r'[\/:*?"<>|]', '_',file_path_name)
            logging.info('文件名%s'%filename)
            return filename
        except Exception as e:
            logging.info('错误信息%s'%e)

有的时候,下载链接的文件名也不太直观,我们想用spider爬取的到其他信息作为文件名,这个时候需要重写get_media_requests,将item传递给file_path,如下案例:

#在Pipelines.py里面继承并重写下载图片的类 
class DownImagesPipeline(ImagesPipeline):
    # 这个方法是在发送下载请求之前调用的,其实这个方法就是去发送下载请求的
    def get_media_requests(self, item, info):
        #获取请求对象和item
        request_objs = super(DownImagesPipeline, self).get_media_requests(item, info)
        for request_obj in request_objs:
            #在每个下载url请求前,往请求中添加item
            request_obj.item = item
        return request_objs

    def file_path(self, request, response=None, info=None):
        try:
            #从请求中获取item里面spider爬取的文件主题
            img_name = request.item.get('img_name')
            num = unquote("".join(re.findall(".com/([\w\W]+)",request.url)))
            #用文件主题加上url的文件名称作为下载后的文件名称
            file_path_name=img_name[0]+'_'+num
            filename = re.sub(r'[\/:*?"<>|]', '_',file_path_name)
            logging.info('文件名%s'%filename)
            return filename
        except Exception as e:
            logging.info('错误信息%s'%e) 

文章作者: 无咎
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 无咎 !
评论
 上一篇
Scrapy使用日志logging Scrapy使用日志logging
Scrapy使用日志logging一、setting启用日志先在项目根目录创建文件夹log,然后在setting.py里面增加以下代码: #日志存储在log文件夹下,以log日期命名,每天一个日志文件 #获取当前时间 import date
2020-06-09
下一篇 
用Python词云库WordClound制作词云图片 用Python词云库WordClound制作词云图片
前言之前练习Scrapy爬取网页文本,爬完后发现有2W多个TXT文档,如果一个个去看内容的话肯定不现实,这时突然想起了快速了解文本信息的‘词云’,因此萌生了用这2W多TXT文档制作一个词云图片快速了解核心内容的想法,顺便熟悉一下Python
  目录