04-磁盘缓存
[toc]
3.3 磁盘缓存
要想缓存下载结果,我们先来尝试最容易想到的方案,将下载到的网页存储到文件系统中。为了实现该功能,我们需要将URL安全地映射为跨平台的文件名。表3.1所示为几大主流文件系统的限制。
| 操作系统 | 文件系统 | 非法文件名字符 | 文件名最大长度 | | :----- | :----- | :----- | :----- | :----- | :----- | | Linux | Ext3/Ext4 | / 和 \0 | 255字节 | | OS X | HFS Plus | : 和 \0 | 255个UTF-16编码单元 | | Windows | NTFS | \、/、?、:、*、"、>、<和 | | 255个字符 |
为了保证在不同文件系统中,我们的文件路径都是安全的,就需要限制其只能包含数字、字母和基本符号,并将其他字符替换为下划线,其实现代码如下所示。
>>> import re
>>> url = 'http://example.python-scraping.com/default/view/Australia-1'
>>> re.sub('[^/0-9a-zA-Z\-.,;_ ]', '_', url)
'http_//example.python-scraping.com/default/view/Australia-1'
此外,文件名及其父目录的长度需要限制在255个字符以内(实现代码如下),以满足表3.1中给出的长度限制。
>>> filename = re.sub('[^/0-9a-zA-Z\-.,;_ ]', '_', url)
>>> filename = '/'.join(segment[:255] for segment in filename.split('/'))
>>> print(filename)
'http_//example.python-scraping.com/default/view/Australia-1'
由于这里的URL部分没有超过255个字符,因此文件路径不需要改变。还有一种边界情况需要考虑,那就是URL路径可能会以斜杠(/)结尾,此时斜杠后面的空字符串就会成为一个非法的文件名。但是,如果移除这个斜杠,使用其父字符串作为文件名,又会造成无法保存其他URL的问题。考虑下面这两个URL:
http://example.python-scraping.com/index/http://example.python-scraping.com/index/1
如果我们希望这两个URL都能保存下来,就需要以 index 作为目录名,以文件名1作为子页面。对于像第一个URL路径这样以斜杠结尾的情况,这里使用的解决方案是添加 index.html 作为其文件名。同样地,当URL路径为空时也需要进行相同的操作。为了解析URL,我们需要使用 urlsplit 函数,将URL分割成几个部分。
>>> from urllib.parse import urlsplit
>>> components = urlsplit('http://example.python-scraping.com/index/')
>>> print(components)
SplitResult(scheme='http', netloc='example.python-scraping.com',
path='/index/', query='', fragment='')
>>> print(components.path)
'/index/'
该函数提供了解析和处理URL的便捷接口。下面是使用该模块对上述边界情况添加 index.html 的示例代码。
>>> path = components.path
>>> if not path:
>>> path = '/index.html'
>>> elif path.endswith('/'):
>>> path += 'index.html'
>>> filename = components.netloc + path + components.query
>>> filename
'example.python-scraping.com/index/index.html'
根据所抓取网站的不同,可能需要修改边界情况处理功能。比如,由于Web服务器有其期望的URL传输方式,一些站点会在每个URL后添加/。对于这些站点,你可能只需要去除每个URL尾部的斜杠即可。再次重申,你需要评估并更新网络爬虫的代码,以最佳适应想要抓取的网站。