python으로 매크로 제작하기
※ 이 글은 파이썬3을 기준으로 작성되었으니 참고하시기 바랍니다.
1. 매크로
▶ 살다보면 반복적인 작업을 해야하는 경우가 생각보다 많다.
▶ 또한 한정판 혹은 선착순 같은 상황에서 선택받지 못한 경우도 많다.
▶ 뮤지컬을 보러가거나 야구 티켓을 예매하는 경우도 마찬가지이다.
▶ 하다못해 RPG게임의 에픽퀘스트를 자동으로 깨주는 것도 포함이다.
2. pyautogui 모듈 사용
※ 시작하기 전 설치해야할 패키지와 파이썬 모듈이 있다.
▶ [sudo apt-get install python3-pip -y]는 파이썬 라이브러리를 설치 및 관리한다.
▶ [sudo apt-get install scrot -y]는 스크린샷 기능 및 사진 관련한 작업을 할 때 필요하다.
▶ [pip3 install pyautogui]는 pyautogui 모듈을 설치한다.
▶ [pip3 install python3-xlib]는 라이브러리의 호환성을 위해 추가적으로 설치해준다.
(1) position1.py
[1] 소스
import pyautogui as m while True: x, y = m.position() print('x : {}, y : {}'. format(x, y))
▶ 1라인은 pyautogui 모듈을 추가하고 마우스의 약자인 m이라고 부르려고 한다.
▶ 4라인은 마우스의 x좌표와 y좌표를 얻어온다.
[2] 시연
▶ 마우스를 움직이면 현재 마우스의 좌표가 출력되고 Ctrl+c를 누르면 종료된다.
▶ 종료될 때 KeyboardInterrupt가 발생한다.
(2) position2.py
[1] 소스
import pyautogui as m try: while True: x, y = m.position() print('x : , y : '.format(x, y)) except: print('Ctrl + C를 눌러서 프로그램을 종료합니다.')
▶ (1)의 소스와 동일하지만 try-except문을 추가하였다.
▶ 8라인의 except: 부분에 세부적으로 KeyboardInterrupt라고 명시해주어도 좋다.
[2] 시연
▶ Ctrl+c를 누르면 위와 같이 출력이 된다.
(3) position3.py
[1] 소스
import pyautogui as m try: while True: x, y = m.position() print('x : {}, y : {} '.format(x, y), end='\r') #position = 'x : {}, y : {}'.format(x, y) #print(position, end='') #print('\b'* len(position), end='') except KeyboardInterrupt: print('\b\bCtrl + C를 눌러서 프로그램을 종료합니다.')
▶ (2)와 비슷하지만 7라인에서 end='\r'을 추가하여 행의 맨 앞으로 이동하고 덮어쓴다.
▶ 이 경우 움직일 때마다 자연스럽게 마우스좌표가 변경되는 것처럼 보인다.
▶ 8, 9, 10라인과 같이 사용하여도 좋지만 3줄을 축약한 것이 7라인과 같다고 보아도 무방하다.
▶ 13라인의 print문은 \b를 사용하여 앞에 Ctrl+c시 기호로 출력되는 2개 문자를 지운다.
[2] 시연
▶ 결과적으로 마우스를 움직일 때마다 (2)보다 자연스럽게 출력되고 종료 시 except문 내에 print문으로 덮어씌워진다.
(4) position4.py
[1] 소스
import pyautogui as m try: while True: x, y = m.position() RGB = m.screenshot().getpixel((x, y)) print('x : {}, y : {}, RGB = {} '.format(x, y, RGB), end='\r') except KeyboardInterrupt: print('\b\bCtrl + C를 눌러서 프로그램을 종료합니다.')
▶ 7라인의 경우 현재 화면을 스크린샷을 찍고 getpixel(x, y)로 x와 y좌표의 위치에 있는 RGB색상표의 값을 반환한다.
▶ 8라인에서는 RGB값을 출력한다.
[2] 시연
▶ (3)과 달라진 점은 현재 마우스좌표의 색상까지 출력하는 것이다.
▶ 구지 이렇게 색상까지 출력하는 이유는 무엇일까?
- 아래로 내리면서 진행하다보면 이미지를 검색해서 특정이미지의 위치로 마우스포인터를 이동시키는 부분이 있기에...
(5) mouse_auto1.py
[1] 소스
import pyautogui as m import random chrome_button = { 'top_left' : {'x': 0, 'y' : 27}, 'bottom_right' : {'x' : 64, 'y' : 89} } #random.uniform(src, dst) = src < (float)random_value < dst x = random.uniform(chrome_button['top_left']['x'], chrome_button['bottom_right']['x']) y = random.uniform(chrome_button['top_left']['y'], chrome_button['bottom_right']['y']) m.moveTo(x, y, duration = 2) # ~동안에 = 2초간 x와 y의 좌표로 이동
▶ 이 소스는 position4.py를 이용해서 얻은 크롬의 좌표영역을 구한 후 클릭한다.
▶ 4라인부터 chrome_button 딕셔너리를 보면 크롬의 좌상단 좌표, 우하단 좌표로 사각형을 그릴 수 있다.
▶ random.uniform(a, b)는 a와 b사이의 랜덤한 값을 반환해주는 함수이다.
▶ 하나의 좌표를 주어도 되지만 매 번 같은 좌표만 이동할 경우 오토?같기 때문에 오해를 받지 않기 위해 범위 내에서 랜덤하게 받았다.
▶ moveTo(x, y) 와 같이 적어도 되지만 duration="초" 옵션을 넣어주면 오토같지 않도록 자연스럽게 2초간 마우스포인터가 이동한다.
[2] 시연
▶ 마우스가 움직이는 영상을 찍어야하기 때문에..
▶ 캑.. 뒤에 곰캠.. 모냥빠지넹...
(6) mouse_auto2.py
[1] 소스
import pyautogui as m import random #0,27 65,88 범위 내에 크롬이 있다. def rand(chrome_button): x = random.uniform(chrome_button['top_left']['x'], chrome_button['bottom_right']['x']) y = random.uniform(chrome_button['top_left']['y'], chrome_button['bottom_right']['y']) # random.uniform(a, b)는 a와 b사이 수 중에 랜덤한 값을 반환한다. return x, y def main(): chrome_button = { 'top_left' : {'x' : 0, 'y' : 27}, 'bottom_right' : {'x' : 65, 'y' : 88} } x, y = rand(chrome_button) #rand()함수에 chrome의 사각형 좌표를 넣고 이 중에서 x와 y를 반환받는다. m.moveTo(x, y, duration = 1) if __name__ == '__main__': main()
▶ (5)의 mouse_auto1.py를 함수로 작성한 것이다.
▶ 동일한 소스라서 시연내용도 동일하다.
(7) mouse_auto3.py
[1] 소스
import pyautogui as m import random import time def rand(chrome_button): x = random.uniform(chrome_button['top_left']['x'], chrome_button['bottom_right']['x']) y = random.uniform(chrome_button['top_left']['y'], chrome_button['bottom_right']['y']) # random.uniform(a, b)는 a와 b사이 수 중에 랜덤한 값을 반환한다. return x, y def click(): time.sleep(1) # 이동 후 1초 쉬고... m.click() # 파라미터가 없으면 현재 마우스좌표를 클릭 print('chrome을 클릭하였습니다.') time.sleep(4) # chrome browser가 뜨는동안 대기 m.typewrite('naver.com', interval=0.25) # 키보드로 입력, interval 옵션은 적지 않아도 무방 # interval = 한 글자 입력 후 대기시간 # 오토같지 않도록... print('주소에 "naver.com"을 입력하였습니다.') time.sleep(1) # 주소 입력 후 대기 m.press('enter') # press는 특정 키를 입력할 때 print('enter를 눌렀습니다.') return def login(): time.sleep(2) try: button = m.locateOnScreen('btn.png') # 버튼의 좌표는 왼쪽 위(x,y), 오른쪽 아래 (x,y)의 사각형 형태 # 아래 라인에서 이 좌표의 중심 좌표를 구하고 클릭! center = m.center(button) # button은 사각형 좌표고 사각형의 중심좌표를 center변수에 저장 print('button_center : ', center) except: print('해당이미지가 존재하지 않아 종료합니다.') exit(0) m.click(center) # 중심좌표 입력 print('Login 버튼을 클릭하였습니다.') def main(): chrome_button = { 'top_left' : {'x' : 0, 'y' : 27}, 'bottom_right' : {'x' : 65, 'y' : 88} } x, y = rand(chrome_button) #rand()함수에 chrome의 사각형 좌표를 넣고 이 중에서 x와 y를 반환받는다. m.moveTo(x, y, duration = 1) click() login() if __name__ == '__main__': main()
▶ 40라인의 btn.png는 우분투의 스크린샷을 이용해서 캡쳐하였다.
▶ locateOnScreen('img.jpg')은 img.jpg와 동일한 이미지를 현재화면 내에서 찾고 좌표를 반환한다.
▶ 이 부분은 못 찾을 경우 에러가 발생하기 때문에 예외처리도 해주어야 좋다.
▶ 찾는 그림이 크면 클수록 비교하는 것이 많아지기 때문에 조금 오래걸릴 수 있다.
▶ 찾는 방법은 내부적으로 RGB색상표를 이용하기 때문에 이미지 범위 내에 약간이라도 다르면 찾지 못한다.
[2] 시연
▶ time.sleep()를 내 환경에 맞게 조금 길게 하였다.
▶ 위와 같이 돌아가지만 만일 네이버가 나오기 전에 이미지검색을 하면 sleep()을 길게하면 된다.
▶ 지금은 굉장히 간단하게 웹브라우저 모듈을 이용하여 킬수도 있는 것을 매크로로 하고 있다.
▶ 맨 위에서 시작한 한정판이나 선착순은 시간 기준이기 때문에 시간을 확인할 수 있도록 해야할 듯 싶다.
(8) countdown.py
[1] 소스
from time import sleep as s # time모듈에서 sleep만 가져와서 s로 정의한다. def countdown(t): while t: # 0초가 아니면 mins = t // 60 # 현재 초 나누기 60 = 분 secs = t % 60 # 현재 초 나머지 60 = 초 print('Now = %02d:%02d' %(mins, secs), end='\r') s(1) t -= 1 return time = int(input('Countdown time input >>> ')) countdown(time)
▶ 시간을 입력하면 카운트다운이 진행된다.
[2] 시연
▶ 위와 같이 스톱워치가 동작한다.
(9) time_now.py
[1] 소스
import subprocess from time import sleep while True: result = subprocess.check_output("date | awk ''", shell=True) # 명령어 사용결과를 저장 # shell=True를 주지 않으면 명령어를 실행하고도 shell이 종료되지 않아 에러가 발생 result = str(result) # print(result[2:10], end='\r') result = result[2:10] a = result.split(':')[0] b = result.split(':')[1] c = result.split(':')[2] #17:34:50 #split(':')는 ''사이에 있는 문자로 나누고 그것을 리스트로 저장 # 0 -> 17 # 1 -> 34 # 2 -> 50 print(a, b, c) sleep(1)
▶ 11라인까지만 적으면 예쁜 시간이 출력되지만 split()함수로 시 분 초를 나누었다.
▶ 나눈 이유는 if문을 이용하여 특정 시간이 되면 매크로를 실행하거나 조건문을 쓸 수 있도록 하기 위함이다.
[2] 시연
▶ date명령어는 써보면 시간이 출력되는 것을 확인할 수 있다.
▶ 그렇다면 ask??? 이것은 특정 문자를 추출할 때 쓰이거나 정규표현식을 이용해서 사용할 수 있다.
▶ [date | awk ''] 는 date의 결과에서 5번째 단어를 찾아서 출력해준다.
▶ 이것은 현재 시간이 된다.
'Try Attack > python[basic]' 카테고리의 다른 글
python 에서 발생한 예외찾기 (0) | 2019.01.29 |
---|---|
python으로 zip파일 크랙하기 (0) | 2019.01.28 |
python 코드 분석 방법 (4) | 2019.01.25 |
python으로 Linux에서 zip파일 압축 및 해제 (0) | 2019.01.19 |
python으로 채팅구현하기 (0) | 2019.01.19 |
댓글