본문 바로가기
개발기록/python

[python] Selenium 활용 인터파크 티켓예매 매크로 만들기

by spectrum20 2023. 11. 30.

Selenium을 활용해서 인터파크 티켓예매 과정을 자동화해보자

* 반복적으로 사용시, 매크로로 감지하여 정지먹음 주의 (selenium 연습용으로만 사용하자)

 

 

 

1. 패키지 설치

먼저 필요한 패키지들을 설치해준다

pip install selenium

pip install easyocr  (부정예매 방지 문자 입력용 OCR 모듈)

 

기존에 파이썬 3.12 버전을 사용중이었는데, 이 버전에서는 easyocr이 설치되지 않아서 3.8 버전으로 가상환경을 새로 생성해주었다

파이썬 버전별 가상환경 설치 방법은 아래 링크 참조 ↓ ↓ ↓

2023.11.05 - [개발기록/python] - [python] 파이썬 버전별 가상환경 설치 (+virtualenv)

 

[python] 파이썬 버전별 가상환경 설치 (+virtualenv)

파이썬 버전별로 다른 가상환경 생성방법 파이썬 3.12.0을 사용하다가, 필요한 패키지가 정상설치되지 않아서 더 낮은 버전의 파이썬이 필요했다 1. 파이썬 설치 아래 링크에서 필요한 파이썬 버

spectrum20.tistory.com

 

 

 

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//'
txt_url ='https://tickets.interpark.com/goods/23013022?app_tapbar_state=hide&'

# 웹페이지가 로드될 때까지 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('960805')
    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
반응형

댓글