社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

用Python将word文件转换成html

Python中文社区 • 7 年前 • 1081 次点击  

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

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

当然,万里长征的第一步是把文章导入我们的数据库。项目使用的是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. ├── imgs

  3. ├── inddfiles

  4. ├── output

  5. └── pdfs

  6. └── 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. guidUrl = "https://my.phrplus.com/REST/guid"

  11. inputPath = '/Users/admin/cwell/parser/docfiles/'

  12. imgPath = "/Users/admin/cwell/parser/imgs/"

  13. 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. def parseFile(f):

  13.    document = Document(inputPath+f)

  14.    article = {"Title":document.core_properties.title,"Content":""}

  15.    with open(inputPath+ f,"rb") as docFile:

  16.        html = mammoth.convert_to_html(docFile,style_map=styleMap,convert_image=mammoth.images.img_element(convert_image))

  17.        decoded = unidecode.unidecode(html.value)

  18.    if not article["Title"]:

  19.        for para in document.paragraphs:

  20.            if para.style.name == 'Title':

  21.                if para.text:

  22.                    article["Title"] = para.text

  23.    article["Content" ]=decoded

  24.    return article  

parseFile就是核心功能了。传递进来的参数f是文件名,和文件路径合在一起能够帮我们准确定位要转化的文件。首先用docx找到文档的标题,并创建一个dictionary,里面包含标题和内容。然后用mammoth转化整个文件。注意命令中要用到stylemap和convertimage。前者用来规定转化规则:'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(")

  9.            for idx, section in enumerate(contentArr):

  10.                for info in imgNameArr:

  11.                    if idx is info["index"]:

  12.                        contentArr[idx] = section+ ""</span><span class="pun" style="box-sizing: border-box;color: rgb(230, 233, 237);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">+</span><span class="pln" style="box-sizing: border-box;color: rgb(230, 233, 237);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">info</span><span class="pun" style="box-sizing: border-box;color: rgb(230, 233, 237);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">[</span><span class="str" style="box-sizing: border-box;color: rgb(255, 206, 84);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">"fileName"</span><span class="pun" style="box-sizing: border-box;color: rgb(230, 233, 237);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">]+</span><span class="str" style="box-sizing: border-box;color: rgb(255, 206, 84);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">"

  13.            article["Content"] = ''.join(contentArr)

  14.            result.append(article)

  15.    with open(outputFile,'w+') as f:

  16.        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

本文作者

栗子君

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

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


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/BMxS53eWbv
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/5127
 
1081 次点击