Python:读取 .doc、.docx 两种 Word 文件简述及“Word 未能引发事件”错误

Python 中可以读取 word 文件的库有 python-docx 和 pywin32。

优点缺点

python-docx跨平台只能处理 .docx 格式,不能处理.doc格式

pywin32仅限 windows 平台.doc 和 .docx 都能处理

本人对于Python学习创建了一个小小的学习圈子,为各位提供了一个平台,大家一起来讨论学习Python。欢迎各位到来Python学习群:960410445一起讨论视频分享学习。Python是未来的发展方向,正在挑战我们的分析能力及对世界的认知方式,因此,我们与时俱进,迎接变化,并不断的成长,掌握Python核心技术,才是掌握真正的价值所在。

pywin32

这个库很强大,不仅仅可以读取 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 来处理了。

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

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 未能引发事件

我的爬虫在爬取到 .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下面,单个文件名的长度限制是255,完整的路径长度(如 E:\abc\test.doc)这样限制是260,一个汉字占2个字符。

路径最后有一个字符串结束符 '\0' 要占掉一个字符,所以完整路径实际限长是259。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • # Awesome Python [![Awesome](https://cdn.rawgit.com/sindr...
    emily_007阅读 2,227评论 0 3
  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,238评论 4 16
  • 四月份来上海找工作的时候,仅仅面试一次就面上了,面试结束就发了Offer,通知下午或第二天去上班,当时并没觉得有什...
    迎着小风尿尿阅读 366评论 0 0
  • 3D:transform-style:preserve-3d.transform-style默认属性值为flat ...
    马尔斯阅读 120评论 0 0
  • 又到周末了。我知道,周末是你们团聚的日子。也许平时你还会想起我来,可是周末的时候,你肯定是顾不上我的。不过,周末的...
    绿水朱楼阅读 209评论 0 0