あらまし
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__.py
のscrot
がインストールされているかどうかを判断するメソッドがちゃんと動いていないのかもしれない.
調査
.../pyscreeze/__init__.py
内の変数scrotExists
がscrot
の有無を管理している:
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.fp
がNonType
だよ」と. もし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
.
最新版を使いましょう. ちょっと勉強になった.