Python在Linux环境下Word转PDF

7 篇文章 2 订阅
有定制化需求可私信联系

有完美 PDF 转 Docx 方案,可私信联系

简介

Word 转 PDF,且需要能够在 Linux 上部署

1.docx(0118)




对比

实现方案优点缺点软件占用空间
win32com效果最好不支持 Linux1 GB 以上
comtypes效果最好不支持 Linux1 GB 以上
docx2pdf效果最好不支持 Linux1 GB 以上
AbiWord占用空间小,安装方便不支持 Windows,导出可能不完整69.4 MB
LibreOffice支持 Windows 和 Linux效果一般,安装麻烦585 MB
wvPDF效果很差,兼容很差247 MB
aspose-words速度快收费,有水印50.6 MB
unoconv效果较差,且有坑306 MB
阿里云市场易源数据API速度快效果较差,收费0
九云图API效果好文档需先上传为url,字体貌似需要不可多样化,收费0
WPS+pywpsrpc效果好首次运行需要界面,安装麻烦350 MB 以上

Linux 环境下建议使用 WPS+pywpsrpc




win32com

代码

from pathlib import Path
from win32com.client import Dispatch, constants, gencache

docx_path = str(Path('1.docx').absolute())
pdf_path = str(Path('1.pdf').absolute())
gencache.EnsureModule('{00020905-0000-0000-C000-000000000046}', 0, 8, 4)
wd = Dispatch('Word.Application')
doc = wd.Documents.Open(docx_path, ReadOnly=1)
doc.ExportAsFixedFormat(pdf_path, constants.wdExportFormatPDF, Item=constants.wdExportDocumentWithMarkup,
                        CreateBookmarks=constants.wdExportCreateHeadingBookmarks)
wd.Quit(constants.wdDoNotSaveChanges)

效果

第一页第二页

优点:代码简洁,效果好

缺点:需要安装Microsoft Word,不支持 Linux




comtypes

安装

pip install comtypes

代码

from pathlib import Path

import comtypes.client

word = comtypes.client.CreateObject('Word.Application')
doc = word.Documents.Open(str(Path('1.docx').absolute()))
wdFormatPDF = 17
doc.SaveAs(str(Path('1.pdf').absolute()), FileFormat=wdFormatPDF)
doc.Close()
word.Quit()

效果

第一页第二页

优点:代码简洁,效果好

缺点:需要安装Microsoft Word,不支持 Linux

wdFormatPDF 的值为 17 查阅 WdSaveFormat enumeration




docx2pdf

原理是调用 Microsoft Word,所以必须安装

安装

pip install docx2pdf

命令行

docx2pdf 1.docx

代码

from docx2pdf import convert

convert('1.docx')
print('转换完成')

效果

第一页第二页

优点:速度快,效果好

缺点:需要安装Microsoft Word,不支持 Linux




AbiWord

Linux 安装

sudo apt-get install abiword

命令行

abiword -t pdf 1.docx

代码

from subprocess import Popen

file = '1.docx'
Popen(['abiword', '-t', 'pdf', file]).communicate()
print('转换完成')

命令行参数详细阅读:Command line options

效果

第一页第二页第三页

优点:占用空间小,安装方便

缺点:不支持 Windows,导出可能不完整




LibreOffice

Windows

安装 LibreOffice

添加环境变量 PATH:C:\Program Files\LibreOffice\program

命令行

soffice.exe --convert-to pdf 1.docx

代码

from subprocess import Popen

file = '1.docx'
Popen(['soffice.exe', '--convert-to', 'pdf', file]).communicate()
print('转换完成')



Linux

Index of libreoffice 找到合适的文件(x.x.x 指具体的版本,如 7.1.8)

LibreOffice_x.x.x_Linux_x86-64_deb.tar.gz
LibreOffice_x.x.x_Linux_x86-64_deb_sdk.tar.gz
LibreOffice_x.x.x_Linux_x86-64_deb_langpack_zh-CN

安装

mkdir -p ~/download/libreoffice/deb
cd ~/download/libreoffice

wget http://mirrors.ustc.edu.cn/tdf/libreoffice/stable/7.1.8/deb/x86_64/LibreOffice_7.1.8_Linux_x86-64_deb.tar.gz
wget http://mirrors.ustc.edu.cn/tdf/libreoffice/stable/7.1.8/deb/x86_64/LibreOffice_7.1.8_Linux_x86-64_deb_sdk.tar.gz
wget http://mirrors.ustc.edu.cn/tdf/libreoffice/stable/7.1.8/deb/x86_64/LibreOffice_7.1.8_Linux_x86-64_deb_langpack_zh-CN.tar.gz

