코딩은 전혀 할 줄 모르지만 관심은 있는 그런 상태로 살던 어느 날,
유튜브에 '기차 티켓팅 5초 만에 예약' 영상을 보게 되었고 영상 속 코딩 화면이 눈에 띄었다.
원래라면 질겁하며 도망쳤겠지만 지금은 다르다.
나는 챗gpt가 함께 있잖아?
지금부터 `**야매 코딩에 주의하세요!**`
매크로 작업환경 세팅
파이썬 설치는 필수 https://www.python.org/downloads/
+ 효율적인 작업을 위해 vscode 도 설치 https://code.visualstudio.com/download
매크로는 파이썬의 웹 자동화 도구를 활용한다. 보통 `selenium` 같은 라이브러리를 쓴다.
vscode 밑에 뜨는 터미널에다가 아래 명령어를 입력한다.
pip install selenium #매크로를 위한 셀레니움 라이브러리 설치
pip install pytz #파이썬에서 시간대를 다루기 위해 설치
특정 웹브라우저를 제어하기 위해 웹 드라이버를 설치해야 하는데, 나는 크롬을 쓸 예정이라 ChromeDriver를 설치해 줬다.
본인의 크롬 버전에 맞게 다운받아야 하는데 난 크롬 버전이 133이라 아래 링크에서 다운을 받았다.
https://googlechromelabs.github.io/chrome-for-testing/
다운받은 ChromeDriver 링크를 코드 상에 연결해줘야 한다.
Selenium 4에서는 `service` 객체를 사용하여 `chromedriver` 경로를 지정해야 하기 때문에 아래와 같이 코드를 완성했다.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
# ChromeDriver 경로 설정
service = Service('/크롬드라이버 경로')
# WebDriver에 Service 객체 전달
driver = webdriver.Chrome(service=service)
사이트 구조 파악하기
이번에 구현해 보려는 기능은
자동으로 로그인하고, 예약버튼 누르고, 전화번호 등 인적사항도 자동으로 입력하는 기능이다.
인터넷은 HTML 코드로 이루어져 있고, 그 안에는 `div`, `p`, `a` 와 같은 태그들이 무수히 많다.
여기서 로그인 버튼, 입력 탭 등의 '정확한 위치'를 전달하기 위해 `XPath`를 이용한다. 일종의 좌표값인 셈.
`XPath`를 파악하기 위해선 우클릭을 해제해야 하는데 대부분의 예약 페이지는 우클릭을 막아 놨기 때문에 크롬 확장프로그램을 설치해서 쉽게 우클릭을 허용해 준다.
Right Click Enable - 오른쪽 클릭 활성화 - Chrome 웹 스토어
우클릭 활성화 - 효과적이고 편리한 컨텍스트 메뉴 활성화기가 차단된 사이트에서 우클릭 메뉴를 허용하도록 합니다.
chromewebstore.google.com
그런 다음 예약버튼 위 우클릭 - 검사를 눌러주면 괴랄하지만 뭔가 있어 보이는 영어들이 뜨는데
거기서 음영처리 된 부분 위에서 또 우클릭 - copy - copy XPath를 해주면 된다.
그럼 아마 `//*[@id =`이런 모양으로 얻은 문자열이 나올 텐데 이걸 예약 버튼 관련 코드의 `By.XPATH` 값에 넣어주면 된다.
지금은 예시가 예약버튼이지만 자동 로그인을 원하면 로그인 버튼,
자동으로 이름이 입력되길 원하면 입력 탭 등 각 고유의 `XPath` 값을 가져와서 코드에 넣어주면 된다.
# 예약 버튼 클릭 (xpath로 지정한 예약 버튼)
reserve_button = driver.find_element(By.XPATH, '예약버튼 XPath 값')
reserve_button.click()
시간 설정하기
예약은 보통 특정시간을 기준으로 활성화되기 때문에 그전까지 대기 후 특정 시간에 자동실행되게 해야 한다.
- `datetime` 체크하면서 예약 가능한 순간까지 대기
- 정확한 `XPath` 값으로 예약 버튼 빠르게 클릭
- `while`, `if` 등 활용해 성공할 때까지 반복 시도
키워드 | 설명 |
`while` | 조건이 참일 때 계속 반복 |
`if` | 조건이 참일 때 특정 코드 실행 |
`try` | 에러가 날 수도 있는 코드 실행 |
`except` | 에러가 발생하면 실행할 코드 지정 |
`break` | 반복문 강제 종료 |
자정에 새로고침이 되게 해야 하지만,
실제로 서버시간이 되어 새로고침 명령이 넘어가기까지의 미세한 차이가 있기 때문에
딱 00시 00분 00초 새로고침이 아닌, 23시 59분 58초 이상이라는 조건으로 수정했다.
while True:
`while`이 조건이 참일 때 계속 반복하는 거라, 뒤에 true를 붙여주면 무한 반복하는 코드가 된다.
WebDriverWait(driver, 10)
WebDriverWait : 웹 드라이버가 특정 조건을 만족할 때까지 기다리기
(driver) : 실행 중인 웹드라이버 객체 - 크롬, 사파리 등
(10) : 최대 대기시간 (초)
= 웹 드라이버가 특정 조건을 만족할 때까지 10초 기다리기. 주로 `.until`과 함께 쓰인다.
EC
Expected Conditions의 약자. `selenium` 에서 제공하는 모듈로, 웹 요소가 특정 조건을 만족하는지 확인하는 함수 제공.
- EC.presence_of_element_located : 요소가 존재하는지 확인
- EC.visibility_of_element_located : 요소가 화면에 보이는지 확인
try: ~
except Exception as e:
try 다음 코드를 실행하다가 오류가 발생하면 except 다음 코드를 실행한다. Exception as e 는 변수 `e`에 오류 사항을 저장하겠다는 뜻.
f " {} "
`f-string` 으로 문자열 앞에 `f`를 붙이면 문자열 안에서 변수를 쓸 수 있다. 변수처리는 중괄호 `{}`
now.strftime('%H:%M:%S')
strftime 은 string format time 의 줄임말로, 날짜와 시간을 문자열(string)로 변환하는 함수. `now.strftime`은 현재의 날짜와 시간을 불러온다는 것이고, 반드시 괄호 안에 원하는 형식을 넣어야 한다. `%m`은 month, `%M`은 Minute을 나타내니 헷갈리지 말기!
완성하면 이렇게 코드가 나온다.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from datetime import datetime
import time
import pytz
# ChromeDriver 경로 설정 (다운로드 폴더에 있는 chromedriver)
service = Service('/ChromeDriver 경로')
# WebDriver에 Service 객체 전달
driver = webdriver.Chrome(service=service)
# 예약 사이트 열기
driver.get('예약 사이트 주소')
# 서울 시간대 설정
seoul_tz = pytz.timezone('Asia/Seoul')
# 예약
while True:
# 현재 시간을 서울 시간으로 확인
now = datetime.now(seoul_tz)
# 예약 시도
if now.hour == 23 and now.minute == 59 and now.second >= 58:
print("일찍 새로고침!")
driver.refresh()
# 페이지가 완전히 새로고침될 때까지 대기
try:
# 예약 버튼이 로드될 때까지 기다리기
reserve_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, '예약버튼 XPath'))
)
reserve_button.click()
print("예약 버튼 클릭 완료")
# 예약 페이지로 넘어갔는지 확인 (페이지 URL 변경 체크)
WebDriverWait(driver, 10).until(EC.url_changes(driver.current_url))
print("예약 창으로 넘어갔습니다!")
break # 예약 완료 후 반복 종료
except Exception as e:
print("예약 버튼 클릭 오류:", e)
time.sleep(2) # 2초 후 다시 시도
# 정해진 시간까지 대기
print(f"현재 시간: {now.strftime('%H:%M:%S')} - 대기 중...")
time.sleep(5) # 5초마다 현재 시간 확인