天天看點

Python:讀取 .doc、.docx

概述

Python 中可以讀取 word 檔案的庫有 python-docx 和 pywin32。

下表比較了各自的優缺點。

優點 缺點
python-docx 跨平台 隻能處理 .docx 格式,不能處理.doc格式
pywin32 僅限 windows 平台 .doc 和 .docx 都能處理

pywin32

這個庫很強大,不僅僅可以讀取 word,本文僅介紹其讀取 word 功能。網上介紹用 pywin32 讀取 .doc 的文章真不多,因為,真心不好用。

以下是 pywin32 讀取 .doc 的代碼示例,但是讀取表格有問題,輸出全是空,原因不明,因為不打算用是以沒有深入研究。另外,如果表格中有縱向合并單元格,會報錯:“無法通路此集合中單獨的行,因為表格有縱向合并的單元格。”

from win32com.client import Dispatch

word = Dispatch('Word.Application')     # 打開word應用程式
# word = DispatchEx('Word.Application') # 啟動獨立的程序
word.Visible = 0        # 背景運作,不顯示
word.DisplayAlerts = 0  # 不警告

path = r'E:\abc\test.doc'
doc = word.Documents.Open(FileName=path, Encoding='gbk')

for para in doc.paragraphs:
    print(para.Range.Text)

for t in doc.Tables:
    for row in t.Rows:
        for cell in row.Cells:
            print(cell.Range.Text)

doc.Close()
word.Quit           

複制

但是 pywin32 有另外一個功能,就是将 .doc 格式另存為 .docx 格式,這樣我們就可以使用 python-docx 來處理了。

# 将 .doc 檔案轉成 .docx 
def doc2docx(path):
    w = win32com.client.Dispatch('Word.Application')
    w.Visible = 0
    w.DisplayAlerts = 0
    doc = w.Documents.Open(path)
    newpath = os.path.splitext(path)[0] + '.docx'
    doc.SaveAs(newpath, 12, False, "", True, "", False, False, False, False)
    doc.Close()
    w.Quit()
    os.remove(path)
    return newpath           

複制

python-docx

python-docx 可以按段落讀取 word,對于表格,可以單獨的提取,代碼如下:

import docx

fn = r'E:\abc\test.docx'
doc = docx.Document(fn)

for paragraph in doc.paragraphs:
        print(paragraph.text)

for table in doc.tables:
    for row in table.rows:
        for cell in row.cells:
            print(cell.text)           

複制

對于縱向合并單元格,python-docx 的處理也很貼心。看下面的截圖:

word 表格截圖:

Python:讀取 .doc、.docx

代碼運作結果截圖:

Python:讀取 .doc、.docx
綜上所述,對于大批量 word 檔案的讀取,我建議使用 python-docx 庫,若是 .doc 檔案,則用 pywin32 庫将其轉化為 .docx 檔案,然後再調用 python-docx 庫讀取。

Word 未能引發事件

這是我遇到的一個實際問題,困擾了我半天時間。

我的爬蟲在爬取到 .doc 檔案之後,就通過上面的方法将其轉為 .docx 格式,原本一切都好,下班挂機在跑,第二天來一看,報了這個錯:pywintypes.com_error: (-2147352567, '發生意外。', (0, 'Microsoft Word', 'Word 未能引發事件。', 'D:\工具\Microsoft Office\Office12\2052\WDMAIN11.CHM', 25482, -2146822286), None)

Python:讀取 .doc、.docx

我用報錯的檔案單獨調試了

doc2docx

方法,并沒有報錯。網上查了這個錯誤,沒有啥收獲。

反複測試後發現總是那個網頁報錯,說明 bug 可以重制,那麼問題到底出在哪裡?

我将代碼一行行删去,直到隻留下執行到報錯所必須的代碼:

def get_winningbid_detail(url, name):
    r = requests.get(url)
    r.encoding = 'utf-8'
    html = r.text
    soup = BeautifulSoup(html, 'lxml')

    ps = soup.find_all(text=re.compile('附件'))
    if len(ps) > 0:
        os.makedirs(os.path.join(download_dir, name), exist_ok=True)
        for p in ps:
            a_tab = p.find_next_sibling('a')
            if a_tab is not None:
                link = homepage + a_tab['href']
                localfilename = os.path.join(download_dir, name, a_tab.text)
                # print(localfilename)
                with open(localfilename, 'wb+') as sw:
                    sw.write(requests.get(link).content)
                if localfilename.endswith('.doc'):
                    doc2docx(localfilename)           

複制

反複讀這段代碼,并沒有發現什麼問題。

因為有些網頁的附件名稱是相同的,例如 "公告.doc",是以我按每個網頁的标題(在總覽頁面爬到的)分檔案夾放置下載下傳的檔案,是以方法中傳了一個

name

參數,而如果

name

參數傳空,則不會報錯。

其實由此已經可以發現 bug 所在了,但我卻沒想到,又反複折騰了很久才發現,原來是檔案名太長了。

在 windows 下面,單個檔案名的長度限制是 25,完整的路徑長度(如 E:\abc\test.doc )限制是 260。路徑最後有一個字元串結束符 '\0' 要占掉一個字元,是以完整路徑實際限長是259。**