跳至主要內容

PDF文档内容替换

yczha大约 6 分钟pythonPDF专题文档替换PDF转Word

这篇文章介绍了如何使用Python3把PDF文件转换为word文档并替换word文档中的文字内容,这里替换的规则是中英转换或者其它自定义规则。

pdf转换为word

pdf文件由于很难编辑,因而想要通过编程修改内容有些困难【不是不可能,只是代价比较大,特别是要保留原pdf格式的话】,故而这里介绍一个替换pdf文件文字内容的间接解决方案,即:把pdf文件转换为word然后再编程替换word的文字内容,当然替换完成后想把word转为pdf就简单的多了

本文这里转换pdf文件介绍四种方法:

  • 使用第三方工具
  • 使用pdfminer3k 解析pdf然后再把内容写入到word中
  • 使用第三方SDK
  • 使用LibreOffice 开发者库

这里简单说明下几种方法的优劣:

使用第三方工具的话,有这样两种情况:

  • Online版本,大多可以免费使用,但是转换麻烦,不能编程操作,需要手动实现

  • 软件版本,大多可以批量转换,但是大多转换有限制,需付费才能无限制使用,且不能编程处理

    如果上面的情况符合你的实际需要,那再好不过!当然,不能符合的话,接着往下看

使用pdfminer3k解析pdf文件

  • 对于纯文本内容且没有着严格的格式要求的话,你可以使用这个工具进行转换。

使用第三方SDK

这个是一个比较好的选择,然而,SDK大多收费!!!这些SDK一般提供完善的开发者API接口,你可以方便而又简单的调用,楼主这里介绍一个叫做easyConvertPDF ,他们提供一个pdf2word.py 的API,使用十分简单,转换效果页令人满意,只是,License太贵了,买不起,当然你可以下载试用

使用LibreOffice 开发者库

这个是Micro Office 支持的 Office 开发者库,里面可以实现PDF转换为Word,只是楼主在使用时一致没测试成功,下面给出一段使用代码,你需要先安装LibreOffice 才行

import os
import subprocess

for top, dirs, files in os.walk('/my/pdf/folder'):
    for filename in files:
        if filename.endswith('.pdf'):
            abspath = os.path.join(top, filename)
            subprocess.call('lowriter --invisible --convert-to doc "{}"'
                            .format(abspath), shell=True)

从上面的四种方法中选择一种适合你的方法!

替换word文字内容

  • 替换word使用的是win32com 的包,使用这个包你需要先安装pywin32

    pip install pywin32
    
  • 安装完成后可能会出现如下错误

    ImportError: DLL load failed: win32api, sys, os
    

    这时你可以通过如下方式解决

    C:\Users\yourname\Anaconda3\Lib\site-packages\pypiwin32_system32这个目录下的pythoncom36.dllpywintypes36.dll 拷贝到C:\Users\fanyu\Anaconda3\Lib\site-packages\win32 这个目录下

  • 正常后编写测试程序

    import os
    import win32com.client
    
    # 处理Word文档的类
    class RemoteWord:
        def __init__(self, filename=None):
            self.xlApp=win32com.client.DispatchEx('Word.Application')
            self.xlApp.Visible=0
            self.xlApp.DisplayAlerts=0    #后台运行,不显示,不警告
            if filename:
                self.filename=filename
                if os.path.exists(self.filename):
                    self.doc=self.xlApp.Documents.Open(filename)
                else:
                    self.doc = self.xlApp.Documents.Add()    #创建新的文档
                    self.doc.SaveAs(filename)
            else:
                self.doc=self.xlApp.Documents.Add()
                self.filename=''
    
        def add_doc_end(self, string):
            '''在文档末尾添加内容'''
            rangee = self.doc.Range()
            rangee.InsertAfter('\n'+string)
    
        def add_doc_start(self, string):
            '''在文档开头添加内容'''
            rangee = self.doc.Range(0, 0)
            rangee.InsertBefore(string+'\n')
    
        def insert_doc(self, insertPos, string):
            '''在文档insertPos位置添加内容'''
            rangee = self.doc.Range(0, insertPos)
            if (insertPos == 0):
                rangee.InsertAfter(string)
            else:
                rangee.InsertAfter('\n'+string)
    
        def replace_doc(self,string,new_string):
            '''替换文字'''
            self.xlApp.Selection.Find.ClearFormatting()
            self.xlApp.Selection.Find.Replacement.ClearFormatting()
            self.xlApp.Selection.Find.Execute(string, False, False, False, False, False, True, 1, True, new_string, 2)
    
        def save(self):
            '''保存文档'''
            self.doc.Save()
    
        def save_as(self, filename):
            '''文档另存为'''
            self.doc.SaveAs(filename)
    
        def close(self):
            '''保存文件、关闭文件'''
            self.save()
            self.xlApp.Documents.Close()
            self.xlApp.Quit()
    
    if __name__ == '__main__':
       doc = RemoteWord(docx)  # 初始化一个doc对象
       # 这里演示替换内容,其他功能自己按照上面类的功能按需使用
       doc.replace_doc('your string','new string')  # 替换文本内容
       doc.close()
    

    好了以上就完成了从pdf到word的完整内容,这里楼主附上一个实例:

    楼主需要把pdf文件报表的英文内容替换为中文,也就是等价于翻译,只是翻译是提前做好的,放置在一个match_rule.xlsx的文件中 ,这个文件内容就是两列:原文 译文,然后程序会读取内容并自动替换。

    下面楼主给出代码:

