Tex, python, illusrator, VPSの学生ノート

latotex-blog

Python

【Excel,Word,PowerPoint対応】複数ファイルをpdfに変換し1つに結合

投稿日:2020年6月13日 更新日:






PDFファイルの結合はオンラインでできるサイトがありますが、個人情報が抜き取られないか心配ですよね。といっても、Adobe Acrobat DCのような有料アプリを購入するのは気が引ける・・・

Pythonで何とかならないのか、調べてまとめてみました。

スポンサーリンク

Windowsしか使えません!!

残念ながら、この記事で示している方法はwindowsだけでしか使えない方法です・・・・

理由は使用しているcomtypesモジュールはwindows推奨であるからです。ちなみにLinuxで使うと以下のURLで説明されているようなエラーが発生します。(pipやcondaを壊すような致命的なエラーではないのでご安心ください)
https://stackoverflow.com/questions/37161560/importerror-cannot-import-name-comerror-in-python

Pythonコード

ベースはこのサイト様を参考にしています。このサイト様はwordとPDF結合をPythonで行う方法について示しています。
https://ysko909.github.io/posts/docx-convert-to-pdf-with-python/

この記事ではwordだけではなく、excel・powerpoint、すでにPDF形式であるもの(例えば、LaTeXで作った文章をコンパイルしてできたpdf)にも対応できるようにしています。

#!/usr/bin/env python3
# coding: UTF-8

#必要なものを宣言
import os
import comtypes.client
import glob
import pathlib
import PyPDF2
import shutil

#wordをpdfに変換する
def WDtoPDF(in_wd, out_wd, formatType = 17):
    word = comtypes.client.CreateObject('Word.Application')
    word.Visible = False
    doc = word.Documents.Open(in_wd)
    doc.SaveAs(out_wd, formatType)
    doc.Close()
    word.Quit()

#powerpointをpdfに変換する
def PPTtoPDF(in_ppt, out_ppt, formatType = 32):
    powerpoint = comtypes.client.CreateObject("Powerpoint.Application")
    #ここを1(Ture)にしないとなぜかエラーがでる
    powerpoint.Visible = 1
    doc = powerpoint.Presentations.Open(in_ppt)
    doc.SaveAs(out_ppt, formatType)
    doc.Close()
    powerpoint.Quit()

#excelをpdfに変換する
def ELtoPDF(in_xlsx, out_xlsx):
    excel = comtypes.client.CreateObject('Excel.Application')
    excel.Visible = False
    doc = excel.Workbooks.Open(in_xlsx)
    doc.ExportAsFixedFormat(0, out_xlsx, 1, 0)
    doc.Close()
    excel.Quit()

#pdfをまとめて1つにする
def pdf_merger(out_pdf, pdfs):
    merger = PyPDF2.PdfFileMerger()

    for pdf in pdfs:
        print(pdf)
        merger.append(pdf)

    merger.write(out_pdf)
    merger.close()

#結合するexcel,word,powerpoint,pdfがある場所
file_path = r'C:\Users\useri\Desktop\file_pdf'

#変換したPDFファイル・結合したPDFファイルを入れるサブフォルダー
sub_name = 'box'

file0 =  pathlib.Path(file_path)
file1 = file0.joinpath(sub_name)

#サブフォルダーを作成
os.makedirs(file1, exist_ok=True)

#もとのファイルがある場所に移動
os.chdir(file_path)
files = glob.glob('*')


#excel,word,powerpointをpdfに変換し、名前の拡張子も.pdfに変更
#変換したPDFのパスをリストに渡す
pdfs = []

