1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自動化:Windowsアプリから、必要な情報を読み取る

Posted at

はじめに

Windowsアプリを操作して、とある情報を読み取りたくなりました。

私が読み取りたくなった情報とは、LINEのWindows版のアプリで、グループ・オープンチャットの人数です。もしかしたら自動化は規約違反かもしれません。真似しようとされる方は、ご自身の責任で行ってください。

ちなみに今回の方法は、手で操作するよりかなり遅いです🤣 当然サーバーへの負荷は人の操作以下です。

でもLINEに限らず、こういうことをしたい場面はかなり頻繁にあり、応用範囲は広いと思います。この記事は、LINEアプリを題材にしたコーディング例であって、他の場面で応用していただくことを目的と考えています。

毎日やらないといけないとしたら、遅くても勝手に取得してくれれば、脳みそを使わず情報が採取できるので、自動化の意味は十分あります。

ご相談などありましたらコメント欄やXなどからご連絡ください。

概要

  • Pythonのpywinautopyautoguiで、知りたい情報を得る(矩形位置、構造)
  • pyautoguiで、クリック
  • pyautoguiで、キャプチャして画像に保存
  • yomitokuで、画像をでOCRして、取得したい文字をGET
    • OCRを使った理由は、LINEはQtで作られていて、その場合はコントロールの値を取得することができなさそうだから(取得できる方法があったら教えてください)

WindowsのLINEアプリがこちら。適当にぼかしてます。「高津区の情報広場」というオープンチャットに153名参加しているのですが、この153という数字を取得します。
screen1.png

  1. 「メディア事業部」というタブのようなボタンのような部分をクリックし
  2. 左ペインに一覧が出るからその中から「高津区の情報広場」を探して
  3. 丸カッコに括られた数字を得る

詳細

0. 前提

LINEアプリ(他のアプリでも)が、プログラミング的にどういう部品をどういう構成で作られているのか知る必要があります。
そのために、Inspectというツールを使います。

Inspectは、Microsoftのサイトから、Windows SDKをダウンロード、インストールすることができます。すごく奥まったところ(2025/10/9時点では、"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\inspect.exe")に格納されます。

1. 位置を探る

まずウィンドウタイトルからトップの要素を取得します。

window_title = "LINE"
app = pywinauto.Application(backend="uia").connect(title_re=window_title)
main = app.window(title_re=window_title)
# 最小化されていたら復元
if main.is_minimized:
    main.restore()
# アクティブ化
main.set_focus()

そのmainを使って、main.children()とかmain.class_name()を使います。childrenもみんな同じクラスで、for child in main.children():で得たchildも同様の関数が使えます。class_nameは、Inspectの表示で、ClassNameという項目があるので、それを見ながら、知りたいコントロール(LabelとかListViewとか)を取得します。

知りたいコントロールを取得する理由は、その矩形の位置情報を得たいから。control.rectangle().leftcontrol.rectangle().topcontrol.rectangle().rightcontrol.rectangle().bottomで取得します。

2. クリック

クリックは、位置をしていする必要があるので、コントロールの左上から、少し右下へズレた位置をクリックします。

pyautogui.click(control_left + 5, control_top + 5)

3. キャプチャして画像保存

位置情報は、left, right, top, bottomだけど、スクリーンショットはwidth, heightなので計算してスクリーンショットします。

width = right - left
height = bottom - top
img = pyautogui.screenshot(region=(left, top, width, height))
img.save(f"temp/img_{left}_{top}_{right}_{bottom}.png")

4. YomiTokuでOCR

PythonのOCRで調べるとTesseractというツールが出てきますが、少なくとも日本語のOCRではまったく役に立ちません。日本語辞書を入れてもです。(個人の意見です)

そこで、機械学習のYomiTokuというライブラリを使いました。

これはガチの機械学習のやつで、GPUで動くCUDAが設定されていればいいけど、かなり遅いCPUモードで動きます。ちなみに私はCUDA環境がないのでCPUモード。なのでかなり遅いです。でも動くし、OCRの精度も私は十分。

pip install yomitokuで設定できるお手軽さなんだけど、実行するときは、プロセス実行。。なぜPythonからの呼び出しを用意してくれないのだろうか。。(悲)

subprocess.run(["yomitoku", img_file_path, "-f", "json", "-o", "temp"])

このコードによって、画像ファイルをOCRして、結果のjsonファイルを、tempフォルダへ出力してくれます。

出てきたJsonをたどれば文字列を得られる。ついでに文字列が入ったboxの矩形も得られる。

私は下記のように、figures>paragraphsparagraphsにあるcontentsboxを単純な配列に入れる汎用関数を用意しました。利用する処理が、単純な配列からそれっぽいものを探せばよい。

texts = []
for figure in json_data["figures"]:
    for paragraph in figure["paragraphs"]:
        texts.append({
            "contents": paragraph["contents"],
            "box": paragraph["box"]
        })
for paragraph in json_data["paragraphs"]:
    texts.append({
        "contents": paragraph["contents"],
        "box": paragraph["box"]
    })
#print(texts)

return texts

おわりに

大体こんな感じです。

今回はLINEでやってみましたが、他のシステムでも使える技です。ブラウザで見るウェブシステムですらいけそう。OCRを使わない自動化であれば、ササっと動く。ブラウザをInspectで見てみたら、コントロールの値も取得できたので、OCRは不要そう。Qtのexeでも値を取得できればOCRを使わずにいけるのにな。

OCRという技術は、GCPなどのサービス(Cloud Vision APIなど)やChatGPTの中で大活躍だけど、逆に手元では廃れつつある気がしますね。数年前の形態素解析とかゼロから作るDeepLearningみたい。

ではよき自動化ライフを!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?