Noob Front End Engineer Blog

CONTACT

PythonでWordファイルをHTMLに変換

2021/01/09

概要

静的なサイトで記事ページを作成する際、ライターの方から
頂いた Word ファイル(.docx)を元に実装する事はありませんか?

コピペを何度も何度も行う単純作業はきついですよね。

という事で、今回は Python を使用して Word ファイルを元に
いい感じの HTML を生成する方法を紹介していきます 🙂

完成品はこちらです。
使用方法はREADME.mdに記載してありますので、お急ぎの方は上記を使用してみてください。
※ Docker 使用を想定して作成しています

Github強化中なので、☆, フォローいただけると喜びます

環境構築

Python3がインストール済み、もしくはDocker等で
Python3の実行環境ができているものとします。

まずは任意の場所にデモ用のディレクトリを作成してください。

bash
# ディレクトリ作成
mkdir demo

# ディレクトリ移動
cd demo

今回のデモは下記のようなディレクトリ構造で行っていきます。

demo
  └ dist
     └ index.html  # <-- 作成されたHTML
  └ src
     └ input.docx  # <-- 元となるWordファイル
  |
  └ converter.py   # <-- HTML生成処理

コマンドでもエクスプローラーでも構わないので、
dist/ディレクトリとsrc/ディレクトリを作成しておいてください。

HTML 生成処理の作成

今回使用するモジュール達は下記の通り

module description
os ファイル・ディレクトリ操作
re 正規表現が使える
glob ファイル名取得
mammoth docx ファイルから html ファイルに変換してくれる
bs4 HTML 操作全般をおこなってくれる(今回は html の整形用として使用)

os, re, globはデフォルトでインストールされている為
mammoth, bs4(beautifulsoup4)のみ明示的にインストールする必要があります。

今回はconverter.pyというファイルを作成して、そこに実装を行っていきます。

処理の内容は下記の通りです。

converter.py
import mammoth # docx → html
import os # create file
import glob # read file name

from bs4 import BeautifulSoup # html linter 
from bs4 import Tag

import re # 正規表現

files = glob.glob('./src/*.docx')

for file in files:
  with open(file, 'rb') as docx_file:
    result = mammoth.convert_to_html(docx_file)
    source = result.value

    # --------------------- class setting start ---------------------

    # 見出し 
    source = source.replace('<h1>', '<h1 class="">')
    source = source.replace('<h2>', '<h2 class="">')
    source = source.replace('<h3>', '<h3 class="">')
    source = source.replace('<h4>', '<h4 class="">')
    source = source.replace('<h5>', '<h5 class="">')

    # テーブル内のpタグ削除
    source = re.sub('<th(.*?)<p>(.*?)</p>', '<th\\1\\2', source)
    source = re.sub('<td(.*?)<p>(.*?)</p>', '<td\\1\\2', source)

    # パラグラフ
    source = source.replace('<p>', '<p class="">')

    # 画像 (画像は未対応の為、ダミー画像を表示)
    source = re.sub('<img src=\"(.*?)\"', '<img src="https://placehold.jp/150x150.png"', source)

    # リスト
    source =source.replace('<ul>', '<ul class="">')
    source =source.replace('<ol>', '<ol class="">')

    # テーブル
    source =source.replace('<table>', '<table class="">')
    source =source.replace('<tr>', '<tr class="">')
    source =source.replace('<td>', '<td class="">')

    # --------------------- class setting end ---------------------

    html = BeautifulSoup(source, 'lxml')
    html = html.prettify()
    messages = result.messages

    outputfile = file.replace('.docx', '.html')
    outputfile = outputfile.replace('/src/', '/dist/')

  with open(outputfile, mode='w') as f:
    f.write(html)

  print("finished convert (´-ω-`)")

それでは、実際にどのように処理を行っているか解説していきます!

元となるWordファイルの取得・ループ処理

まずは元となるWordファイルのファイルパスを全て取得し
ファイルの件数分だけループを回しています。

