Python:读取 .doc、.docx 两种 Word 文件简述及“Word 未能引发事件”错误
概述
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 表格截图:

综上所述,对于大批量 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)
我用报错的文件单独调试了 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。**
Python:读取 .doc、.docx 两种 Word 文件简述及“Word 未能引发事件”错误的更多相关文章
- 简介C#读取XML的两种方式
简介C#读取XML的两种方式 作者: 字体:[增加 减小] 类型:转载 时间:2013-03-03 在程序中访问进而操作XML文件一般有两种模型,分别是使用DOM(文档对象模型)和流模型,使用DOM的 ...
- day2 编程语言介绍、Python运行程序的两种方式、变量
一 编程语言介绍 1. 机器语言 用计算机能理解的二进制指令直接编写程序,直接控制硬件 2. 汇编语言 用英文标签取代二进制指令编写程序,本质也是直接控制硬件 3. 高级语言 用人能理解的表达方式去编 ...
- python读取与写入csv,txt格式文件
python读取与写入csv,txt格式文件 在数据分析中经常需要从csv格式的文件中存取数据以及将数据写书到csv文件中.将csv文件中的数据直接读取为dict类型和DataFrame是非常方便也很 ...
- 用Python计算幂的两种方法,非递归和递归法
用Python计算幂的两种方法: #coding:utf-8 #计算幂的两种方法.py #1.常规方法利用函数 #不使用递归计算幂的方法 """ def power(x, ...
- Python实现屏幕截图的两种方式
Python实现屏幕截图的两种方式 使用windows API 使用PIL中的ImageGrab模块 下面对两者的特点和用法进行详细解释. 一.Python调用windows API实现屏幕截图 好处 ...
- Python 输出百分比的两种方式
Python 输出百分比的两种方式 注: 在python3环境下测试. 方式1:直接使用参数格式化:{:.2%} {:.2%}: 显示小数点后2位 显示小数点后2位: >>> pri ...
- Python 下JSON的两种编解码方式实例解析
概念 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写.在日常的工作中,应用范围极其广泛.这里就介绍python下它的两种编解码方法: ...
- Git 的两种忽略文件方式 gitignore 和 exclude
Git 的两种忽略文件方式 gitignore 和 exclude .gitignore 不用说了,大家都知道. 有一个 exclude 可能接触比较少. 知道这个功能后发现,用在服务器上非常方便,因 ...
- Python 发送 email 的两种方式
Python发送email的两种方式,分别为使用登录邮件服务器.调用sendmail命令来发送三种方法 Python发送email比较简单,可以通过登录邮件服务来发送,linux下也可以使用调用sen ...
随机推荐
- Solr(六)Solr索引数据存放到HDFS下
Solr索引数据存放到HDFS下 一 新建solr core hdfs 方法:http://www.cnblogs.com/Matchman/p/7287385.html 二 修改solrconfig ...
- Hive中Join的原理和机制
转自:http://lxw1234.com/archives/2015/06/313.htm 笼统的说,Hive中的Join可分为Common Join(Reduce阶段完成join)和Map Joi ...
- C#之Redis所欲为
一 Redis是一种支持多种数据结构的键值对数据库 1.1Redis下载地址 :https://github.com/MicrosoftArchive/Redis 建议下载 .msi结尾的应用程序进行 ...
- Selenium自动化测试-unittest单元测试框架
一.Pyhon工作原理-- 核心概念:test case, testsuite, TestLoder,TextTestRunner,TextTestResult, test fixture TestC ...
- popup_layer插件示例
导入popup_layer.js插件 设置好显示的div: <div class="main" id="showImg" style="disp ...
- redis两种持久化方法对比分析
1.前言 最近在项目中使用到Redis做缓存,方便多个业务进程之间共享数据.由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能, ...
- SQL关于IN和EXISTS的用法和区别的比较
1.exist,not exist一般都是与子查询一起使用. In可以与子查询一起使用,也可以直接in (a,b.....).2.exist会针对子查询的表使用索引. not exist会对主子查询都 ...
- springboot+activemq中引入重发机制
一.简介 在使用activemq消息中间件进行消息队列传输时,总会由于各种原因导致消息失败. 一个经典的场景是一个生成者向Queue中发消息,里面包含了一组邮件地址和邮件内容.而消费者从Queue中将 ...
- Java NIO Channel to Channel Transfers通道传输接口
原文链接:http://tutorials.jenkov.com/java-nio/channel-to-channel-transfers.html 在Java NIO中如果一个channel是Fi ...
- asp.net mvc 使用 Autocomplete 实现类似百度,谷歌动态搜索条提示框。
Autocomplete是一个Jquery的控件,用法比较简单. 大家先看下效果: 当文本框中输入内容,自动检索数据库给出下拉框进行提示功能. 需要用此控件大家先到它的官方网站进行下载最新版本: ht ...