레이블이 uiautomator2인 게시물을 표시합니다. 모든 게시물 표시
레이블이 uiautomator2인 게시물을 표시합니다. 모든 게시물 표시

2022년 5월 22일 일요일

weditor 설치 방법, UnicodeDecodeError: 'cp949' 해결방법

weditor

openatx에서 만든 uianimator2에서 UI script를 쉽게 사용하기 위한 web app입니다. 해당 어플이 있으면 좀 더 쉽게 스크립트 작성이 가능합니다.

설치 방법은 pip install weditor 이라고 하면 되는데 종종 아래와 같은 오류가 발생합니다.


C:\Users>pip install weditor

Collecting weditor

  Downloading https://files.pythonhosted.org/packages/04/9b/ec6c2b8ab08fecd21d98121e2b91244632d1836669bb9c917ff01406bd1a/weditor-0.6.5.tar.gz (2.2MB)

     |████████████████████████████████| 2.2MB 3.3MB/s

    ERROR: Command errored out with exit status 1:

     command: 'c:\users\user\appdata\local\programs\python\python38\python.exe' -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\USER\\AppData\\Local\\Temp\\pip-install-mn6ozje2\\weditor\\setup.py'"'"'; __file__='"'"'C:\\Users\\USER\\AppData\\Local\\Temp\\pip-install-mn6ozje2\\weditor\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base pip-egg-info

         cwd: C:\Users\USER\AppData\Local\Temp\pip-install-mn6ozje2\weditor\

    Complete output (22 lines):

    ERROR:root:Error parsing

    Traceback (most recent call last):

      File "c:\users\user\appdata\local\temp\pip-install-mn6ozje2\weditor\.eggs\pbr-5.9.0-py3.8.egg\pbr\core.py", line 111, in pbr

        attrs = util.cfg_to_args(path, dist.script_args)

      File "c:\users\user\appdata\local\temp\pip-install-mn6ozje2\weditor\.eggs\pbr-5.9.0-py3.8.egg\pbr\util.py", line 272, in cfg_to_args

        pbr.hooks.setup_hook(config)

      File "c:\users\user\appdata\local\temp\pip-install-mn6ozje2\weditor\.eggs\pbr-5.9.0-py3.8.egg\pbr\hooks\__init__.py", line 25, in setup_hook

        metadata_config.run()

      File "c:\users\user\appdata\local\temp\pip-install-mn6ozje2\weditor\.eggs\pbr-5.9.0-py3.8.egg\pbr\hooks\base.py", line 27, in run

        self.hook()

      File "c:\users\user\appdata\local\temp\pip-install-mn6ozje2\weditor\.eggs\pbr-5.9.0-py3.8.egg\pbr\hooks\metadata.py", line 25, in hook

        self.config['version'] = packaging.get_version(

      File "c:\users\user\appdata\local\temp\pip-install-mn6ozje2\weditor\.eggs\pbr-5.9.0-py3.8.egg\pbr\packaging.py", line 860, in get_version

        version = _get_version_from_pkg_metadata(package_name)

      File "c:\users\user\appdata\local\temp\pip-install-mn6ozje2\weditor\.eggs\pbr-5.9.0-py3.8.egg\pbr\packaging.py", line 828, in _get_version_from_pkg_metadata

        pkg_metadata = email.message_from_file(pkg_metadata_file)

      File "c:\users\user\appdata\local\programs\python\python38\lib\email\__init__.py", line 54, in message_from_file

        return Parser(*args, **kws).parse(fp)

      File "c:\users\user\appdata\local\programs\python\python38\lib\email\parser.py", line 53, in parse

        data = fp.read(8192)

    UnicodeDecodeError: 'cp949' codec can't decode byte 0xad in position 825: illegal multibyte sequence

    error in setup command: Error parsing C:\Users\USER\AppData\Local\Temp\pip-install-mn6ozje2\weditor\setup.cfg: UnicodeDecodeError: 'cp949' codec can't decode byte 0xad in position 825: illegal multibyte sequence


해당 어플이 unicode를 고려해서 작성되지 않았기 때문입니다.

이런경우 수동으로 설치하도록 합니다.

https://github.com/alibaba/web-editor 여기 접속해서 소스를 받아서 cfg 파일을 수정해도 되지만, 여기에서는 github에 있는 최신 버전을 설치해도 해결됩니다.

해결 방법은 아래와 같습니다.

pip install git+https://github.com/alibaba/web-editor.git


실행방법

weditor 만 실행시키고 자동으로 브라우저를 띄우면 됩니다. 다만 IE는 지원하지 않기 때문에 크롬으로 http://localhost:17310/ 주소를 열어줍니다. 포트 번호는 weditor를 실행시키면 로그에 나오게 됩니다.

C:\Users>weditor

listening on http://192.168.0.18:17310

[I 220522 14:48:29 web:2239] 200 GET / (::1) 251.33ms

[I 220522 14:48:30 web:2239] 200 GET /cdn.jsdelivr.net/bootstrap/3.3.7/css/bootstrap.min.css (::1) 1176.85ms

[I 220522 14:48:30 web:2239] 200 GET /cdn.jsdelivr.net/npm/jstree@3.3.8/dist/themes/default/style.min.css (::1) 9.98ms

[I 220522 14:48:30 web:2239] 200 GET /static/libs/css/buttons.css (::1) 22.94ms

[I 220522 14:48:30 web:2239] 200 GET /static/libs/fontawesome/css/font-awesome.min.css (::1) 32.91ms

[I 220522 14:48:30 web:2239] 200 GET /cdn.jsdelivr.net/bootstrap.select/1.12.2/css/bootstrap-select.min.css (::1) 37.90ms

[I 220522 14:48:30 web:2239] 200 GET /static/style.css?v=9f60773ea7a93488c91ffc68ab65f5401ef20f496b28d3354df7f635fdb4b8b94e0e4dcc476e74d4964d687c774abdb0e83341777dc0b483f3a338a5cd8db027 (::1) 44.88ms


이런식으로도 해결이 안되는 패키지가 있을 수 있습니다. 즉, 개발자가 git에 수정된 소스를 업데이트 하지 않은 경우입니다. 그런 경우 git에서 소스를 직접 받아서 직접 소스 수정한 후 로컬에서 설치합니다.


수정 방법

아래와 같이 open할때 마지막에 encoding="utf-8" 이런식으로 넣어 주면 됩니다.

output = open("output.txt", "wt", encoding="utf-8")


설치 방법 링크 참조

https://swlock.blogspot.com/2022/04/python-github-creating-and-installing.html

만약 소스 코드에 로컬에 있다면 아래와 같이 설치합니다.

python setup.py install


2022년 4월 10일 일요일

uiautomator2 로 screenshot 비교하기

uiautomator2로 android에서 자동화를 해보기위해서 이것저것 해보고 있습니다. 도움이 될만한 내용들을 정리해 보았습니다.


1. 현재앱 알아내기

print(d.app_current())

출력 형태

{'package': 'com.android.settings', 'activity': '.homepage.SettingsHomepageActivity', 'pid': 14781}


2. 앱 실행키시기

app_start로 실행합니다. 이때인자는 패키지 이름입니다. 앱을 실행 시킨 후 app_wait로 pid를 얻어 올 수 있습니다.

		d.app_start(test_package)
		pid = d.app_wait(test_package, timeout=20.0)
		if not pid:
			print(f"{test_package} is not running")
		else:
			print(f"{test_package} pid is {pid}")


3. 화면 구성값 가져오기

xml 형태로 저장됩니다.

		xml = d.dump_hierarchy()
		print("saving xml")
		write_file("hierarchy.xml",str(xml))

형태가 복잡해서 전체 예제를 실행시키면 저장하도록 해놨습니다. 파일을 열어보시길 추천합니다.


4. 스크린샷 찍어 저장하기

확장자에 따라서 png, jpg 형태로 저장이 가능합니다.

		image = d.screenshot()
		if not exists(test_image_name):
			image.save(test_image_name)
			print("save screenshot")


5. 키보내기

여러 종류의 키를 보낼 수 있습니다.

d.press("home")

숫자값으로 보낼때는 여기 참고

https://developer.android.com/reference/android/view/KeyEvent

텍스트는 아래 참고

home

back

left

right

up

down

center

menu

search

enter

delete ( or del)

recent (recent apps)

volume_up

volume_down

volume_mute

camera

power


6. 종합 screenshot 찍어서 이전 저장된 사진과 비교하기

전체 소스

from os.path import exists
import uiautomator2 as u2
import adbutils
import time
from PIL import Image
from PIL import ImageChops
import math, operator

test_image_name = "testimage.png"
test_package = "com.android.settings"


def write_file(filename,str_data):
	with open(filename, 'w', encoding="utf-8") as fp:
		fp.write(str_data)
		fp.close()
		
def images_are_similar(img1, img2, error=90):
	print(img1.size[0],img1.size[1]) # xsize, ysize
	diff = ImageChops.difference(img1, img2).histogram()
	# [ r 256 , g 256 , b 256 ] = 768 list
	print(len(diff))
	print(diff)
	sq = (value * (i % 256) ** 2 for i, value in enumerate(diff))
	sum_squares = sum(sq)
	print(sum_squares)
	rms = math.sqrt(sum_squares / float(img1.size[0] * img1.size[1]))
	print(rms)
	return rms < error
	
if __name__ == "__main__":
	d = None
	for dev in adbutils.adb.device_list():
		print("Dev:", dev)
		d = u2.connect(dev.serial)

	if d==None:
		print("please check connected devices (adb devices)")
	else:
		d.screen_on()
		d.unlock()
		d.press("home")

		print(d.app_current())
		d.app_start(test_package)
		pid = d.app_wait(test_package, timeout=20.0)
		if not pid:
			print(f"{test_package} is not running")
		else:
			print(f"{test_package} pid is {pid}")

		xml = d.dump_hierarchy()
		print("saving xml")
		write_file("hierarchy.xml",str(xml))
		image = d.screenshot()
		if not exists(test_image_name):
			image.save(test_image_name)
			print("save screenshot")
		else:
			# compare
			image.save("new"+test_image_name)
			pimage = Image.open(test_image_name)
			#for test sdiff = images_are_similar(image,image)
			sdiff = images_are_similar(image,pimage)
			print(sdiff)
		print(d.app_current())
		d.press("home")


7.이미지 비교 함수 설명

images_are_similar

여기에 넘어가는 이미지는 PIL type입니다. size[0], size[1]은 각각 가로 세로 크기입니다.

기본 원리는 image의 diff를 구하는것입니다. 이것은 ImageChops.difference(img1, img2) 와 같은 형태로 구할 수 있습니다.

다음으로는 histogram()을 취하게 되는데 histogram은 R, G, B 각각 256개로 모두 768 개를 지닙니다. 

일반적으로 delta를 수치로 표현할때 표준편차를 구해서 비교하는데 여기에서는 이미지 histogram의 표준 편차를 구해서 특정값보다 크게 되면 차이가 난다고 판단합니다. 임의의 기준을 여기에서는 90으로 정했으며 조정 가능한 값입니다.

같은 이미지로 시험하면 아래와 같은 histogram을 얻게 됩니다. 여기에 들어가 있는 2592000 는 가로*세로 즉 점의 갯수가 됩니다. 1080 2400 화면에서는 아래와 같습니다.

[2592000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2592000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2592000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

그리고 첫번째는 R의 0번값이며 2592000 수치를 나타낸다는 의미는 점을 빼줬기 때문에 0을 가진다는 의미입니다.

만약 다른 이미지로 테스트했다면 아래와 같은 형태가 될것입니다.


중간이미지가 diff(차)연산으로 나온 이미지인데 이것을 histogram을 해서 표준 편차를 구한다는 의미입니다.  

여기에서는 이미지가 같게 되면 rms 수치가 작아지게 되고 images_are_similar True값이 리턴됩니다.