3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

pyautoguiで「これ動かないな?」となったときの確認点まとめ

Posted at

目的

以前、タイピングを高速するとの目的でpyautoguiを触ってみたが、先日仕事としてpyautoguiを触ることになった。
その際に得た知見を、自分なりにまとめておく。

仕事の中身

簡単に言うと、csv形式のファイルをwebアプリ経由でサーバにアップロードするだけの仕事。
ただし、2025年の壁を超えれない企業の作ったアプリなため、下記のような制限がかかる。

  • アップロードされたcsvを1行処理するのに30秒~1分かかる
  • csvの行数が長すぎると上記処理がタイムアウトする
  • 2窓すると片方の処理がもう片方の処理にコピーされてバグる

どうやったらこんな作りになるのか一切僕には理解できなかったが、
ただの派遣の作業員の身である自分には正す義理も義務も権限もない。

できるだけ自分の知識と評価にするために自動化し、後続の人にも使いやすいコードを残しておくことにした。

コード

動かなかったコード

ざっくり書くと、下記のようなコードが最初に作った駄目な例。

(セイウチ演算子って便利だね)

import pyautogui as gui


def wait_and_get_pos_from_image(image_path: str, interval: float = 1, max_try: int = 10):
    """特定の画像が表示されるまで待機する

    :param image_path: 比較対象の画像
    :param interval: 確認する感覚
    :param max_try: 最大確認回数(この回数超えても見つけられなければエラー)
    :return: 見つけた場所の中央を返す
    """

    for _ in range(max_try):
        if (position := gui.locateCenterOnScreen(image_path)) is not None:
            return position

        gui.sleep(interval)

    raise TimeoutError("画像を指定時間内に見つけられませんでした。")


def set_locate(path: str):
    """Ctrl+L→パス出力
    ブラウザもファイルダイアログも同様の処理でOKなためまとめる。

    :param path: 書き込みたいパス
    :return:
    """

    gui.hotkey("ctrl", "l")
    gui.write(path)
    gui.press("enter")


if __name__ == '__main__':
    # ※ブラウザはすでに開かれているものとする。

    # 開きたいwebアプリへのパスを書き込む
    set_locate(r"https://qiita.com/")

    gui.click(wait_and_get_pos_from_image("「投稿する」ボタンの画像"))
    gui.click(wait_and_get_pos_from_image("「記事」の画像"))

    gui.click(wait_and_get_pos_from_image("画像をアップロードするボタン"))

    gui.write("画像へのファイルパス")
    gui.press("enter")

何がいけなかったか

主に下の3点。

修正したコード

上記の注意点を元に修正を施したら期待通りの動作をするようになった。
具体的には下記のコードのような修正を行っている。

import pyautogui as gui
import pyperclip as clip


def wait_and_get_pos_from_image(image_path: str, interval: float = 1, max_try: int = 10):
    """特定の画像が表示されるまで待機する

    :param image_path: 比較対象の画像
    :param interval: 確認する感覚
    :param max_try: 最大確認回数(この回数超えても見つけられなければエラー)
    :return: 見つけた場所の中央を返す
    """

    for _ in range(max_try):
        # 若干の画像のブレは許容する
        if (position := gui.locateCenterOnScreen(image_path, confidence=0.9)) is not None:
            return position

        gui.sleep(interval)

    raise TimeoutError("画像を指定時間内に見つけられませんでした。")


def set_locate(path: str):
    """Ctrl+L→パス出力

    :param path: 書き込みたいパス
    :return:
    """

    # パスの入力はクリップボード経由で行う
    gui.hotkey("ctrl", "l")
    clip.copy(path)
    gui.hotkey("ctrl", "c")
    gui.press("enter")


if __name__ == '__main__':
    # ※ブラウザはすでに開かれているものとする。

    # 開きたいwebアプリへのパスを書き込む
    set_locate(r"https://qiita.com/")

    gui.click(wait_and_get_pos_from_image("「投稿する」ボタンの画像"))
    gui.click(wait_and_get_pos_from_image("「記事」の画像"))

    gui.click(wait_and_get_pos_from_image("画像をアップロードするボタン"))

    # ダイアログの表示待ちを行う
    gui.sleep(1)
    # パスの入力はクリップボード経由で行う
    gui.hotkey("ctrl", "l")
    clip.copy("画像のファイルパス")
    gui.hotkey("ctrl", "c")
    gui.press("enter")

このコードを元にしたツールを使ってcsvファイルを流し込むことにより、膨大な待ち時間とそれを確認する不毛な作業をもう少し生産性の高い作業に置き換えることが出来た。

3
6
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
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?