Selenium을 활용해서 인터파크 티켓예매 과정을 자동화해보자
* 반복적으로 사용시, 매크로로 감지하여 정지먹음 주의 (selenium 연습용으로만 사용하자)
+ element 제어기 안된다는 댓글이 많아서 추가
셀레늄 감지 방지 코드 (요소가 클릭이 안될때 아래 코드를 추가하여 셀레늄 감지를 피할 수 있다) ↓
2024.11.15 - [개발기록/python] - [python] selenium-stealth 셀레늄 감지 방지 (구글 크롬)
1. 패키지 설치
먼저 필요한 패키지들을 설치해준다
pip install selenium
pip install easyocr (부정예매 방지 문자 입력용 OCR 모듈)
기존에 파이썬 3.12 버전을 사용중이었는데, 이 버전에서는 easyocr이 설치되지 않아서 3.8 버전으로 가상환경을 새로 생성해주었다
파이썬 버전별 가상환경 설치 방법은 아래 링크 참조 ↓ ↓ ↓
2023.11.05 - [개발기록/python] - [python] 파이썬 버전별 가상환경 설치 (+virtualenv)
2. 모듈 import
import selenium
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import Select
import time
import easyocr
3. 웹 드라이버 설정
# 브라우저 꺼짐 방지 옵션
chrome_options = Options()
chrome_options.add_experimental_option("detach", True)
# 드라이버 생성
driver = webdriver.Chrome(options=chrome_options)
# 브라우저 사이즈
driver.set_window_size(1900, 1000)
# 웹페이지가 로드될 때까지 2초를 대기
driver.implicitly_wait(time_to_wait=2)
driver.get(url='https://tickets.interpark.com/')
4. 로그인
driver.find_element(By.LINK_TEXT,'로그인').click()
driver.switch_to.frame(driver.find_element(By.XPATH, "//div[@class='leftLoginBox']/iframe[@title='login']"))
userId = driver.find_element(By.ID, 'userId')
userId.send_keys('아이디')
userPwd = driver.find_element(By.ID, "userPwd")
userPwd.send_keys('패스워드')
userPwd.send_keys(Keys.ENTER)
5. 티켓 예매 페이지로 이동
검색창에서 예매할 티켓의 이름을 입력하여 예매페이지로 이동
# 검색
search = driver.find_element(By.XPATH,'//*[@id="__next"]/div/header/div/div[1]/div/div[1]/div[3]/div/input')
search.send_keys('싸이 올나잇')
search.send_keys(Keys.ENTER)
#예매 페이지로 이동
driver.find_element(By.XPATH,'//*[@id="__next"]/div/main/div/div/div[1]/div[2]/a[1]/div[1]').click()
6. 예매하기 버튼 클릭
예매하기 버튼을 누루기 전에, 새로 생선된 탭으로 이동해줘야 한다
(print(driver.window_handles) 코드를 사용하면, 윈도우가 2개 생성되어 있는 것을 알 수 있다
그 중에서 새로 생긴 탭으로 이동하기 위해, driver.switch_to.window(driver.window_handows[-1] 코드로 마지막으로 생성된 탭으로 이동)
# 새로운 탭으로 이동
print('--------------------')
print(driver.window_handles)
driver.switch_to.window(driver.window_handles[-1])
#예매하기 버튼 클릭
driver.find_element(By.XPATH,'//*[@id="productSide"]/div/div[2]/a[1]').click()
7. 예매하기 창
새로운 예매하기 창이 생성되어서 drivre.switch_to.window(driver.windos_handles[-1])로 이동해준다
다음으로 아이프레임을 이동해서, 부정예매 방지 코드가 있는 element 에 접근해준다
(* 인터파크 예매 페이지는 여러개의 아이프레임으로 구성되어 있어서, 요소를 찾기위해 아이프레임을 잘 선택하는 것이 중요하다)
# 새로운 탭으로 이동
print(driver.window_handles)
driver.switch_to.window(driver.window_handles[-1])
# 아이프레임으로 이동
driver.switch_to.frame(driver.find_element(By.XPATH, "//*[@id='ifrmSeat']"))
8. 부정예매 방지코드 입력 OCR
# 부정예매방지문자 OCR 생성
reader = easyocr.Reader(['en'])
# 부정예매방지 문자 이미지 요소 선택
capchaPng = driver.find_element(By.XPATH,'//*[@id="imgCaptcha"]')
# 부정예매방지문자 입력
while capchaPng:
result = reader.readtext(capchaPng.screenshot_as_png, detail=0)
capchaValue = result[0].replace(' ', '').replace('5', 'S').replace('0', 'O').replace('$', 'S').replace(',', '')\
.replace(':', '').replace('.', '').replace('+', 'T').replace("'", '').replace('`', '')\
.replace('1', 'L').replace('e', 'Q').replace('3', 'S').replace('€', 'C').replace('{', '').replace('-', '')
# 입력
driver.find_element(By.XPATH,'//*[@id="divRecaptcha"]/div[1]/div[3]').click()
chapchaText = driver.find_element(By.XPATH,'//*[@id="txtCaptcha"]')
chapchaText.send_keys(capchaValue)
#입력완료 버튼 클릭
driver.find_element(By.XPATH,'//*[@id="divRecaptcha"]/div[1]/div[4]/a[2]').click()
# 입력이 잘 됐는지 확인하기
display = driver.find_element(By.XPATH,'//*[@id="divRecaptcha"]').is_displayed()
# 입력 문자가 틀렸을 때 새로고침하여 다시입력
if display:
driver.find_element(By.XPATH,'//*[@id="divRecaptcha"]/div[1]/div[1]/a[1]').click()
# 입력 문자가 맞으면 select 함수 실행
else:
select()
break
입력문자가 틀렸을 경우, 오른쪽의 새로고침 버튼을 클릭하여 첨부터 다시 문자입력한다
9. 좌석선택
# 좌석 탐색
def select():
print(driver.window_handles)
driver.switch_to.window(driver.window_handles[-1])
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmSeat"]'))
# 좌석등급 선택
#driver.find_element(By.XPATH,'//*[@id="GradeRow"]/td[1]/div/span[2]').click()
while True:
# 세부 구역 선택
driver.find_element(By.XPATH,'//*[@id="GradeDetail"]/div/ul/li[1]/a').click()
# 좌석선택 아이프레임으로 이동
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmSeatDetail"]'))
# 좌석이 있으면 좌석 선택
try:
driver.find_element(By.XPATH,'//*[@id="Seats"]').click()
# 결제 함수 실행
payment()
break
# 좌석이 없으면 다시 조회
except:
print('******************************다시선택')
driver.switch_to.default_content()
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmSeat"]'))
driver.find_element(By.XPATH,'/html/body/form[1]/div/div[1]/div[3]/div/p/a/img').click()
time.sleep(1)
(좌석이 있으면, id가 "Seats"인 Element 가 존재한다)
10. 결제하기
좌석 선택이 완료되면, 결제 과정을 하나씩 진행한다
(Select 모듈은 드롭다운의 옵션을 선택하는데 사용)
# 결제하기
def payment():
# 좌석선택 완료 버튼 클릭
driver.switch_to.default_content()
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmSeat"]'))
driver.find_element(By.XPATH,'//*[@id="NextStepImage"]').click()
# 가격선택
driver.switch_to.default_content()
driver.switch_to.frame(driver.find_element(By.XPATH, "//*[@id='ifrmBookStep']"))
select = Select(driver.find_element(By.XPATH, '//*[@id="PriceRow001"]/td[3]/select'))
select.select_by_index(1)
driver.switch_to.default_content()
driver.find_element(By.XPATH,'//*[@id="SmallNextBtnImage"]').click()
# 예매자 확인
driver.switch_to.frame(driver.find_element(By.XPATH, "//*[@id='ifrmBookStep']"))
driver.find_element(By.XPATH,'//*[@id="YYMMDD"]').send_keys('생년월일 입력')
driver.switch_to.default_content()
driver.find_element(By.XPATH,'//*[@id="SmallNextBtnImage"]').click()
# 결제방식 선택
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmBookStep"]'))
driver.find_element(By.XPATH,'//*[@id="Payment_22004"]/td/input').click()
select2 = Select(driver.find_element(By.XPATH, '//*[@id="BankCode"]'))
select2.select_by_index(1)
driver.switch_to.default_content()
driver.find_element(By.XPATH,'//*[@id="SmallNextBtnImage"]').click()
# 동의 후, 결제하기
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmBookStep"]'))
driver.find_element(By.XPATH,'//*[@id="checkAll"]').click()
driver.switch_to.default_content()
driver.find_element(By.XPATH,'//*[@id="LargeNextBtnImage"]').click()
끝
완성코드
select, payment 함수는 OCR 문자입력보다 앞에 있다
import selenium
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
#from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import Select
import time
import easyocr
# 브라우저 꺼짐 방지 옵션
chrome_options = Options()
chrome_options.add_experimental_option("detach", True)
driver = webdriver.Chrome(options=chrome_options)
driver.set_window_size(1900, 1000)
interpark_url = 'https://tickets.interpark.com//'
# 웹페이지가 로드될 때까지 2초를 대기
driver.implicitly_wait(time_to_wait=2)
driver.get(url=interpark_url)
# 로그인
driver.find_element(By.LINK_TEXT,'로그인').click()
driver.switch_to.frame(driver.find_element(By.XPATH, "//div[@class='leftLoginBox']/iframe[@title='login']"))
userId = driver.find_element(By.ID, 'userId')
userId.send_keys('아이디')
userPwd = driver.find_element(By.ID, "userPwd")
userPwd.send_keys('패스워드')
userPwd.send_keys(Keys.ENTER)
# 티켓 사이트 이동
search = driver.find_element(By.XPATH,'//*[@id="__next"]/div/header/div/div[1]/div/div[1]/div[3]/div/input')
search.send_keys('싸이 올나잇')
search.send_keys(Keys.ENTER)
driver.find_element(By.XPATH,'//*[@id="__next"]/div/main/div/div/div[1]/div[2]/a[1]/div[1]').click()
#예매하기
print('--------------------')
print(driver.window_handles)
driver.switch_to.window(driver.window_handles[-1])
driver.find_element(By.XPATH,'//*[@id="productSide"]/div/div[2]/a[1]').click()
print('--------------------')
print(driver.window_handles)
driver.switch_to.window(driver.window_handles[-1])
driver.switch_to.frame(driver.find_element(By.XPATH, "//*[@id='ifrmSeat']"))
# 좌석 탐색
def select():
print('******************************select seat')
print(driver.window_handles)
driver.switch_to.window(driver.window_handles[-1])
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmSeat"]'))
# 구역선택
#driver.find_element(By.XPATH,'//*[@id="GradeRow"]/td[1]/div/span[2]').click()
while True:
# 세부구역 선택
driver.find_element(By.XPATH,'//*[@id="GradeDetail"]/div/ul/li[1]/a').click()
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmSeatDetail"]'))
try:
driver.find_element(By.XPATH,'//*[@id="Seats"]').click()
payment()
break
except:
print('******************************다시선택')
driver.switch_to.default_content()
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmSeat"]'))
driver.find_element(By.XPATH,'/html/body/form[1]/div/div[1]/div[3]/div/p/a/img').click()
time.sleep(1)
def payment():
print('******************************payment')
#좌석선택
driver.switch_to.default_content()
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmSeat"]'))
driver.find_element(By.XPATH,'//*[@id="NextStepImage"]').click()
#가격선택
driver.switch_to.default_content()
driver.switch_to.frame(driver.find_element(By.XPATH, "//*[@id='ifrmBookStep']"))
select = Select(driver.find_element(By.XPATH, '//*[@id="PriceRow001"]/td[3]/select'))
select.select_by_index(1)
driver.switch_to.default_content()
driver.find_element(By.XPATH,'//*[@id="SmallNextBtnImage"]').click()
#주문자 확인
driver.switch_to.frame(driver.find_element(By.XPATH, "//*[@id='ifrmBookStep']"))
driver.find_element(By.XPATH,'//*[@id="YYMMDD"]').send_keys('생년월일')
driver.switch_to.default_content()
driver.find_element(By.XPATH,'//*[@id="SmallNextBtnImage"]').click()
#결제
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmBookStep"]'))
driver.find_element(By.XPATH,'//*[@id="Payment_22004"]/td/input').click()
select2 = Select(driver.find_element(By.XPATH, '//*[@id="BankCode"]'))
select2.select_by_index(1)
driver.switch_to.default_content()
driver.find_element(By.XPATH,'//*[@id="SmallNextBtnImage"]').click()
driver.switch_to.frame(driver.find_element(By.XPATH,'//*[@id="ifrmBookStep"]'))
driver.find_element(By.XPATH,'//*[@id="checkAll"]').click()
driver.switch_to.default_content()
driver.find_element(By.XPATH,'//*[@id="LargeNextBtnImage"]').click()
# 부정예매방지 문자
reader = easyocr.Reader(['en'])
capchaPng = driver.find_element(By.XPATH,'//*[@id="imgCaptcha"]')
while capchaPng:
print('---------------capcha')
result = reader.readtext(capchaPng.screenshot_as_png, detail=0)
capchaValue = result[0].replace(' ', '').replace('5', 'S').replace('0', 'O').replace('$', 'S').replace(',', '')\
.replace(':', '').replace('.', '').replace('+', 'T').replace("'", '').replace('`', '')\
.replace('1', 'L').replace('e', 'Q').replace('3', 'S').replace('€', 'C').replace('{', '').replace('-', '')
# 입력
driver.find_element(By.XPATH,'//*[@id="divRecaptcha"]/div[1]/div[3]').click()
chapchaText = driver.find_element(By.XPATH,'//*[@id="txtCaptcha"]')
chapchaText.send_keys(capchaValue)
#입력완료 버튼 클릭
driver.find_element(By.XPATH,'//*[@id="divRecaptcha"]/div[1]/div[4]/a[2]').click()
display = driver.find_element(By.XPATH,'//*[@id="divRecaptcha"]').is_displayed()
if display:
# 새로고침
driver.find_element(By.XPATH,'//*[@id="divRecaptcha"]/div[1]/div[1]/a[1]').click()
else:
select()
break
+ element 제어기 안된다는 댓글이 많아서 추가
셀레늄 감지 방지 코드 (요소가 클릭이 안될때 아래 코드를 추가하여 셀레늄 감지를 피할 수 있다) ↓
예매창에서 개발자모드 열기 (F12)
예매창에서는 F12를 눌러도 개발자모드가 열리지 않는다
이럴때는 Ctrl+Shift+I 누르면 열림
이렇게 해도 됨
브라우저 맨 위 작업표시줄에서 오늘쪽마우스를 눌러 '탭으로 표시'를 클릭
그 다음, 더보기(점세개)>도구 더보기>개발자 도구를 클릭하면 된다
예스24 티켓예매 ↓
'개발기록 > python' 카테고리의 다른 글
ModuleNotFoundError : No module named (가상환경) (6) | 2024.03.17 |
---|---|
[python] CSV 파일 합치기 프로그램 만들기 (tkinter GUI) (0) | 2024.03.10 |
[python] 파이썬 버전별 가상환경 설치 (+virtualenv) (7) | 2023.11.05 |
[python] Selenium IE 에서 시작하기 (+Internet Explore) (2) | 2023.11.04 |
[python] Selenium chrome에서 시작하기 (+ 크롬 브라우저, element, driver, alert 다루기) (2) | 2023.10.15 |
댓글