写点什么

你只认识大众汽车的车标怎么能行?赶紧用 python 采集所有车标学习一下

作者:梦想橡皮擦
  • 2021 年 12 月 11 日
  • 本文字数:4283 字

    阅读完需:约 14 分钟

本篇博客我们将学习如何通过 scrapy 批量下载文件,还能学习通过密码解压缩包?

目标站点分析

本次要采集的目标站点为:【车标网】,最终获取的数据是车标的的矢量图。

在测试过程中发现,最后下载的压缩包存在解压密码,所以增加一个 通过密码解压缩的步骤


素材的下载地址,比较容易获取到,通过地址 logo.php?id=119 修改为 download.php?id=119 即可实现。


其中车标列表页所在的页面无迭代规则,按照分类获取即可:


http://www.chebiao.net/domestic.phphttp://www.chebiao.net/es.phphttp://www.chebiao.net/jsk.phphttp://www.chebiao.net/other.phphttp://www.chebiao.net/famous.php
复制代码

编写时间

scrapy 基本创建不在过多说明,spider 文件夹中的爬虫文件名为 cb.py,首先通过 start_urls 的设置,采集所有分类数据。


import scrapyfrom chebiao.items import ChebiaoItemfrom urllib.parse import urlparse

class CbSpider(scrapy.Spider): name = 'cb' allowed_domains = ['chebiao.net'] start_urls = ['http://www.chebiao.net/domestic.php', 'http://www.chebiao.net/es.php', 'http://www.chebiao.net/jsk.php', 'http://www.chebiao.net/other.php', 'http://www.chebiao.net/famous.php']
复制代码


接下来就是重点部分了,我们将启用 FilesPipeline 管道,用于实现对文件的下载。


使用该模块需要导入如下内容:


from scrapy.pipelines.files import FilesPipeline
复制代码


FilesPipeline 类继承自 MediaPipeline,打开类文件源码,在其中发现两个比较重要的类变量。


DEFAULT_FILES_URLS_FIELD = 'file_urls'DEFAULT_FILES_RESULT_FIELD = 'files'
复制代码


上述两个变量,如果不进行修改,后续在 items.py 文件中,必须要进行声明与赋值。


在查看源码的过程中,发现了很多可以在 settings.py 文件初始化的配置,代码不在整体复制,本文仅用到了 FILES_STORE,即下图框选区域,该值表示文件存储路径。



FilesPipeline 类中三个比较重要的方法是:


  • file_path:遍历 item 中的每一项,返回一个文件存储地址,函数原型如下所示:file_path(self, request, response=None, info=None, *, item=None)

  • get_media_requests:遍历 item 中的每一项,返回一个 Request 请求,请求的结果会传递给 item_completed 方法;

  • item_completed:媒体请求完毕之后,返回数据到该方法,并且该方法需要返回 item 或者 drop item


这里还要补充一个知识点,也是在翻阅 scrapy 源码的时候发现的,在 MediaPipeline 类中存在如下私有方法。


def _make_compatible(self):       """Make overridable methods of MediaPipeline and subclasses backwards compatible"""       methods = [           "file_path", "media_to_download", "media_downloaded",           "file_downloaded", "image_downloaded", "get_images"       ]
for method_name in methods: method = getattr(self, method_name, None) if callable(method): setattr(self, method_name, self._compatible(method))
复制代码


上述代码将 file_pathfile_downloaded 方法进行了兼容,即 file_pathmedia_to_downloadmedia_downloaded 功能一致,file_downloadedimage_downloadedget_images 功能一致。


如果你在测试代码时,发现 file_path() 方法被执行了 3 次,该原因也是由于 scrapy 框架实现的,因为 file_path() 方法分别在 media_to_download()media_downloaded()file_downloaded() 三个方法中被调用过。继续深入学习,会发现上述 3 个方法的调用顺序,这里就不在过多展开说明。

通过单文件下载,测试 scrapy 下载文件流程

接下来通过一个文件,体验整体的下载流程,该地址为:http://www.chebiao.net/download.php?id=181。按照一般编写爬虫代码的顺序,修改如下文件代码:items.py 文件代码如下


import scrapy

class ChebiaoItem(scrapy.Item): file_url = scrapy.Field() file_name = scrapy.Field() files = scrapy.Field()
复制代码


其中 file_url 表示请求的文件名,如果不希望自己扩展,应该用 file_urls 实现,file_name 为保存文件名,files 为默认字段,用于返回文件响应结果相关信息。


cb.py 文件代码如下


import scrapyfrom chebiao.items import ChebiaoItem

class CbSpider(scrapy.Spider): name = 'cb' allowed_domains = ['chebiao.net'] start_urls = ['http://www.chebiao.net/famous.php']
def parse(self, response): item = ChebiaoItem() item['file_name'] = "测试" # 文件名 item['file_url'] = "http://www.chebiao.net/download.php?id=181" yield item
复制代码


其中 file_namefile_url 都为测试值。


settings.py 文件设置爬虫相关配置


USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' # 用户代理
ROBOTSTXT_OBEY = False # 不访问 robot.txt 文件DEFAULT_REQUEST_HEADERS = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Host': 'www.chebiao.net', 'Referer': 'http://www.chebiao.net/logo.php'} # 请求头# 开启数据管道,尤其注意 ChebiaoFilePipeline 为我们手动创建的管道类,代码在下文ITEM_PIPELINES = { 'chebiao.pipelines.ChebiaoFilePipeline': 1, 'chebiao.pipelines.ChebiaoPipeline': 300,}FILES_STORE = './files' # 文件存储路径LOG_LEVEL = 'WARNING' # 日志等级
复制代码


配置中的 FILES_STORE 表示文件存储路径,设置绝对地址与相对地址都可。


pipelines.py 代码文件


from scrapy.pipelines.files import FilesPipeline# 自定义类,继承自 FilesPipelineclass ChebiaoFilePipeline(FilesPipeline):    def get_media_requests(self, item, info):        print("--get_media_requests--start-----")        print("正在下载:", item['file_name'])        print("--get_media_requests--end-----")        # 请求传递文件名参数        yield Request(item['file_url'], meta={'title': item['file_name']})
def file_path(self, request, response=None, info=None): print("--file_path--start-----") file_name = request.meta.get('title') + ".rar" print("--file_path--end-----") return file_name
def item_completed(self, results, item, info): print("--item_completed--start-----") print(results) print("下载完毕") print("--item_completed--end--------") return item
复制代码


上述代码中的 item_completed() 方法,还有一层含义,是将数据返回到下一个要执行的管道类,例如在该方法中为下一个管道增加 items.py 中的参数,需提前在 items.py 中增加 file_paths 变量。


def item_completed(self, results, item, info):    print("--item_completed--start-----")    print(results)    print("下载完毕")    file_paths = [x['path'] for ok, x in results if ok]    adapter = ItemAdapter(item)    adapter['file_paths'] = file_paths    print("--item_completed--end--------")    return item
复制代码

扩展为多文件下载

只需要修改 cb.py 文件即可实现多文件下载。


import scrapyfrom chebiao.items import ChebiaoItemfrom urllib.parse import urlparse

class CbSpider(scrapy.Spider): name = 'cb' allowed_domains = ['chebiao.net'] start_urls = ['http://www.chebiao.net/domestic.php', 'http://www.chebiao.net/es.php', 'http://www.chebiao.net/jsk.php', 'http://www.chebiao.net/other.php', 'http://www.chebiao.net/famous.php']
def parse(self, response): down_url = "http://www.chebiao.net/download.php" dds = response.xpath("//div[@class='box2']/dl/dd") for dd in dds: item = ChebiaoItem() name = dd.xpath('./a/text()').extract()[0] url = dd.xpath('./a/@href').extract()[0] url = down_url + "?" + urlparse(url).query item['file_name'] = name item['file_url'] = url
yield item
复制代码


现在我们已经可以下载全站的图片了,接下来实现解压缩文件。

解压文件

由于文件是 rar 格式,所以需要安装 unrar 模块,安装过程非常简单,使用 pip install unrar 即可,但是后续出现一些列问题,接下来为大家一一说明。


安装 unrar 之后,直接使用会出现找不到库的 BUG,需要下载 unrar library,打开 https://www.rarlab.com/rar_add.htm,找到 UnRAR.dll 下载即可,下载之后的文件为 UnRARDLL.exe,直接按照到默认路径,例如我本机为 Windows7 64 位操作系统,安装路径为 C:\Program Files (x86)\UnrarDLL


下面要配置环境变量与文件名称。


  1. 配置 x64 目录到系统环境变量中;

  2. 修改 x64 目录中的 UnRaR64.dllUnRAR64.lib 为全小写字母。



上述内置配置完毕,由于修改了环境变量,为了让 pycharm 等开发工具加载,需要重启开发工具。


接下来在 ChebiaoPipeline 类中编写如下代码,重点注意解压部分相关代码。


import osfrom unrar import rarfile

class ChebiaoPipeline: def process_item(self, item, spider): # 获取文件完整路径 path = os.path.join(os.getcwd(), "files", item['file_path']) # 解压路径 extract_path = os.path.join(os.getcwd(), "files") # 由于文件设置了【加密文件名】,所以在加载文件时,也需要设置密码 rf = rarfile.RarFile(path, pwd="www.chebiao.net") # 通过密码解压文件,解压目录为当前目录 rf.extractall(path=extract_path, pwd="www.chebiao.net") return item
复制代码


最终运行结果如下所示:

写在后面

今天是持续写作的第 <font color=red>249</font> / 365 天。期待 <font color=#04a9f4>关注</font>,<font color=#04a9f4>点赞</font>、<font color=#04a9f4>评论</font>、<font color=#04a9f4>收藏</font>。


发布于: 4 小时前阅读数: 5
用户头像

爬虫 100 例作者,蓝桥签约作者,博客专家 2021.02.06 加入

6 年产品经理+教学经验,3 年互联网项目管理经验; 互联网资深爱好者; 沉迷各种技术无法自拔,导致年龄被困在 25 岁; CSDN 爬虫 100 例作者。 个人公众号“梦想橡皮擦”。

评论

发布
暂无评论
你只认识大众汽车的车标怎么能行?赶紧用python采集所有车标学习一下