目次
はじめに
Python + Selenium + BeautifulSoup + Microsoft SQL Server + FileMakerを組み合わせて、いまいち自分の思い通りな検索ができない某公共機関のサイトからデータを取得・加工し、FileMakerを最終的なインターフェースとしたオレオレ検索アプリを作成しています。
たまにデータ更新があるので、そのデータを再取得し、DBを更新する機能を作りこんでいました。
「Eventを送信」で処理を投げたものの、FileMakerのWindows環境では投げっぱなしになって結果を自動的に受けるような標準機能が無い(多分)ので、どうにかしてできないかと試行錯誤した話です。
処理概要
最近Pythonや機械学習、そしてSQLに興味を持ち始め、Microsoft SQL ServerにDBを構築して一カ所でデータを管理しているので、このデータもFileMakerへはストックせずにMicrosoft SQL Serverに保存しています。
処理としては、
1.FileMakerからデータ取得のバッチを起動させる
2.Pythonで書いたPGが実行されHTMLダウンロード、データ形成の実施
3.最終成果物としてCSVファイルを作成
4.FileMaker経由でMicrosoft SQL Serverへインポート
ということを行い、これをFileMaker上のスクリプトで、途中人の手を入れることなく(3⇒4のところ)一貫して実行させようと、前述の通りどうにかしてEventの結果を受け取る試みです。
ファイル更新日時+クリップボードの工夫で実現
今回着目したのは、最終成果物となるCSVファイルの更新日時と、クリップボード機能です。
たまたまでもありますが、このCSVファイルは2.の作業中都度書き込みではなく、2.の作業が全てて完了してデータを蓄積させ、最後にまとめて出力する。という仕様にしていたので実現しました。要は最後の書き込みが終わるまではファイルの日付は古いまま(前の更新日時)と言う特性を利用しています。つまり、
“ファイルの更新日時” と “FileMakerのスクリプト起動日時“
を比較させ、“FileMakerのスクリプト起動時間” < “ファイルの更新日時”となるまでFileMakerのスクリプトを待機させます。
そのファイルの日付取得にはかなりアナログな方法ですが、これまたバッチでクリップボードに都度貼り付けさせる。という方法で実現しました。
1.本体スクリプト
全体はこのような状態です。意外とシンプルにできました。
a.基準となるタイムスタンプ
#現在日付取得
変数を設定 [$curdatetime; 値: Get( タイムスタンプ )]
まずは基準となるタイムスタンプです。ファイルの更新日時がここを越えるか超えないかが判定条件となります。
b.python処理実行
#python処理実行
Event を送信 [ 「aevt」; 「odbc」: 「main.bat」 ]
Pythonファイルも認識しますが、うまく処理が起動しないので、Batで起動させています。内容は割愛します。
c.終了判定
#python処理待ち
Loop
Event を送信 [「aevt」; 「odbc」; 「file_time.bat」 ]
貼り付け [ main::gFileDateTime ][ 選択; スタイルなし]
変数を設定 [ $filedatetime; 値:Substitute ( main::gFileDateTime ; " ¶" ; "" ) ]
フィールド設定 [ main::gFileDateTime; "" ]
スクリプト一時停止/続行 [ 間隔(秒): 1 ]
Exit Loop If [$curdatetime < $filedatetime ]
End Loop
スクリプト一時停止/続行 [ 間隔(秒): 1 ]
今回試行錯誤してみた部分です。
Loop処理を回し続け、1秒ごとにCSVファイルの更新日時を取得しています。そのバッチの中身は下記の通り。
cd /d %~dp0
cd ./csv
forfiles /M basic_info.txt /C "cmd /c echo @fdate @ftime | clip"
forfiles関数でファイルを取得し、その更新日と更新時間を”clip”でクリップボードへ貼り付け
その後FileMakerスクリプトでは取得した時間をいったんグローバルなタイムスタンプフィールドに貼り付け。その後変数として取得して比較条件として取り扱います。
(微妙に改行コードやスペースが入っているのでsubstitute関数で置換)
Loop脱出条件は先ほど記載した通り、”FileMakerのスクリプト起動日時($curdatetime)” > “ファイルの更新日時($filedatetime)”となっています。
d.データ更新
#最新ファイル更新
全レコードを表示
対象レコードを削除 [ダイアログあり:オフ]
レコードのインポート [ダイアログあり:オフ; 「basic_info.text」; 追加; UTF-8]
カスタムダイアログを表示 [ "結果"; "処理完了時間:" & Get ( タイムスタンプ ) & "¶更新前時間:" &$filedatetime ]
今回のデータは差分更新が必要なデータでもなかったので、最新データで一気に洗い替えです。
まとめ
最後に処理が終わったことを確認するためにダイアログを出現させて完了です。
ちなみにデータスクレイピング部分をカットしてデータ形成だけ回したので、バッファー設定の5秒を足しても一瞬でしたが、スクレイピングを含めると、相手先サーバへの負荷を避けるためにあえて収集速度を落としているので普通に10分くらいかかりました。
今回はでアナログながらもFileMakerの「Event を送信する」コマンドにより外で動いているバッチの処理結果を受け取る工夫の話でした。
・ファイルの更新日時とスクリプト起動日時を比較
・クリップボードで間接的にデータを受け渡し
一応注意点としては、このスクリプトが動いている間は他のコピペできない…。ってことくらいですね(笑)。
次はCSVインポートの部分をPython側で(直接SQLへ)行うようにしたいな。と勉強中です。
コメント