用Python将word文件转换成html

论坛 期权论坛 期权     
Python中文社区   2019-7-28 23:29   4570   0


最近公司一个客户大大购买了一堆医疗健康方面的科普文章,希望能放到我们正在开发的健康档案管理软件上。客户大大说,要智能推送!要掌握节奏!要深度学习!要让用户留恋网站无法自拔!
话说符合以上特点的我也只能联想到某榴了。
当然,万里长征的第一步是把文章导入我们的数据库。项目使用的是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
    复制代码
    1. [/code]
    2. [*][code]├── imgs
    复制代码
    1. [/code]
    2. [*][code]├── inddfiles
    复制代码
    1. [/code]
    2. [*][code]├── output
    复制代码
    1. [/code]
    2. [*][code]└── pdfs
    复制代码
    1. [/code]
    2. [*][code]└── word.py
    复制代码
2、引入模块和申明文件路径
    1. import mammoth
    复制代码
    1. import mammoth.transforms
    复制代码
    1. import os
    复制代码
    1. from docx import Document
    复制代码
    1. from bson import json_util
    复制代码
    1. import zipfile
    复制代码
    1. import json
    复制代码
    1. import unidecode
    复制代码
    1. import requests
    复制代码
    1. [/code]
    2. [*][code]guidUrl = "https://my.phrplus.com/REST/guid"
    复制代码
    1. inputPath = '/Users/admin/cwell/parser/docfiles/'
    复制代码
    1. imgPath = "/Users/admin/cwell/parser/imgs/"
    复制代码
    1. outputFile = '/Users/admin/cwell/parser/output/output.json'
    复制代码
mammoth: 核心组件,用来做转化工作
docx: 另一个做转化工作的模块,用来补充mammoth
os: 用来在系统中读取写入文件
zipfile: 用来解压word文档以提取图片
json: 用来把数据转化成json
bson: 用来配置写入json文件
unicode:用来处理字符
requests:用来调用api
3、转换单个文件
    1. styleMap = """
    复制代码
    1. p[style-name='Title'] => h1.hide
    复制代码
    1. p[style-name='Subhead 1'] => h3
    复制代码
    1. p[style-name='List Bullet'] => ul.first > li:fresh
    复制代码
    1. p[style-name='List Bullet 2'] => ul.second > li:fresh
    复制代码
    1. p[style-name='Hyperlink']=>a.link
    复制代码
    1. """
    复制代码
    1. def convert_image(image):
    复制代码
    1.     return {
    复制代码
    1.         "src":""
    复制代码
    1.     }
    复制代码
    1. [/code]
    2. [*][code]def parseFile(f):
    复制代码
    1.     document = Document(inputPath+f)
    复制代码
    1.     article = {"Title":document.core_properties.title,"Content":""}
    复制代码
    1.     with open(inputPath+f,"rb") as docFile:
    复制代码
    1.         html = mammoth.convert_to_html(docFile,style_map=styleMap,convert_image=mammoth.images.img_element(convert_image))
    复制代码
    1.         decoded = unidecode.unidecode(html.value)
    复制代码
    1. [/code]
    2. [*][code]
    复制代码
    1.     if not article["Title"]:
    复制代码
    1.         for para in document.paragraphs:
    复制代码
    1.             if para.style.name == 'Title':
    复制代码
    1.                 if para.text:
    复制代码
    1.                     article["Title"] = para.text
    复制代码
    1. [/code]
    2. [*][code]    article["Content"]=decoded
    复制代码
    1.     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):
    复制代码
    1.     ziped = zipfile.ZipFile(inputPath+f)
    复制代码
    1.     allFiles = ziped.namelist()
    复制代码
    1.     imgs = filter(lambda x: x.startswith('word/media/'), allFiles)
    复制代码
    1.     imgNameArr = []
    复制代码
    1.     for img in imgs:
    复制代码
    1.         res = requests.post(guidUrl)
    复制代码
    1.         if res.status_code is 200:
    复制代码
    1.             guid = res.text
    复制代码
    1.             data = ziped.read(img,imgPath)
    复制代码
    1.             idxStr = os.path.basename(img).split(".")[0][-1:]
    复制代码
    1.             imgDict = {}
    复制代码
    1.             imgDict["index"] = int(idxStr)-1
    复制代码
    1.             imgDict["fileName"] = guid+".jpg"
    复制代码
    1.             imgNameArr.append(imgDict)
    复制代码
    1.             targetPath = os.path.join(imgPath,guid+".jpg")
    复制代码
    1.             target = open(targetPath,"wb")
    复制代码
    1.             target.write(data)
    复制代码
    1.             target.close()
    复制代码
    1.     ziped.close()
    复制代码
    1.     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):
    复制代码
    1.     result = []
    复制代码
    1.     for f in os.listdir(path):
    复制代码
    1.         if not f.startswith('.'):
    复制代码
    1.             imgNameArr = extractImage(f)
    复制代码
    1.             article = parseFile(f)
    复制代码
    1.             fileName = os.path.basename(f)
    复制代码
  • [code]            contentArr = article["Content"].split("
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:200
帖子:40
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP