LoginSignup
0
0

More than 5 years have passed since last update.

PyAutoGuiでlocateCenterOnScreenが動かない

Posted at

あらまし

import pyautogui as pa
position = pa.locateCenterOnScreen("target.png")

locateOnScreen("target.png")は画面内にあるtarget.pngと一致する場所の中心の座標を出力する.

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    position = pa.locateCenterOnScreen("target.png")
  File "/home/USER/.pyenv/versions/anaconda3-4.1.1/lib/python3.5/site-packages/pyscreeze/__init__.py", line 122, in locateCenterOnScreen
    return center(locateOnScreen(image, grayscale))
  File "/home/USER/.pyenv/versions/anaconda3-4.1.1/lib/python3.5/site-packages/pyscreeze/__init__.py", line 105, in locateOnScreen
    screenshotIm = screenshot()
  File "/home/USER/.pyenv/versions/anaconda3-4.1.1/lib/python3.5/site-packages/pyscreeze/__init__.py", line 156, in _screenshot_linux
    raise NotImplementedError('"scrot" must be installed to use screenshot functions in Linux. Run: sudo apt-get install scrot')
NotImplementedError: "scrot" must be installed to use screenshot functions in Linux. Run: sudo apt-get install scrot

怒られてしまった.

実行環境

OS : Ubuntu 16.04 LTS
Shell : Zsh
Python : anaconda3-4.1.1 on pyenv

何を怒っているの?

scrotがないよ」と言われているが, もう既に導入している(scrotはターミナルからスクリーンショットを撮るコマンド). どうやらpyautoguiではなくpyscreezeからエラーが飛んでいるらしい. .../pyscreeze/__init__.pyscrotがインストールされているかどうかを判断するメソッドがちゃんと動いていないのかもしれない.

調査

.../pyscreeze/__init__.py内の変数scrotExistsscrotの有無を管理している:

try:
    if sys.platform not in ('java', 'darwin', 'win32'):
        whichProc = subprocess.Popen(['which', 'scrot'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        scrotExists = whichProc.wait() == 0

except:
    # if there is no "which" program to find scrot, then assume there is no scrot.
    pass

scrotがないよ」と怒ってくるのはscrotExistsがFalseになっているということ. subprocess.Popen().wait()が期待通りに動いていないのだろう. いろいろ手を動かしてみた結果, shell=Trueが怪しい.

Popen

shell=Trueを指定すると, Ubuntuでは実行するシェルが/bin/shになるらしい. shell=Falseだと自分の環境ではzshで実行される:

>>> sp.Popen("echo $0", shell=True).wait()
/bin/sh
0

>>> sp.Popen(["ps"]).wait()
  PID TTY          TIME CMD
 2418 pts/20   00:00:00 python
 2871 pts/20   00:00:00 ps
21011 pts/20   00:00:00 zsh
26515 pts/20   00:00:24 emacs
0

戻り値のゼロはリターンコード. 正常終了している. 見ての通り, "shell"の指定によってコマンドの書式が違う. 前者はstring, 後者はlistを渡している. /bin/shが悪さしてるのかなと思いきや, そうではなかった. 結局, 「shell=Trueかつstringで渡す」か「shell=Falseかつlistで渡す」かのどちらかではうまくいった. ちゃんと調べていないが, pythonのバージョンでsubprocess.popen()の仕様が違うのか, はたまた別の理由か.

これでうまく行くかと思いきや, まだ怒られる:

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    position = pa.locateCenterOnScreen("images/target.png")
  File "/home/USER/.pyenv/versions/anaconda3-4.1.1/lib/python3.5/site-packages/pyscreeze/__init__.py", line 120, in locateCenterOnScreen
    return center(locateOnScreen(image, grayscale))
  File "/home/USER/.pyenv/versions/anaconda3-4.1.1/lib/python3.5/site-packages/pyscreeze/__init__.py", line 106, in locateOnScreen
    screenshotIm.fp.close() # Screenshots on Windows won't have an fp since they came from ImageGrab, not a file.
AttributeError: 'NoneType' object has no attribute 'close'

screenshotIm.fpNonTypeだよ」と. もしcloseしなければならないオブジェクトだとしても, デストラクタがフォローしてくれるだろうと高をくくってこの部分をコメントアウト. 結果ちゃんと動いた.

教訓

とりあえず動いたのでgithubにPullRequestを投げようと思ったら, 既に修正されていた:

def locateAllOnScreen(image, **kwargs):
    screenshotIm = screenshot(region=None) # the locateAll() function must handle cropping to return accurate coordinates, so don't pass a region here.
    retVal = locateAll(image, screenshotIm, **kwargs)
    try:
        screenshotIm.fp.close()
    except AttributeError:
        # Screenshots on Windows won't have an fp since they came from
        # ImageGrab, not a file. Screenshots on Linux will have fp set
        # to None since the file has been unlinked
        pass
    return retVal

ご丁寧なコメント付き. バージョンを見てみるとgithubは0.1.8. conda cloudにあるのは0.1.0.
最新版を使いましょう. ちょっと勉強になった.

0
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
0
0