自動化について考えるブログ

自動化に関する話が好きで、ロボットやライフロギングについて書いていきます。たまに趣味の地理・旅行に関する話もします。

Pythonによるdocx文字数・画像数カウンタ

概要

卒論や報告書等がどのような速度感で出来上がっていくのか興味を持つことがあります。
今回はそのような用途のためにMicrosoft Wordのdocxファイルの文字数・画像数を外部から計算するスクリプトを作成しました。
進捗の可視化や、自分の追い込みの速度の把握にご利用ください。


図は自分の学位論文執筆時の文字数カウント結果です。このようなグラフを自動で書けるようにするのが今回の目標です。


※※注意※※
このプログラムは目標のdocxファイル自体は直接いじらない仕様となっていますが、
コピーと消去といったファイル操作をするため、
動作環境によっては目標のファイルに害が及ぶかもしれません。利用は自己責任でお願いします。
まずは全然関係ないファイルでテストしてみるとか、ファイルのバックアップを定期的に取るなどの対策をお薦めします。

github.com



やっていること

  1. docxファイルを拡張子をzipにしてコピーし、フォルダに展開※
  2. zipファイルの/word/mediaディレクトリに格納される画像ファイルの数から、文章内の画像数をカウント
  3. 文章の内容がかかれているxmlファイル(document.xml)から文字の部分を取り出して、文字数をカウント
  4. コピーして生成したzipファイル、zip展開したフォルダ・ファイルを削除

※docxファイルは実はzip形式で、中には画像ファイルや文章ファイルが別個に格納されている

環境

言語: Python 3.6.1
OS: Windows 10 Pro (64 bit)
Officeのバージョン: Microsoft Office Professional Plus 2013

コードは以下の通り

#docxファイルの文字数、画像数の統計量を計算
#180201追記 ハイパーリンクに未対応。ハイパーリンクは通常のテキストに比べてネストが深くなるため、奥深くまで探索しないといけない。

import xml.etree.ElementTree as ET
import shutil
import zipfile
import os
import sys

#docxファイルの文字数、画像数の統計量を計算
def calsDocxStats(fileheader):
	#docxの中身を見るためにzip形式にし解凍
	shutil.copy(fileheader+".docx", fileheader+".zip")
	with zipfile.ZipFile(fileheader+".zip",'r') as inputFile:
		inputFile.extractall(path=fileheader+"\\")
	#画像ファイル数カウント
	try:
		figure_dirname = fileheader+"/word/media"
		figures_ls = os.listdir(figure_dirname)
		img_n = len(figures_ls)
		#print("画像数は%dです。"%len(figures_ls)) #debug
	except:
		#print("画像はありません。") #debug
		img_n = 0
	#文字数カウント
	xml_filename = fileheader+"/word/document.xml"
	tree = ET.parse(xml_filename)
	root = tree.getroot()
	body = root[0]
	header = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
	mojiretsu = ""
	for i in range(len(body)-1):
		line = body[i]
		for ele in line:
			for child in ele:
				#print(child.tag) #debug
				if child.tag == ("{"+header+"}t"): #文字が入っているタグなら文字を描画
					moji = child.text
					mojiretsu += moji
		mojiretsu += "\n"
	#print(moji_retsu) #debug:取得した全文の表示
	moji_n = len(mojiretsu)
	#zipファイルの削除
	os.remove(fileheader+".zip")
	#zip展開ディレクトリの削除
	shutil.rmtree(fileheader)
	return img_n, moji_n

if __name__ == '__main__':
	#計測するファイル名
	docx_filename = input("docxファイル名を入力してください。>")
	fileheader = docx_filename.split(".docx")[0]
	img_n, moji_n = calsDocxStats(fileheader) #docxファイルの文字数、画像数の統計量を計算
	print("画像数は%dです。"%img_n)
	print("文字数は%dです。"%moji_n)

使い方

上のプログラムはそのまま実行すれば動きますが、
論文やマニュアルなどの進捗を定期的にロギングしたいときは、
タスクスケジューラなどで実行してやるのが良さそうです。

その他仕様など

ハイパーリンクが貼られている部分だけ文字数のカウントがうまくいかなくなりますが、
ハイパーリンク部分の文字数は全体の文字数からすると僅かで影響がないと考え、今回は対処していません。
1,2例試しただけですが、wordの段組みやタイトルページなどがあってもおおむね正しい文字数が出るようです。