for f in files:
    file_p = file0.joinpath(f)

    if file_p.suffix == '.xlsx':
        file_pdf = file1.joinpath(f.replace(file_p.suffix, '.pdf'))
        ELtoPDF(str(file_p), str(file_pdf))
        pdfs.append(str(file_pdf))

    elif file_p.suffix == '.pptx':
        file_pdf = file1.joinpath(f.replace(file_p.suffix, '.pdf'))
        PPTtoPDF(str(file_p), str(file_pdf))
        pdfs.append(str(file_pdf))

    elif file_p.suffix == '.docx':
        file_pdf = file1.joinpath(f.replace(file_p.suffix, '.pdf'))
        WDtoPDF(str(file_p), str(file_pdf))
        pdfs.append(str(file_pdf))

    elif file_p.suffix == '.pdf':
        shutil.copy('./'+ f, './'+ sub_name)    #もともとPDFであるものはそのままコピー
        file_pdf = file1.joinpath(f)
        pdfs.append(str(file_pdf))
    else:
        pass

#結合したPDFに名前を付け、サブフォルダーに置く
out_file = str(pathlib.Path(file1).joinpath('out.pdf'))
#PDFの結合
pdf_merger(out_file, pdfs)

    

スポンサーリンク

補足説明

それでは、補足説明していきます。私の作業環境はwindows10 + Jupyter Notebookです。

PyPDF2・comtypesを使ったことがある方は、以下のリンクからUnicodeEncodeエラーの対処方だけチェックしてください!

UnicodeEncodeErrorへの対処方法

PyPDF2・comtypesのインストール

condaでインストールできます。defaultのリポジトリには存在しないので、conda-forgeのチャンネルを指定してインストールしてください。

$ conda install -c conda-forge comtypes
$ conda install -c conda-forge pypdf2

うまくいかない場合はanaconda cloudからモジュール名(今回であれば PyPDF2・comtypes)を検索して他の手段でインストールしてください。anaconda cloudのURLを載せておきます。

https://anaconda.org/

PDF変換作業におけるformatType

excel,word,powerpointをバックグラウンドで実行し(powerpointは例外。しかし、画面上に表示した後すぐにクローズするので問題ない)開いたファイルをPDFとして保存することで、もとのファイルを残したままPDF変換ができます。formatTypeは出力ファイルの指定をするもので、アプリケーションによって表示が異なります。excelだけは特殊で、SaveAsというメゾットがないのでExportAsFixedFormatから指定します。

powerpoint・wordにおけるformatTypeの指定

https://docs.microsoft.com/ja-jp/office/vba/api/powerpoint.ppsaveasfiletype

ExportAsFixedFormatメゾットについて

https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2007/ms409271(v=office.12)?redirectedfrom=MSDN

UnicodeEncodeErrorへの対処方法

結合するファイルによっては、以下のようなエラーが表示されることがあります。

UnicodeEncodeError: 'latin-1' codec can't encode characters in position .... : ordinal not in range (...)

これはPyPDF2モジュールのencodeが r = s.encode('latin-1')と指定しているため、'utf-8'に直す必要があります。PyPDF2のutils.pyを探して変更作業を行います。スタートボタンの隣にある検索機能で「PyPDF2」を検索し、出てきたフォルダーにあると思います。少なくともAnaconda3をお使いのかたはC:\Users\(ユーザー名)\Anaconda3\envs\(仮想環境の名前)\lib\site-packages\PyPDF2にあります。(仮想環境とbase環境を間違えないように注意)

utils.pyの238-241行目にある以下の文章を、

#!/usr/bin/env python3
r = s.encode('latin-1')
if len(s) < 2:
    bc[s] = r
return r

以下のようにr = s.encode('utf-8')が使える形に変更します。Anaconda3を再起動しなくてもpythonの実行で変更が反映されます。

#!/usr/bin/env python3
try:
    r = s.encode('latin-1')
except:
    r = s.encode('utf-8')
if len(s) < 2:
    bc[s] = r
return r

これで、エラーは出なくなるはずです。try-except構文を使っているので、変更で障害が生じることはないかと思います。

エラーの対処方法はこちらのサイトを参考にしました。
https://github.com/mstamy2/PyPDF2/issues/438


-Python

Copyright© latotex-blog , 2020 All Rights Reserved Powered by STINGER.