虽然互联网在20世纪60年代末期就已经以不同的形式出现,但是HTML直到1992年才问世。在此之前,互联网基本上就是收发邮件和传输文件;今天看到的网页的概念那时还没有。总之,互联网并不是一个HTML页面的集合。它是一个信息集合,而HTML文件只是展示信息的一个框架而已。如果我们的爬虫不能读取其他类型的文件,包括纯文本、PDF、图像、视频、邮件等,我们将会失去很大一部分数据。
6.1 文档编码
文件格式
6.2 纯文本
from urllib.request import urlopen
textPage = urlopen("http://www.pythonscraping.com/pages/warandpeace/chapter1.txt")
print(textPage.read())
在UTF8设计过程中,设计师决定利用ASCII文档里的“填充位”,让所有以“0”开头的字节表示这个字符只用1个字节,从而把ASCII和UTF-8编码完美地结合在一起。
一个常见的误解是UTF-8把所有字符都存储成8位。其实“8位“只是显示一个字符需要的最小位数,而不是最大位数,一个字符最多可以是四个字符。
除了UTF-8,还有UTF-16、UTF-24、UTF-32,不过很少用这些编码标准对文件进行编码。
显然,Unicode标准也有问题,就是任何一种非英文语言文档的体积都比ASCII编码的体积大。
ISO标准解决这个问题的办法是为每种语言创建一种编码。目前仍有约9%的网站使用ISO编码,所以有必要做基本的了解,并在采集网站之前需要检查是否使用了这种编码方法。
Python默认把文本读成ASCII编码格式,而浏览器把文本读成ISO-8859-1编码格式。
print(str(textPage.read(), 'utf-8'))
6.3 CSV
读取CSV文件:Python的CSV库主要是面向本地文件。
from urllib.request import urlopen
from io import StringIO
import csv
data = urlopen("http://pythonscraping.com/files/MontyPythonAlbums.csv").read().decode('ascii', 'ignore')
dataFile = StringIO(data)
csvReader = csv.reader(dataFile)
for row in csvReader:
print(row)
dictReader = csv.DictReader(dataFile)
print(dictReader.fieldnames)
6.4 PDF
Adobe在1993年发明PDF格式(Portable Document Format,便携式文档格式)是一种技术革命。PDF可以让用户在不同的系统上用同样的方式查看图片和文本文档,无论这些文件是在哪种系统上制作的。
虽然把PDF显示在网页上已经有点儿过时了(你已经可以把内容显示成HTML了,为什么还要用这种静态、加载速度超慢的格式呢?),但是PDF仍然无处不在,尤其是在处理商务报表和表单的时候。
不过目前很多PDF解析库都是用Python 2.x版本建立的,还没有迁移到Python 3.x版本。但是,因为PDF比较简单,而且是开源的文档格式,所以有一些给力的Python库可以读取PDF文件,而且支持Python 3.x版本。
PDFMiner3K就是一个非常好用的库。
pip install pdfminer
from urllib.request import urlopen
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from io import StringIO
from io import open
def readPDF(pdfFile):
rsrcmgr = PDFResourceManager()
retstr = StringIO()
laparams = LAParams()
device = TextConverter(rsrcmgr, retstr, laparams=laparams)
process_pdf(rsrcmgr, device, pdfFile)
device.close()
content = retstr.getvalue()
retstr.close()
return content
pdfFile = urlopen("http://pythonscraping.com/pages/warandpeace/chapter1.pdf")
outputString = readPDF(pdfFile)
print(outputString)
pdfFile.close()
6.5 微软Word和.docx
Word文件从未打算让人频繁传递。不过它们在一些网站上很流行,包括重要的文档、信息,甚至图表和多媒体;总之,那些内容都应该用HTML代替。
大约在2008年以前,.doc文件格式。这种二进制格式很难读取,而且能够读取word格式的软件很少。为了跟上时代,微软决定使用Open Office类的XML格式标准,此后新版Word文件才与其他文字处理软件兼容,这个格式就是.docx
不过Python对这种.docx格式的支持还不够好。虽然有python-docx库,不支持正文读取。我们需要自己动手找方法。
# -*- coding: utf-8 -*-
from zipfile import ZipFile
from urllib.request import urlopen
from io import BytesIO
# 第一步是从文件读取XML
wordFile = urlopen("http://pythonscraping.com/pages/AWordDocument.docx").read()
wordFile = BytesIO(wordFile)
# 这段代码把一个远程Word文档读成一个二进制文件对象( BytesIO与本章之前用的StringIO 类似),
# 再用 Python 的标准库 zipfile 解压(所有的 .docx 文件为了节省空间都进行过压缩),
# 然后读取这个解压文件,就变成 XML
document = ZipFile(wordFile)
xml_content = document.read('word/document.xml')
print(xml_content.decode('utf-8'))
#
# -*- coding: utf-8 -*-
from zipfile import ZipFile
from urllib.request import urlopen
from io import BytesIO
from bs4 import BeautifulSoup
# 第一步是从文件读取XML
wordFile = urlopen("http://pythonscraping.com/pages/AWordDocument.docx").read()
wordFile = BytesIO(wordFile)
# 这段代码把一个远程Word文档读成一个二进制文件对象( BytesIO与本章之前用的StringIO 类似),
# 再用 Python 的标准库 zipfile 解压(所有的 .docx 文件为了节省空间都进行过压缩),
# 然后读取这个解压文件,就变成 XML
document = ZipFile(wordFile)
xml_content = document.read('word/document.xml')
#print(xml_content.decode('utf-8'))
# 正文包含在<w:t> </w:t>标签中
wordObj = BeautifulSoup(xml_content.decode('utf-8'))
textStrings = wordObj.findAll("w:t")
# print(textStrings)
for textElem in textStrings:
print(textElem.text)