tar -zxvf LibreOffice_7.1.8_Linux_x86-64_deb.tar.gz -C deb
tar -zxvf LibreOffice_7.1.8_Linux_x86-64_deb_sdk.tar.gz -C deb
tar -zxvf LibreOffice_7.1.8_Linux_x86-64_deb_langpack_zh-CN.tar.gz -C deb

sudo dpkg -i LibreOffice_7.1.8.1_Linux_x86-64_deb/DEBS/*.deb
sudo dpkg -i LibreOffice_7.1.8.1_Linux_x86-64_deb_sdk/DEBS/*.deb
sudo dpkg -i LibreOffice_7.1.8.1_Linux_x86-64_deb_langpack_zh-CN/DEBS/*.deb

命令行

soffice --headless --convert-to pdf 1.docx
或
libreoffice --headless --convert-to pdf 1.docx

效果

第一页第二页第三页

删除安装包

cd ~
rm -r ~/download/libreoffice

TODO:卸载(要一个个删,很多)

dpkg -l | grep LibreOffice
sudo dpkg -r xxx



命令行参数

详细阅读:LibreOffice command line parameters

指定保存位置(不含文件名):--outdir




wvPDF

安装

sudo apt-get install wv texlive-base texlive-latex-base ghostscript

命令行

wvPDF 1.docx 1.pdf

效果:这份文档无法导出




aspose-words

安装

pip install aspose-words

代码

import aspose.words as aw

doc = aw.Document('1.docx')
doc.save('1.pdf')
print('转换完成')

效果

第一页第二页第三页




unoconv

安装

sudo apt-get install unoconv

命令行

unoconv -fpdf 1.docx
doc2pdf 1.docx

效果

第一页第二页第三页




易源数据API

代码

import base64
import requests

encoded = base64.b64encode(open('1.docx', 'rb').read())
url = 'https://word2pdf.showapi.com/word2pdf'
appcode = '你的AppCode'
headers = {
    'Authorization': 'APPCODE ' + appcode,
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
r = requests.post(url, data={'base64': encoded}, headers=headers, verify=False)
print(r)
print(r.json()['showapi_res_body']['url'])

效果

第一页第二页第三页第四页




九云图API

创建转换任务

import json
import requests

url = 'https://api.docsdk.com/v2/jobs'
apiKey = '你的apiKey'
data = {
    'tasks': {
        'ImportURL': {
            'operation': 'import/url',
            'url': 'https://image2.9yuntu.cn/resources/api/九云图API使用说明.docx'
        },
        'ConvertFile': {
            'input': ['ImportURL'],
            'operation': 'convert',
            'output_format': 'pdf'
        },
        'ExportResult': {
            'input': ['ConvertFile'],
            'operation': 'export/url'
        }
    }
}
headers = {
    'Authorization': 'Bearer ' + apiKey,
    'Content-Type': 'application/json'
}
r = requests.post(url, data=json.dumps(data), headers=headers)
print(r)
result = r.json()
print(result)
print(result['data']['status'])
print(result['data']['job_id'])

主动查询转换结果(复制上一步的 job_id)

import requests

jobId = '上一步的job_id'
url = f'https://api.docsdk.com/v2/jobs/{jobId}'
apiKey = '你的apiKey'
headers = {
    'Authorization': 'Bearer ' + apiKey
}
r = requests.get(url, headers=headers)
print(r)
result = r.json()
print(result)
status = result['data']['status']
print(status)
if status == 'finished':
    tasks = result['data']['tasks']
    for task in tasks:
        files = task['result']['files']
        print(task['id'], task['status'], str(task['percent']) + '%')
        for index, file in enumerate(files):
            print(index, file['filename'], file.get('url', '无下载地址'))

安装 Python SDK

pip install docsdk

封装

import docsdk

docsdk.configure(api_key='你的apiKey')
payload = {
    'tasks': {
        'ImportURL': {
            'operation': 'import/url',
            'url': 'https://image2.9yuntu.cn/resources/api/九云图API使用说明.docx'
        },
        'ConvertFile': {
            'input': ['ImportURL'],
            'operation': 'convert',
            'output_format': 'pdf',
        },
        'ExportResult': {
            'input': ['ConvertFile'],
            'operation': 'export/url'
        }
    }
}
res = docsdk.Job.create(payload=payload)  # 创建转换任务
print(res)
job_id = res['id']
res = docsdk.Job.wait(job_id)  # 等待转换结果
file = res['tasks'][-1]['result']['files'][0]
filename = docsdk.download(url=file['url'], filename=file['filename'])  # 下载文件
print(filename)

效果

第一页第二页







WPS+pywpsrpc

此方法需要 X11

查看是否已安装 X11

dpkg -l | grep xserver-xorg-core

查看是否开启 X11

cat /etc/ssh/sshd_config | grep X11Forwarding

查看架构

dpkg --print-architecture

根据架构下载 WPS Office 2019 for Linux,如本人为 amd64,选择 X64

安装(本人实际安装的是wget https://wdl1.pcfg.cache.wpscdn.com/wpsdl/wpsoffice/download/linux/10920/wps-office_11.1.0.10920.XA_amd64.deb,以下为新版)

mkdir -p ~/download/wps
cd ~/download/wps
wget https://wdl1.cache.wps.cn/wps/download/ep/Linux2019/10920/wps-office_11.1.0.10920_amd64.deb
sudo dpkg -i wps-office_11.1.0.10920_amd64.deb
sudo apt-get install qt5-default
pip3 install pywpsrpc
wget https://raw.githubusercontent.com/timxx/pywpsrpc/master/examples/rpcwpsapi/convertto/convertto.py

打开 WPS(应该是中文的)

wps 1.docx

弹出,同意即可(如果没有弹出,要装 X11,阅读 Linux安装X11实现GUI


命令行

python3 convertto.py -f pdf 1.docx

这时可能会报错,再运行一次即可

Convert failed:
Details: Can't get the application
ErrCode: 0x80000008


也有可能因为网络问题渲染画面迟迟才出来报错

安装无界面模式

sudo apt install xserver-xorg-video-dummy
vim dummy.conf

输入以下内容

Section "Monitor"
        Identifier "dummy_monitor"
        HorizSync 28.0-80.0
        VertRefresh 48.0-75.0
        Modeline "1920x1080" 172.80 1920 2040 2248 2576 1080 1081 1084 1118
EndSection

Section "Device"
        Identifier "dummy_card"
        VideoRam 256000
        Driver "dummy"
EndSection

Section "Screen"
        Identifier "dummy_screen"
        Device "dummy_card"
        Monitor "dummy_monitor"
        SubSection "Display"
        EndSubSection
EndSection

启动虚拟界面

X :0 -config dummy.conf

另外开一个 SSH,实现无界面运行

export DISPLAY=localhost:0.0
echo $DISPLAY
python3 convertto.py -f pdf 1.docx

效果

第一页第二页

删除安装包

cd ~
rm -r ~/download/wps

卸载

dpkg -l | grep wps-office
sudo dpkg -r wps-office
sudo apt-get --purge remove wps-office




Supervisor 守护进程

创建 X11 的配置文件 xorg.conf

sudo vim /usr/share/X11/xorg.conf.d/xorg.conf

填入内容,具体含义见 xorg.conf

Section "Monitor"
        Identifier "dummy_monitor"
        HorizSync 28.0-80.0
        VertRefresh 48.0-75.0
        Modeline "1920x1080" 172.80 1920 2040 2248 2576 1080 1081 1084 1118
EndSection

Section "Device"
        Identifier "dummy_card"
        VideoRam 256000
        Driver "dummy"
EndSection

Section "Screen"
        Identifier "dummy_screen"
        Device "dummy_card"
        Monitor "dummy_monitor"
        SubSection "Display"
        EndSubSection
EndSection

创建子进程配置文件

sudo vim /etc/supervisor/conf.d/X11.conf

填入内容

[program:X11]
command=X :0 -config /usr/share/X11/xorg.conf.d/xorg.conf
autostart=true
autorestart=true
startsecs=10
stdout_logfile=/tmp/X11.stdout.log
stderr_logfile=/tmp/X11.stderr.log

重新读取配置并更新子进程

supervisorctl reread
supervisorctl update

查看进程状态

ps -ef | grep Xorg
supervisorctl status | grep X11




封装

import os
import argparse
from pathlib import Path

from pywpsrpc.common import S_OK
from pywpsrpc.rpcwpsapi import wpsapi, createWpsRpcInstance

os.environ['DISPLAY'] = ':0.0'  # 设置环境变量,指定哪块屏幕

formats = {
    'doc': wpsapi.wdFormatDocument,
    'docx': wpsapi.wdFormatXMLDocument,
    'rtf': wpsapi.wdFormatRTF,
    'html': wpsapi.wdFormatHTML,
    'pdf': wpsapi.wdFormatPDF,
    'xml': wpsapi.wdFormatXML,
}


class ConvertException(Exception):
    def __init__(self, text, hr):
        self.text = text
        self.hr = hr

    def __str__(self):
        return 'Convert failed:\nDetails: {}\nErrCode: {}'.format(self.text, hex(self.hr & 0xFFFFFFFF))


def convert_to(paths, format='pdf'):
    hr, rpc = createWpsRpcInstance()
    if hr != S_OK:
        raise ConvertException('Can not create the rpc instance', hr)
    hr, app = rpc.getWpsApplication()
    if hr != S_OK:
        raise ConvertException('Can not get the application', hr)
    app.Visible = False  # 不需要GUI
    docs = app.Documents
    for path in paths:
        path = Path(path)
        if path.is_file():
            hr, doc = docs.Open(str(path.absolute()), ReadOnly=True)
            if hr != S_OK:
                raise ConvertException('can not open file {}'.format(path.name), hr)
            new_file = '{}.{}'.format(path.parent / path.stem, format)
            hr = doc.SaveAs2(new_file, FileFormat=formats[format])
            if hr != S_OK:
                raise ConvertException('convert_file failed', hr)
            doc.Close(wpsapi.wdDoNotSaveChanges)
    app.Quit()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('path', nargs='+')
    args = parser.parse_args()
    paths = args.path
    print(paths)
    try:
        convert_to(paths)
        print('转换完成')
    except ConvertException as e:
        print(e)




遇到的坑

1. 报错 NotImplementedError: docx2pdf is not implemented for linux as it requires Microsoft Word to be installed

docx2pdf 不能在 Linux 上运行

2. 报错 unoconv: Cannot find a suitable pyuno library and python binary combination in /usr/lib/libreoffice

sudo vim /usr/bin/unoconv

将首行

#!/usr/bin/env python3

改为

#!/usr/bin/python3

3. 报错 The program ‘libreoffice’ is currently not installed. To run ‘libreoffice’ please ask your administrator to install the package ‘libreoffice-common’

sudo apt-get libreoffice-common

4. 报错 Error: source file could not be loaded

sudo apt-get libreoffice-writer

5. WPS 的方案,测试代码能正常转换,部署代码报错 Can not get the application

检查环境变量 PATH 是否添加 WPS 所在目录:/usr/bin

import os

print(os.environ['PATH'])
print('/usr/bin' in os.environ['PATH'])

可能不支持并发多线程

X11 可能不支持不同用户或无 sudo 权限用户使用,Can’t start X11 applications after “su” or “su -” to another user

6. WPS 的方案,报错 convert_file failed ErrCode: 0x80010105

没有写入权限

7. WPS 可能有 BUG,需要切换为多组件模式

设置多组件模式流程:wps → 右上角设置按钮 → Settings → Others → Change window manage mode… → 选择【Multi-Module Mode】


8. Errors were encountered while processing

cd /var/lib/dpkg
sudo mv info info.bak
sudo mkdir info
sudo apt-get update




参考文献

  1. pywpsrpc GitHub
  2. wpsrpc-sdk GitHub
  3. wps_cpp
  4. WPS 开放平台
  5. WPS C++ 集成源码
  6. WPSOffice二次开发帮助文档
  7. docx2pdf GitHub
  8. Converting docx to pdf with pure python (on linux, without libreoffice)
  9. LibreOffice command line parameters
  10. How to convert Word (doc) to PDF in linux
  11. unoconv: Cannot find a suitable pyuno library and python binary combination · Issue #49 · unoconv/unoconv
  12. AbiWord vs LibreOffice 2022 Comparison
  13. Linux 下的LibreOffice安装
  14. pywpsrpc Run on Server
  15. Linux deb 软件包管理
  16. Linux安装X Window服务——远程显示GUI
  17. linux服务器通过X11实现图形化界面显示
  18. Error: source file could not be loaded
  19. Python 中docx转pdf
  20. comtypes Documentation
  21. comtypes GitHub
  22. ubuntu 下使用python操作wps文档和表格
  23. python 设置linux环境变量
  24. python 如何设置linux环境变量?
  25. What is the $DISPLAY environment variable?
  26. Python实现的进程管理神器——Supervisor
  27. Where is the X.org config file? How do I configure X there?
  28. 并发执行文件转换的程序获取不到application
  29. Can’t start X11 applications after “su” or “su -” to another user
  30. xserver - What are xhost and xhost +si?
  31. How can I run /usr/bin/Xorg without sudo?
  32. /usr/bin/xauth: file /…/.Xauthority does not exist
  33. Word转PDF-阿里云
  34. Requests Documentation
  35. Python图片转base64
  36. 九云图 - API文档
  37. docsdk GitHub
  • 29
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XerCis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值