matplotlib是图形绘制库,使用matplotlib可以方便的绘制函数图形、以及直方图、条形图、散点图等统计图形,主要用于科学计算和数据分析等领域。在matplotlib官网提供了很多案例源代码,每个案例的源代码需要单独下载。若希望快速下载全部案例源代码,可以编写一个爬虫程序来下载全部的案例源代码。
下面使用PyCharm来建立matplotlib案例源代码爬虫项目。
1、 使用PyCharm建立爬虫项目
使用PyCharm建立matplotlib爬虫项目的步骤如下:
1、建立Pure Python项目,解释器选择Exsiting interpreter,即本地安装的Python解释器,如下图所示:

(2)展开PyCharm终端窗口(Terminal),在终端窗口使用Scrapy创建项目命令,创建爬虫项目,在终端窗口输入下面的Scrapy命令并回车执行命令:
scrapy startproject matplotlib
命令执行成功后,Scrapy会在matplotlib项目目录下创建Scrapy爬虫项目,爬虫项目名称为matplotlib,如下图所示:

创建的项目资源如下图所示:

(3)在终端窗口将当前工作目录切换到Scrapy项目目录下,如下图所示:

输入创建爬虫命令:
scrapy genspider spider_matplotlib www.matplotlib.org
命令执行成功后,Scrapy会在项目的spiders目录创建爬虫spider_matplotlib.py模块文件。如下图所示:

2、 分析matplotlib网站
项目要下载matplotlib网站的案例源代码,就需要了解matplotlib网站结构,找到案例源代码网页,然后对案例源代码网页进一步分析,编写XPath表达式提取案例源代码的下载链接。
通过对matplotlib网站观察分析得知,matplotlib网站的所有案例网页链接都在Examples网页内,网页地址如下:
https://www.matplotlib.org/gallery/index.html
观察index.html网页源代码,发现所有案例网页链接标签<a>的href属性值都包含子串“-py”,利用子串“-py”可以把所有案例网页链接提取出来,并能过滤掉不需要的链接。
某<a>标签代码如下:
<a class="reference internal" href="images_contours_and_fields/image_nonuniform.html#sphx-glr-gallery-images-contours-and-fields-image-nonuniform-py"> <span class="std std-ref"> Image Nonuniform </span> </a>
提取网页内全部<a>标签的href属性值的XPath表达式如下:
//a[contains(@href,'-py')]/@href
检测XPath表达式的正确性
可以使用Scrapy shell命令检测XPath表达式的正确性,在PyCharm的终端窗口输入下面的命令(如下图所示):
scrapy shell https://www.matplotlib.org/gallery/index.html
命令执行后,shell会爬取指定的url网页,并返回response实例对象。对象变量名称为response,开发者可以使用response来执行内容提取测试任务。

