上一期我們講解了使用 Python 讀取文檔編碼的相關問題,本期我們講解使用 Python 處理 CSV、PDF、Word 文檔相關內容。
CSV
我們進行網頁采集的時候,你可能會遇到 CSV 文件,也可能項目需要將數據保存到 CSV 文件。Python 有一個超贊的標准庫可以讀寫 CSV 文件。雖然這個庫可以處理各種 CSV 文件,但是我們這里重點介紹標准 CSV 格式。
讀取 CSV 文件
Python 的 CSV 主要是面向本地用戶,也就是說你的 CSV 文件得保存到你的電腦上。而經行網絡數據采集的時候,很多文件都是在線的。不過有一些方法可以解決這個問題:
-
手動把 CSV 文件下載到本機,然后用 Python 定位文件位置;
-
寫 Python 程序下載文件,讀取之后把源文件刪除;
-
從網上直接把文件讀取成一個字符串,然后轉換成一個 StringIO 對象,使它具有文件的屬性。
雖然前兩個方法也可以用,但是既然你可以輕易的把 CSV 文件保存到內存里,就不要下載到本地占用硬盤空間了。直接把文件讀取成字符串,然后封裝成 StringIO 對象,讓 Python 把他當作文件來處理,就不需要保存成文件了。下面的程序就是從網上獲取一個 CSV 文件,然后把每一行都打印到命令行里:
import requests
from io import StringIO
import csv
class ProcessCSVPDFDOCX(object):
def __init__(self):
self._csv_path = 'https://image.pdflibr.com/crawler/blog/country.CSV'
self._session = requests.Session()
def read_csv(self):
response = self._session.get(self._csv_path)
# 將文本設置成 utf-8 的編碼方式
response.encoding = 'utf-8'
response_text = response.text
data_file = StringIO(response_text)
dict_reader = csv.DictReader(data_file)
print(dict_reader.fieldnames)
for row in dict_reader:
print(row)
if __name__ == '__main__':
ProcessCSVPDFDOCX().read_csv()
csv.DictReader
會返回把 CSV 文件每一行轉化成 Python 的字典對象返回,而不是列表對象,並把字段列表保存到變量 dict_reader.fieldnames
里,字段同時作為字典對象的鍵。
從某種意義上來說, Adobe 在 1993 年發明 PDF 格式(Protable Document Format,便攜式文檔格式)是一種技術革命。PDF 可以讓用戶在不同系統上使用同樣的方式查看圖片和文本文檔,無論這種文件是在那種系統上制作的。
雖然把 PDF 顯示在網頁上已經過時了(你已經可以把內容顯示成 HTML 了,為什么還要這種靜態、加載速度超慢的格式呢?),但是 PDF 仍然無處不在,尤其是在處理商務報表和表單的時候。
目前很多 PDF 解析庫都是 Python 2.x 版本建立的,還沒有遷移到 Python 3.x 版本。但是,因為 PDF 比較簡單,而且開源的文檔格式,所以一些給力的 Python 可以讀取 PDF 文件,而且支持 Python 3.x 版本。
PDFMiner3K 就是一個非常好用的庫(是 PDFMiner 的 Python 3.x 移植版)。他非常靈活,可以通過命令行使用,也可以整合到代碼中。還可以處理不同的語言編碼,而且對網絡文件的處理也非常的方便。
你可以下載這個模塊的源文件(https://pypi.org/project/pdfminer3k/),解壓並用下面命令安裝:
python setup.py install
我們也可以使用 pip 的方式安裝:
pip install pdfminer3k
下面的例子可以把任意 PDF 讀成字符串,然后使用 StringIO 轉換成文件對象:
import requests
from io import StringIO
import csv
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.layout import LAParams
from pdfminer.converter import TextConverter
from urllib.request import urlopen
class ProcessCSVPDFDOCX(object):
def __init__(self):
self._session = requests.Session()
self._pdf_path = 'https://image.pdflibr.com/crawler/blog/markdown-cheatsheet-online.pdf'
def read_pdf(self, pdf_file):
rscmgr = PDFResourceManager()
retstr = StringIO()
laparames = LAParams()
device = TextConverter(rscmgr, retstr, laparams=laparames)
process_pdf(rscmgr, device, pdf_file)
device.close()
content = retstr.getvalue()
retstr.close()
return content
def read_pdf_main(self):
pdf_file = urlopen(self._pdf_path)
output_string = self.read_pdf(pdf_file)
print(output_string)
pdf_file.close()
if __name__ == '__main__':
ProcessCSVPDFDOCX().read_pdf_main()
readPDF 最大的好處是,如果你的 PDF 文件在電腦里,你就可以直接把 urlopen 返回的對象 pdf_file 換成普通的 open() 文件對象。
輸入的結果可能不是很完美,尤其是當文件中包含圖片、各種各樣的文本格式,或者帶有表格和數據圖的時候。但是,對於大多數只包含純文本內容的 PDF 而言,其輸出結果與純文本並沒有什么區別。
微軟 Word 和 .docx
網上有很多對 Word 吐槽的網友,Word 的特意功能就是把那些因該寫成簡單 TXT 或 PDF 格式的文件,變成了即大又慢且難以打開的怪獸,它們經常在系統切換和版本切換中出現格式不兼容,而且應為某些原因在文件內容已經定稿后仍處於可編輯狀態。Word 文檔從未打算讓人頻繁傳遞。不過他們在一些網站上很流行,包括重要的文檔、信息,甚至圖表和多媒體;總之,那些內容都應該使用 HTML 代替。
大約在 2008 年以前,微軟 Office 產品中 Word 用 .doc 文件格式。這種二進制格式很難讀取,而且能夠讀取 word 格式的軟件很少。為了跟上時代,讓自己的軟件符合主流軟件的標准,微軟決定使用 Open Office 的類 XML 格式標准,此后新版本 Word 才能與其他文字處理軟件兼容,這個格式就是 .docx
不過,Python 對這種 Google Docs、Open Office 和 Microsoft Office 都在使用的 .docx 格式支持還不夠好。雖然有一個 python-docx 庫,但是只支持創建和讀取一些基本的數據,入文件大小和文件標題,不支持正文讀取。如果想讀取 Microsoft Office 文件的正文內容,我們需要自己動手找方法。
第一步是從文件讀取 XML:
import requests
from io import StringIO
import csv
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.layout import LAParams
from pdfminer.converter import TextConverter
from urllib.request import urlopen
from io import open, BytesIO
from zipfile import ZipFile
class ProcessCSVPDFDOCX(object):
def __init__(self):
self._csv_path = 'https://image.pdflibr.com/crawler/blog/country.CSV'
self._session = requests.Session()
self._pdf_path = 'https://image.pdflibr.com/crawler/blog/markdown-cheatsheet-online.pdf'
self._docx_path = 'https://image.pdflibr.com/crawler/blog/test_document.docx'
def convert_docx_to_xml(self):
word_file = urlopen(self._docx_path).read()
word_file = BytesIO(word_file)
document = ZipFile(word_file)
xml_content = document.read('word/document.xml')
print(xml_content.decode('utf-8'))
if __name__ == '__main__':
ProcessCSVPDFDOCX().convert_docx_to_xml()
這段代碼把遠程 Word 讀取成一個二進制文件對象(BytesIO 與上面使用的 StringIO 類似),再使用 Python 的標准庫 zipfile 解壓(所有的 .docx 文件為了節省空間都進行了壓縮),然后對讀取這個解壓文件,就變成了 XML 了。
解壓后的 XML 文件包含了大量信息,好在所有的內容都包含在 <w:t>
標簽里面,標題內容也是如此,這樣就容易處理多了。
import requests
from io import StringIO
import csv
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.layout import LAParams
from pdfminer.converter import TextConverter
from urllib.request import urlopen
from io import open, BytesIO
from zipfile import ZipFile
from bs4 import BeautifulSoup
class ProcessCSVPDFDOCX(object):
def __init__(self):
self._csv_path = 'https://image.pdflibr.com/crawler/blog/country.CSV'
self._session = requests.Session()
self._pdf_path = 'https://image.pdflibr.com/crawler/blog/markdown-cheatsheet-online.pdf'
self._docx_path = 'https://image.pdflibr.com/crawler/blog/test_document.docx'
def convert_docx_to_xml(self):
word_file = urlopen(self._docx_path).read()
word_file = BytesIO(word_file)
document = ZipFile(word_file)
xml_content = document.read('word/document.xml')
print(xml_content.decode('utf-8'))
word_obj = BeautifulSoup(xml_content.decode('utf-8'), features="html.parser")
text_string = word_obj.findAll("w:t")
for text_ele in text_string:
print(text_ele.text)
if __name__ == '__main__':
ProcessCSVPDFDOCX().convert_docx_to_xml()
這段代碼顯示的結果可能並不完美,但是已經差不多了,一行打印一個 <w:t>
標簽。
總結
這篇文章主要講解了使用 Python 如何處理在線 CSV、PDF、Word 文檔,由於 docx 文檔並沒有很好的庫,如何曲線解析 docx 文件,通過這篇文章可以處理互聯網上大部分文檔內容。
這篇文章的所有源代碼已經托管於 Github: https://github.com/sycct/Scrape_1_1.git
如果有任何問題,歡迎大家 issue。