用Python将word文件转换成html

火山方舟向量数据库云通信

picture.image

最近公司一个客户大大购买了一堆医疗健康方面的科普文章,希望能放到我们正在开发的健康档案管理软件上。客户大大说,要智能推送!要掌握节奏!要深度学习!要让用户留恋网站无法自拔!

话说符合以上特点的我也只能联想到某榴了。

当然,万里长征的第一步是把文章导入我们的数据库。项目使用的是AWS的dynamoDB,是非关系型数据库,所有内容都是以json的形式储存的。而客户大大购买来的文章,一共600多篇,要么是word要么是Adobe indesign的indd。找了一圈,没有发现合适的应用可以把word或indd转化成干净的html。所以我只能自己造轮子啦~听说python很擅长文本处理,所以就是你了,python!这是我第一次用python写项目,不符合规范的地方欢迎大神提点。

太长不看

用逆天的python 模块mammoth和docx 处理你的word文件;把indd批量转化成pdf然后用layout_scanner转化成html。

word批量转化为html

1、 建立文件结构并批量读取文件

在根目录下创建几个文件夹,用来放不同格式的文件,我把所有要处理的word文件放在docfiles 这个子目录里。word.py里写转化程序。


      1. `├── docfiles`
2. 
3. `├── imgs`
4. 
5. `├── inddfiles`
6. 
7. `├── output`
8. 
9. `└── pdfs`
10. 
11. `└── word.py`


    

2、引入模块和申明文件路径


      1. `import mammoth`
2. `import mammoth.transforms`
3. `import os`
4. `from docx import Document`
5. `from bson import json_util`
6. `import zipfile`
7. `import json`
8. `import unidecode`
9. `import requests`
10. 
11. `guidUrl = "https://my.phrplus.com/REST/guid"`
12. `inputPath = '/Users/admin/cwell/parser/docfiles/'`
13. `imgPath = "/Users/admin/cwell/parser/imgs/"`
14. `outputFile = '/Users/admin/cwell/parser/output/output.json'`


    

mammoth: 核心组件,用来做转化工作

docx: 另一个做转化工作的模块,用来补充mammoth

os: 用来在系统中读取写入文件

zipfile: 用来解压word文档以提取图片

json: 用来把数据转化成json

bson: 用来配置写入json文件

unicode:用来处理字符

requests:用来调用api

3、转换单个文件


      1. `styleMap = """`
2. `p[style-name='Title'] => h1.hide`
3. `p[style-name='Subhead 1'] => h3`
4. `p[style-name='List Bullet'] => ul.first > li:fresh`
5. `p[style-name='List Bullet 2'] => ul.second > li:fresh`
6. `p[style-name='Hyperlink']=>a.link`
7. `"""`
8. `def convert_image(image):`
9. `return {`
10. `"src":""`
11. `}`
12. 
13. `def parseFile(f):`
14. `document = Document(inputPath+f)`
15. `article = {"Title":document.core_properties.title,"Content":""}`
16. `with open(inputPath+f,"rb") as docFile:`
17. `html = mammoth.convert_to_html(docFile,style_map=styleMap,convert_image=mammoth.images.img_element(convert_image))`
18. `decoded = unidecode.unidecode(html.value)`
19. 
20. 
21. `if not article["Title"]:`
22. `for para in document.paragraphs:`
23. `if para.style.name == 'Title':`
24. `if para.text:`
25. `article["Title"] = para.text`
26. 
27. `article["Content"]=decoded`
28. `return article`


    

parseFile就是核心功能了。传递进来的参数f是文件名,和文件路径合在一起能够帮我们准确定位要转化的文件。首先用docx找到文档的标题,并创建一个dictionary,里面包含标题和内容。然后用mammoth转化整个文件。注意命令中要用到style map和convert image。前者用来规定转化规则:'style-name'是word里的式样名称,用word打开文档,点击任意一个元素可以查看其式样名称;这里规定标题转化为h1,副标题转化为h2等等。关于列表的转化规则这里就不详细叙述了,具体可以参考下面的文章:

参考链接


      1. `Converting
  docx to clean HTML
 :
  handling the XML structure mismatch`


    

'convert_image' 是用来规定图片的转化方式的,由于我准备之后批处理所有文档中的图片,在这里就告诉程序不储存任何图片信息。但是于此同时保留图片的img tag以便标注图片在文档中的位置。如果不规定任何转化方式,生成的html里面会包含一大长串base64的图片信息。

