背景
製造業あるある風景
・まとめ資料、提出資料は共有サーバーやNASに置くことになっている
・共有ドライブ上に資料が置かれていくが、台帳で管理されているわけではない
・そのうちどこに何があるかわからなくなり、定期的に過去資料発掘キャンペーンが開催
どこでもこんなものかと思いますが、めんどくさがりの人にはつらいと思います。
これに対処するために昔てきとうに作った意識低い系データベースの記録を残しておきます。
意識低いというのは「やる気がなくてもおいしくできるお手軽料理本」的な意味です。
つまり全くおしゃれではないですが「こういうのでいいんだよ」的な簡易文書検索を目指しました。
方針
共有サーバー上にあるPowerpointファイルのデータベースを作ります。
AccessでデータベースとGUI部分を作って、Pythonでそれを更新していく感じにします。
Access部分に欲しい機能
・スライド中のテキストを検索し、そのファイルの場所とページ番号を知ることができる
・データベースUIからクリックで当該ファイルを開ける
Python部分に欲しい機能
・テキスト抽出
・データベースをレコードを追加できる(INSERT)
・内容が更新されている場合はレコードを更新する(UPDATE)
Access部分の実装(データベース編)
これをもとにフォームウィザードで帳票形式のフォームも作っておきます。
Private Sub コマンド9_Click()
Dim filepath As String
If IsNull(Me.Path) = True Then
MsgBox "No path in record"
Exit Sub
End If
filepath = Me.Path
Dim pp_app As Object
If Dir(filepath, vbNormal) <> "" Then
Dim rc As Integer
rc = MsgBox(filepath & "が見つかりました。開きますか?", vbYesNo + vbQuestion, "ファイルを開く")
If rc = vbYes Then
Set pp_app = CreateObject("PowerPoint.Application")
pp_app.Presentations.Open filepath
Set pp_app = Nothing
End If
Else
MsgBox "ファイルが見つかりません。"
End If
End Sub
Access部分の実装(検索編)
任意のフレーズで検索できるような仕組みを追加しておきます。
検索文字列を入力するテキストボックスと、フィルター処理を実行するボタンをフォームの上に作ります。
Private Sub コマンド13_Click()
Me.Refresh
Dim filters, sqltmp As String
filters = ""
sqltmp = ""
'フィルター文の準備
If IsNull(searchpath) = False Then
filters = "(Path like '*" & Me.searchpath & "*')"
End If
If IsNull(search1) = False Then
sqltmp = "(Texts like '*" & Me.search1 & "*')"
If filters = "" Then
filters = sqltmp
Else
filters = filters & "AND " & sqltmp
End If
sqltmp = ""
End If
If IsNull(search2) = False Then
sqltmp = "(Texts like '*" & Me.search2 & "*')"
If filters = "" Then
filters = sqltmp
Else
filters = filters & "AND " & sqltmp
End If
sqltmp = ""
End If
Me.Filter = filters
Me.FilterOn = True
If filters = "" Then
Me.FilterOn = False
End If
End Sub
ほかの人も使う場合、Accessファイルを開いたときにナビゲーションウィンドウは表示せず、またフォームが最初から表示されるように設定しておきます。
Python(データベースの更新)部分の実装
ここからはデータベース生成・更新用のPythonコードを書きます。
次の操作を行います。
・指定したディレクトリ内のpptxファイルからテキストを抽出
・上記のAccessデータベースに登録または更新する
また、python-pptxを環境に、「Microsoft Access データベース エンジン 2016 再頒布可能コンポーネント」を事前にお使いのシステムに導入しておく必要があります。(たぶん)
from glob import glob
import pptx
from pptx.exc import PackageNotFoundError
import os
import pyodbc
#スライドを探すフォルダを設定
folder_paths=[r'C:\database']
#ファイル一覧作成
print("PowerPointファイルの一覧を作っています...")
file_paths=[]
for folder_path in folder_paths:
file_paths +=glob(folder_path+r'\**\*.pptx', recursive=True)
#データベース接続
conn_str= (
r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};'
r'DBQ=C:\Database.accdb;'#Accessファイルのパス
)
conn=pyodbc.connect(conn_str)
cursor=conn.cursor()
def text_extract(pptx_file):
try:
prs=pptx.Presentation(pptx_file)
except PackageNotFoundError:
print(pptx_file)
print("パスワードがかかっているか、空のファイルです")
print('_'*40)
record_list=[]
for i, sld in enumerate(prs.slides, start=1):
record_dict={'filepath':pptx_file,'page_num':i,'text':''}
extracted_texts=''
for shape in sld.shapes:
if shape.has_text_frame:
extracted_texts+=r'/'+shape.text.replace('\n','')
if shape.has_table:
for cell in shape.table.iter_cells():
extracted_texts+=r'/'+cell.text.replace('\n','')
record_dict['text']=extracted_texts
record_list.append(record_dict)
return record_list
#データベースに登録
for pptx_file in file_paths:
if r'~$' in pptx_file:
continue
record_set=text_extract(pptx_file)
for record in record_set:
param_insert=[record['filepath'],record['page_num'],record['text']]
sql_insert="INSERT INTO [テーブル1] ([Path],[Page],[Texts]) VALUES (?,?,?)"
param_update=[record['text'],record['filepath'],record['page_num']]
sql_update="UPDATE [テーブル1] SET [Texts]=? WHERE [Path]=? AND [Page]=?"
cursor.execute(sql_update,param_update)
if cursor.rowcount>0:
print("updated")
else:
cursor.execute(sql_insert, param_insert)
cursor.commit()
cursor.close()
conn.close()
print("おわり")
使い方メモ
・共有サーバーにAccessファイルを置いて、リンクを利用者におしえる
・定期的にPythonのコードを実行して更新しよう
・PowerPointファイルが多い場合は書き込み処理が多くなるので、Accessファイルをローカルに置いて更新し、終わったら共有サーバーに置くのがいいでしょう
この方法のよいところ
・人を説得して巻き込む必要がない(とても重要)
・保守が楽
おわりに
まあSharepointに置けば全て解決するんですけどね。
ただ普通は新しいやり方を提案しても面倒だといわれることは多そうなので、
既存のやり方を変える必要がないこういう迂回策のほうが話が早いことはよくある気がします。
今でも誰かの役に立つと信じています。
追記
ファイル名変わったらリンク切れが起きますね。
リンク切れをチェックして削除するコードも考えました。