在PyCharm终端窗口shell环境下,输入下面的命令验证XPath表达式的正确性:
response.xpath("//a[contains(@href,'-py')]/@href").extract()
命令执行后,在PyCharm终端窗口会列出提取的网页案例URL,若提取内容不符合要求,需要进一步分析网页结构,修改XPath表达式。
分析下载页面
接下来分析下载页面,单击index.html网页的案例代码连接即可进入案例代码下载网页,观察下载网页源代码,文件下载链接代码如下(已简化):
<a class="reference download internal" download="" href="../../_downloads/79cca01aa25ff65b23b051f7e4ca55f5/linestyles.py"></a>
编写下面的XPath表达式即可提取文件下载URL:
//a[@class='reference download internal']/@href
3、 定义Item数据容器
项目目标主要是下载matplotlib网站的源代码,不需要存储爬取的数据。因此只需要在Item类定义下载文件必须的数据项即可。
在PyCharm编辑items.py文件,定义file_urls和files数据项。编辑代码如下:
import scrapy class MatplotlibItem(scrapy.Item): # 案例分类 catalog = scrapy.Field() # 定义file_urls数据项,存储源代码文件URL路径 file_urls = scrapy.Field() # 定义files数据项,存储源代码下载路径 files = scrapy.Field()
4、 定义文件下载管道类
Scrapy专门提供了一个用于下载文件的管道类FilesPipeline类,该管道类提供了file_path()、get_media_requests()、item_completed()三个重写方法,可以设置源代码文件存储路径、过滤准备要下载的源代码文件URL、对下载完成的源代码文件进一步处理。三个重写方法的使用参见《4..1. 下载网页图片》一节。
在爬虫matplotlib包目录下,编辑pipelines.py文件,代码如下:
# 导入os模块
import os
# 导入scrapy
import scrapy
# 导入适配器
from itemadapter import ItemAdapter
# 导入urlparse模块
from urllib.parse import urlparse
# 导入ImagesPipeline模块
from scrapy.pipelines.files import FilesPipeline
# 导入Scrapy异常处理模块
from scrapy.exceptions import DropItem
class MatplotlibPipeline(FilesPipeline):
# 设置源代码文件存储路径
def file_path(self, request, response=None, info=None):
# 从request对象的meta字典获取Item数据项
item = request.meta.get('item')
# 获取catalog数据项,该数据项存储了案例类别
catalog = item['catalog']
filename = os.path.basename(urlparse(request.url).path)
return '%s/%s' % (catalog,filename)
# 设置需要下载的图片URL,并返回图片request
def get_media_requests(self, item, info):
# 遍历file_urls数据项,为每个图片URL生成request请求
for file_url in item['file_urls']:
# 设置meta字典,传递Item数据项
yield scrapy.Request(file_url,meta={'item': item})
# 存储图片下载路径
def item_completed(self, results, item, info):
# result是一个包含元组的列表
# 元组包含两个值,第一个代表状态True/False,
# 第二个值是一个dict对象,若元素中状态为True则取dict中的path值
file_paths = [x['path'] for ok, x in results if ok]
# 若image_paths为空,说明下载失败
# 抛出DropItem异常
if not file_paths:
raise DropItem("文件下载失败")
# 获取Item的适配器
adapter = ItemAdapter(item)
# 存储image_paths
adapter['files'] = file_paths
return item5、 修改配置文件
修改配置文件,添加管道类配置项和文件存储路径配置项。
(1)添加管道类配置项
ITEM_PIPELINES = {
'matplotlib.pipelines.MatplotlibPipeline': 300,
}在配置文件中该配置项已经存在,只需要把语句前面的注释符去掉就可以。
(2)添加文件存储路径配置项
爬虫需要从配置文件读取下载文件的存储路径,在配置文件的尾部添加文件存储路径配置项:
# 下载文件存储路径配置项 FILES_STORE = os.path.join(os.path.dirname(os.path.dirname(__file__)),"source")
该配置项使用了os模块,因此需要在配置文件头部导入os模块。下载文件存储路径设置为爬虫项目目录下的source,source目录爬虫会自动创建。
6、 编辑爬虫文件
修改SpiderMatplotlibSpider爬虫类,代码如下:
import scrapy
from matplotlib.items import MatplotlibItem
class SpiderMatplotlibSpider(scrapy.Spider):
name = 'spider_matplotlib'
allowed_domains = ['www.matplotlib.org']
start_urls = ['https://www.matplotlib.org/gallery/index.html']
def parse(self, response):
# 获取爬取下来的网页代码
html = response.text
# 提取案例代码网页链接
source_link = response.xpath("//a[contains(@href,'-py')]/@href").extract()
# 处理提取的案例代码网页链接
for link in source_link:
# 获取link的绝对URL
url = response.urljoin(link)
# 发送request请求
request = scrapy.Request(url, callback=self.parse_source_link, dont_filter=True)
yield request
# 处理案例代码网页
def parse_source_link(self, response):
#实例化MatplotlibItem对象
item = MatplotlibItem()
# 从URL提取案例分类
catalog = response.url.split('/')[-2]
# 赋值Item类的catalog数据项
item["catalog"] = catalog
# 提取文件下载URL
down_link = response.xpath("//a[@class='reference download internal']/@href").extract()
# 相对URL转换为绝对URL
item["file_urls"] = [response.urljoin(link) for link in down_link]
# 使用yield语句返回item给parse的调用者
yield itemparse()方法用于提取index.html所有案例网页URL,对每个案例网页URL发送request请求。
parse_source_link()方法解析案例网页,提取案例分类和文件下载URL,并创建Item实例对象进行后续处理。
7、 运行爬虫
在PyCharm环境中,若编写py文件来运行爬虫程序,PyCharm可能不识别Scrapy命令。
具体运行方法:
(1)在PyCharm环境中,打开终端窗口,在终端窗口将当前工作目录切换到爬虫项目目录(课程案例是在D盘splider目录下):
D:\splider\matplotlib\matplotlib>
(2)输入Scrapy运行爬虫命令:
scrapy crawl spider_matplotlib -o items.json
爬虫运行完成后,会将下载文件存储到爬虫项目目录下的source目录,在source目录内建立分类目录,分类目录是下载的文件。
项目全部代码见课程资源(unit4\ matplotlib)。