mammoth转化出来的html是含有unicode的,不知道为什么python里跑一直报错,就用unicode解码了一下。

这之后,如果前面的程序没有抓取到文档标题,用docx换个姿势再抓取一下。

最后返回article这个dictionary。

4、抓取图片


      1. `def extractImage(f):`
2. `ziped = zipfile.ZipFile(inputPath+f)`
3. `allFiles = ziped.namelist()`
4. `imgs = filter(lambda x: x.startswith('word/media/'), allFiles)`
5. `imgNameArr = []`
6. `for img in imgs:`
7. `res = requests.post(guidUrl)`
8. `if res.status_code is 200:`
9. `guid = res.text`
10. `data = ziped.read(img,imgPath)`
11. `idxStr = os.path.basename(img).split(".")[0][-1:]`
12. `imgDict = {}`
13. `imgDict["index"] = int(idxStr)-1`
14. `imgDict["fileName"] = guid+".jpg"`
15. `imgNameArr.append(imgDict)`
16. `targetPath = os.path.join(imgPath,guid+".jpg")`
17. `target = open(targetPath,"wb")`
18. `target.write(data)`
19. `target.close()`
20. `ziped.close()`
21. `return imgNameArr`


    

没想到word文档其实是一个压缩文件吧?如果直接把word文档的后缀名改成zip然后再用解压软件查看,会看到一个media文件夹,里面就包含所有插入的图片。

用ziped读取文档,然后找到存放图片的media文件夹,每一个图片重新用guid命名,生成一个dictionary,里面包含的信息有“此图片在文档中出现的顺序”和文件名。话说media中的图片都被按照顺序重新命名为image1.png, image2.png,刚好为我们抓取顺序信息提供了方便。

(python也有生成guid的模块,我在这里调用api有点多此一举,但是为了和项目中其他图片需要用到的uuidv4保持一致还是用了)

之后就是把图片存在‘imgs’这个文件夹下。

5、生成json


      1. `def processDocs(path):`
2. `result = []`
3. `for f in os.listdir(path):`
4. `if not f.startswith('.'):`
5. `imgNameArr = extractImage(f)`
6. `article = parseFile(f)`
7. `fileName = os.path.basename(f)`
8. `contentArr = article["Content"].split("<img")`
9. `for idx, section in enumerate(contentArr):`
10. `for info in imgNameArr:`
11. `if idx is info["index"]:`
12. `contentArr[idx] = section+"<img alt='"+info["fileName"]+"' data-fileName='"+info["fileName"]+"'"`
13. 
14. `article["Content"] = ''.join(contentArr)`
15. `result.append(article)`
16. 
17. 
18. `with open(outputFile,'w+') as f:`
19. `json.dump(result,f,default=json_util.default)`


    

最后要用到的一个function就是写个循环挨个处理docfiles文件夹底下的文件了。针对每一个文件,记得把之前生成的图片信息的数组map到html里,然后在写入到json文件里就大功告成了!

indd转化为html

话说,到现在为止,我还没有找到一个完美的解决方案。我使用了相同的思路,把indd先批量生成为pdf(有一个indesign 脚本就是专门批量转化pdf的),然后用了一个叫做layout_scanner的github项目抓取pdf信息并转化为html。最后生成的html包含了文字和图片,但是图标和排版就保存不下来了。客户大大表示不满意。我也很惆怅啊!机智的小伙伴们如果有更好的思路请务必告诉我!如果需要我详细说明一下这一块内容,我会更新在这篇文章中。

参考链接


      1. `dpapathanasiou/pdfminer-layout-scanner`


    

本文作者

picture.image

栗子君

Python中文社区专栏作者,一枚身在美帝的小程序媛,爱好:Web开发/古典吉他。

picture.image

点击 阅读原文 进入作者个人博客

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
云原生环境下的日志采集存储分析实践
云原生场景下,日志数据的规模和种类剧增,日志采集、加工、分析的多样性也大大增加。面对这些挑战,火山引擎基于超大规模下的 Kubernetes 日志实践孵化出了一套完整的日志采集、加工、查询、分析、消费的平台。本次主要分享了火山引擎云原生日志平台的相关实践。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论