首页 > 其他 > 详细

scrapy下载的文件重新命名

时间:2019-06-01 16:49:43      阅读:478      评论:0      收藏:0      [点我收藏+]

scrapy利用FilesPipline实现了文件的下载, 因此如果想要重名文件,只需要重写这个类

class MyfilesPipeline(FilesPipeline):

    def file_downloaded(self, response, request, info):
      """
         文件下载完成以后会调用FilesPipeline 中的file_downloaded方法,因此只需要重写
         file_downloaded方法即可
      """
        path = self.file_path(request, response=response, info=info)
        # 文件的名字, 在Response响应内容中,一般都包含file文件的名字,可以根据reponse中的请求头参数
        # 进行提取,比如content-disposition可能就含有文件名或者文件类型,
        # content-disposition: attachment; filename="科创板上市法律意见书模板.docx";filename*=utf-8‘ ‘%E7%A7%91%E5%88%9B%E6%9D%BF%E4%B8%8A%E5%B8%82%E6%B3%95%E5%BE%8B%E6%84%8F%E8%A7%81%E4%B9%A6%E6%A8%A1%E6%9D%BF.docx
        # 或者也可以自定义文件名字
        file_name = self.clean_file_name(response)
        if file_name:
            path = file_name
        buf = BytesIO(response.body)
        checksum = md5sum(buf)
        buf.seek(0)
        self.store.persist_file(path, buf, info)
        return checksum 

如上述代码重写 FilesPipeline 中的 file_downloaded 方法, 因为当文件下载完成以后会执行这个方法, 而其中的path则是文件的名字, 其中path 调用了 FilesPipeline 中的 file_path 方法,下面来看这个方法的源码

# 生成储存文件名的方法
def file_path(self, request, response=None, info=None):
        ## start of deprecation warning block (can be removed in the future)
        def _warn():
            from scrapy.exceptions import ScrapyDeprecationWarning
            import warnings
            warnings.warn(FilesPipeline.file_key(url) method is deprecated, please use 
                          file_path(request, response=None, info=None) instead,
                          category=ScrapyDeprecationWarning, stacklevel=1)

        # check if called from file_key with url as first argument
        if not isinstance(request, Request):
            _warn()
            url = request
        else:
            url = request.url

        # detect if file_key() method has been overridden
        if not hasattr(self.file_key, _base):
            _warn()
            return self.file_key(url)
        ## end of deprecation warning block

        media_guid = hashlib.sha1(to_bytes(url)).hexdigest()  # change to request.url after deprecation
        media_ext = os.path.splitext(url)[1]  # change to request.url after deprecation
        return full/%s%s % (media_guid, media_ext)
      
# 上述为file_path的源码,最终返回的是full/hash后的URL , 那么会在指定文件中生成full文件夹,在full文件夹下储存下载好的文件,文件名为hash候的URL

文件储存则是调用了 self.store.persist_file(path, buf, info) 方法, 其实是调用了文件的储存类 FSFilesStore ,下面看一下该类的源码

class FSFilesStore(object):
    def __init__(self, basedir):
        if :// in basedir:
            basedir = basedir.split(://, 1)[1]
        self.basedir = basedir
        self._mkdir(self.basedir)
        self.created_directories = defaultdict(set)
  # 文件储存调用了该方法
def persist_file(self, path, buf, info, meta=None, headers=None): absolute_path = self._get_filesystem_path(path) self._mkdir(os.path.dirname(absolute_path), info) with open(absolute_path, wb) as f: f.write(buf.getvalue())

如上面源码所示, scrapy 将传入的path和setting中的文件储存路径进行拼接,最后在生成的路径中写入文件, 所以我们只需要修改path就能对文件重新进行命名, 至于是从reponse请求头中获取还是其他自定义方式,由情况而定

在完成path的修改以后,还需要添加一下内容

settings.py

# setting 中配置
ITEM_PIPELINES = {
     # ‘scrapy.pipelines.files.FilesPipeline‘:1,  # 文件下载管道
       zhishixinqiu.pipelines.MyfilesPipeline:1  # 自定义的文件下载管道
}

DOWNLOAD_TIMEOUT=1800  # 长连接断开时间
FILES_STORE = /Users/lin/Desktop/test  # 文件储存路径

spider.py文件

# 需要将download_url 对象返回, 
# 如果是item,则必须在item中含有file_urls字段
item = ZhishixinqiuItem()
item["files"] = file
item["file_urls"] = [download_url]  # file_urls字段value必须是列表对象
yield item

# 也可以直接返回字典,但是字典中必须含有键"file_urls", 且值必须是URL列表
item = {}
item["file_urls"] = [download_url]
yield item

 

scrapy下载的文件重新命名

原文:https://www.cnblogs.com/kentlin/p/10960107.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!