# 该程序实现把PDF转换为word然后读取word文件中的文字内容并按照特定的规则替换文字
  
  # -*- encoding: utf8 -*-
  
  __author__ = 'yooongchun'
  
  # 引入所需要的基本包
  import os
  import re
  import xlrd
  import win32com.client
  import logging
  
  logging.basicConfig(level=logging.INFO)
  
  
  # 处理Word文档的类
  class RemoteWord:
      def __init__(self, filename=None):
          self.xlApp = win32com.client.DispatchEx('Word.Application')
          self.xlApp.Visible = 0
          self.xlApp.DisplayAlerts = 0  # 后台运行,不显示,不警告
          if filename:
              self.filename = filename
              if os.path.exists(self.filename):
                  self.doc = self.xlApp.Documents.Open(filename)
              else:
                  self.doc = self.xlApp.Documents.Add()  # 创建新的文档
                  self.doc.SaveAs(filename)
          else:
              self.doc = self.xlApp.Documents.Add()
              self.filename = ''
  
      def add_doc_end(self, string):
          '''在文档末尾添加内容'''
          rangee = self.doc.Range()
          rangee.InsertAfter('\n' + string)
  
      def add_doc_start(self, string):
          '''在文档开头添加内容'''
          rangee = self.doc.Range(0, 0)
          rangee.InsertBefore(string + '\n')
  
      def insert_doc(self, insertPos, string):
          '''在文档insertPos位置添加内容'''
          rangee = self.doc.Range(0, insertPos)
          if (insertPos == 0):
              rangee.InsertAfter(string)
          else:
              rangee.InsertAfter('\n' + string)
  
      def replace_doc(self, string, new_string):
          '''替换文字'''
          self.xlApp.Selection.Find.ClearFormatting()
          self.xlApp.Selection.Find.Replacement.ClearFormatting()
          self.xlApp.Selection.Find.Execute(string, False, False, False, False, False, True, 1, True, new_string, 2)
  
      def save(self):
          '''保存文档'''
          self.doc.Save()
  
      def save_as(self, filename):
          '''文档另存为'''
          self.doc.SaveAs(filename)
  
      def close(self):
          '''保存文件、关闭文件'''
          self.save()
          self.xlApp.Documents.Close()
          self.xlApp.Quit()
  
  
  # 遍历找到word文件路径
  def find_docx(pdf_path):
      file_list = []
      if os.path.isfile(pdf_path):
          file_list.append(pdf_path)
      else:
          for top, dirs, files in os.walk(pdf_path):
              for filename in files:
                  if filename.endswith('.docx') or filename.endswith('.doc'):
                      abspath = os.path.join(top, filename)
                      file_list.append(abspath)
      return file_list
  
  
  # 替换文本内容
  def replace_docx(rule, docx_list):
      len_doc = len(docx_list)
      i = 0  # 计数
      for docx in docx_list:
          i += 1
          logging.info('开始替换第 %s/%s 个word文件内容:%s...' % (i, len_doc, os.path.basename(docx)))
          doc = RemoteWord(docx)  # 初始化一个doc对象
          for item in rule:  # 替换
              doc.replace_doc(item[0], item[1])
          doc.close()
  
      logging.info('完成!')
  
  
  # 对内容进行排序
  # 这里因为在进行文本替换的时候涉及到一个长句里面的部分可能被短句(相同内容)内容替换掉
  # 因而必须先把文本按照从长到短的顺序来进行替换
  def sort_rule(rule):
      result = []
      for item, val in rule.items():
          le = len(item)
          flag = True
          if len(result) > 0:
              for index, res in enumerate(result):
                  if len(item) >= len(res[0]):
                      flag = False
                      result.insert(index, (item, val))
                      break
              if flag:
                  result.append((item, val))
  
          else:
              result.append((item, val))
  
      return result
  
  
  # 加载Excel,把取得的内容返回,格式:dict{'原文':'译文'}
  def init_excel(excel_path):
      logging.info('加载文本匹配规则的Excel:%s' % os.path.basename(excel_path))
      rule = {}  # 储存原文和翻译内容
      pdf_path = ''
      try:
          book = xlrd.open_workbook(excel_path)  # 打开一个wordbook
          sheet = book.sheet_by_name('Translation')  # 切换sheet
          rows = sheet.nrows  # 行数
          for row in range(rows - 1):
              text_ori = sheet.cell(row, 0).value  # 取得数据:原文
              text_trans = sheet.cell(row, 1).value  # 取得数据:译文
              if not re.match(r'^#.+', text_ori):  # 原文不以#开头
                  if text_ori == 'pdf文件(或文件夹)地址':  # 获得pdf文件路径
                      pdf_path = text_trans
                  else:
                      rule[text_ori] = text_trans  # 取得值加入text
      except IOError:
          raise IOError
      logging.info('加载Excel完成!')
  
      return pdf_path, rule
  
  
  if __name__ == '__main__':
  
      excel_path = './match_rule.xlsx'  # 替换规则的Excel文件地址
      logging.info('正在打开pdf转换软件,请手动转换你的pdf文件!')
      os.popen(r'"./PDF2Word/pdf2word.exe"')
      flag = input('你已经完成pdf文件转换了吗?(y/n):')
      while not flag == 'y':
          logging.info('请先转换pdf!')
          flag = input('你已经完成pdf文件转换了吗?(y/n):')
      pdf_path, rule = init_excel(excel_path)  # 加载Excel,取得内容
      sorted_rule = sort_rule(rule)  # 排序规则:按照由长到短
      docx_list = find_docx(pdf_path)  # 获取docx文件路径
      replace_docx(sorted_rule, docx_list)  # 替换内容
  
      logging.info('程序执行完成!')

项目github地址:https://github.com/yooongchun/Python_transPDF