Try Attack/python[basic]

python으로 매크로 제작하기

D4tai1 2019. 1. 26.

※ 이 글은 파이썬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번째 단어를 찾아서 출력해준다.

  ▶ 이것은 현재 시간이 된다.

 

댓글