converter.py
# --- 略 ---
files = glob.glob('./src/*.docx')

for file in files:
# --- 略 ---

globモジュールを使用する事でファイルパスを取得することができます。
今回の場合は./src/ディレクトリ内にある.docx形式のファイル全てのファイルパスを
取得しfiles変数に格納しています。

Wordファイルを元にHTMLを作成

ここからは実際にWordファイルを元にHTMLを作成する機能を作成しています。

converter.py
# --- 略 ---
  with open(file, 'rb') as docx_file:
    result = mammoth.convert_to_html(docx_file)
    source = result.value
# --- 略 ---

fileには先ほど取得してきたWordファイルのパスが格納されているので
そちらのファイルを開き、docx_file変数にWordファイルの情報を格納します。

次にdocx_fileに取得したWordファイルをmammothモジュールを使用してHTMLに変換します。 mammoth.convert_to_html()docx_fileを渡すことでHTMLの情報を取得できます。
返ってきたHTML情報をresultに格納し、valueを確認すると、 実際にHTML入っていることが確認できると思います。

タグを独自に加工

ここから各HTMLタグを独自に加工していきます。

converter.py
# --- 略 ---
    # --------------------- class setting start ---------------------

    # 見出し 
    source = source.replace('<h1>', '<h1 class="">')
    source = source.replace('<h2>', '<h2 class="">')
    source = source.replace('<h3>', '<h3 class="">')
    source = source.replace('<h4>', '<h4 class="">')
    source = source.replace('<h5>', '<h5 class="">')

    # テーブル内のpタグ削除
    source = re.sub('<th(.*?)<p>(.*?)</p>', '<th\\1\\2', source)
    source = re.sub('<td(.*?)<p>(.*?)</p>', '<td\\1\\2', source)

    # パラグラフ
    source = source.replace('<p>', '<p class="">')

    # 画像 (画像は未対応の為、ダミー画像を表示)
    source = re.sub('<img src=\"(.*?)\"', '<img src="https://placehold.jp/150x150.png"', source)

    # リスト
    source =source.replace('<ul>', '<ul class="">')
    source =source.replace('<ol>', '<ol class="">')

    # テーブル
    source =source.replace('<table>', '<table class="">')
    source =source.replace('<tr>', '<tr class="">')
    source =source.replace('<td>', '<td class="">')

    # --------------------- class setting end ---------------------
# --- 略 ---

replaceを使用して開始タグを編集します。
ここは実際に入れたいclass名、id名等を自由に記入してください。

HTMLの整形・出力

最後にHTMLの整形を行い、ディレクトリ・ファイル名を指定して出力する処理を解説していきます。

converter.py
# --- 略 ---
    html = BeautifulSoup(source, 'lxml')
    html = html.prettify()
    messages = result.messages

    outputfile = file.replace('.docx', '.html')
    outputfile = outputfile.replace('/src/', '/dist/')

  with open(outputfile, mode='w') as f:
    f.write(html)

  print("finished convert (´-ω-`)")
# --- 略 ---

Wordから変換したHTMLデータが入っているsource
改行やインデント等が入っていないHTMLファイルになってしまっている為、
BeautifleSourceモジュールを使用して整形を行っています。

html = BeautifulSoup(source, 'lxml')を行う事で、
sourceに入っていたHTML情報の文字列をHTMLデータとして
html変数に格納することができます。

このような、「どういったデータ構造になっているか明示的に示す」事を
「パースする」と言う事を初めて知りました

html変数にはBeautifulSoupで使用できるHTMLデータになったので、 prettifyという整形用の関数を使用して整形を行えます。

最後にファイルパスを出力用のパスに書き換えて、
HTMLファイルを作成したら完成です🙆‍♂️

おわり

今回初めてまともにPythonを触ったのですが、記述方法がとても簡単で感動しました…
知識が薄いので、もっといい書き方、説明があれば是非ご指摘ください!


Written by daichi iwamoto