본문 바로가기
그냥 끄적끄적

인터파크 매크로 만들기 [4. 좌석 선점하기 - 1]

by 강성주의 알고리즘 2023. 12. 1.

2023.11.29 - [그냥 끄적끄적] - 인터파크 매크로 만들기. [1. 환경 구축]

2023.11.29 - [그냥 끄적끄적] - 인터파크 매크로 만들기. [2. 로그인]

2023.11.30 - [그냥 끄적끄적] - 인터파크 매크로 만들기 [3. 공연 스케쥴 선택하기 - 1]

2023.11.30 - [그냥 끄적끄적] - 인터파크 매크로 만들기 [3. 공연 스케쥴 선택하기 - 2]

이전 글을 보고 오시면 이해가 쉽습니다.


이번 포스팅에서는 매크로의 꽃인 좌석 선점하기에 대해 글을 써보겠습니다.

지난 글 까지는 원하는 공연의 원하는 관람일과 시간을 선택하여 좌석 창까지 넘어갔었습니다. 티켓팅을 할 때, 가장 좋은 자리를 노릴 것이냐? 안전하게 2/3층의 자리를 노릴 것이냐? 를 선택해야 합니다.

먼저 1층에서 가장 앞쪽 자리를 선점하는 시나리오를 가정하여 코드를 작성해 보도록 하겠습니다. 

1층이 좋은 점은 오른쪽 상단의 맵을 별도로 누르지 않아도 된다는 장점이 있습니다. 아쉽게도 이번 시나리오의 좌석은 전부 매진이니 2, 3층으로 가보겠습니다.

일단 2, 3층으로 가기 전에 예매하기 버튼을 눌렀으므로 새창이 떴습니다. 우리는 driver를 새창으로 옮겨주는 작업이 필요하겠죠? chatGPT 한테 물어보니 아래의 방식을 사용한다고 합니다.

main_window_handle = driver.current_window_handle
all_window_handles = driver.window_handles
new_window_handle = [handle for handle in all_window_handles if handle != main_window_handle][0]
# 새 창으로 전환
driver.switch_to.window(new_window_handle)

앞으로 Iframe으로의 프레임 전환이 빈번하게 일어나니 new_window_handle의 변수를 자주 볼 것입니다.

일단, 위의 코드로 새창으로 열린 예매페이지로 driver를 이동시킨 후, 2/3층으로 가기 위해 오른쪽 상단의 미니맵에 대한 요소에 접근을 해야 합니다. 해당 엘리먼트를 눌러보면 아래와 같은데

이 요소의 속성이 html 아래 body 아래.. iframe#ifrmSeat 아래... iframe#ifrmSeatView 아래 ... tr 아래 td 아래 img라는 것을 알 수 있습니다. 즉 iframe#ifrmSeat으로 프레임을 전환한 후, 다시 ifrmSeatView로 프레임을 전환해서 미니맵 엘리먼트에 접근해야 한다는 소리입니다... 

복잡하니 제가 짠 코드로 넘어가 보도록 하겠습니다.

iframes = driver.find_elements(By.TAG_NAME, "iframe")
for ifr in iframes:
    if ifr.get_attribute('name') == 'ifrmSeat':
        print("convert")
        driver.switch_to.frame(ifr)
        driver.switch_to.frame('ifrmSeatView')
        break

생각보다 코드는 간단하죠? 반복문으로 원하는 iframe의 이름을 비교해서 이동시키기만 하면 됩니다.

그럼 현재 driver는 ifrmSeatView의 프레임을 잡고 있으니 우리가 원하는 미니맵의 요소를 find_element를 통해 접근만 하면 됩니다.

Seat_region = driver.find_element(By.XPATH, "//*[@id='TmgsTable']/tbody/tr/td/map")

자 그럼. 지금 Seat_region이라는 변수에는 해당 미니맵의 요소에 대한 정보가 들어있으니, 2, 3층으로 이동해야 합니다.

해당 Map의 객체를 보니까 href 속성에 javascript:GetBlockSeatList라는 함수가 보이고 맨 마지막 인자로 'RGN002'가 있는 것을 보아하니.. 현재 보이는 좌석이 1층이라면 2층으로 가기 위한 마지막 인자가 RGN002 이며, 현재 보여지는 좌석이 2층이라면 1층으로 가기 위한 마지막 인자가 RGN001 임을 유추해 볼 수 있습니다. 

레베카 공연은 2, 3 층 좌석이 한 번에 보이므로 GetBlockSeatList(' ', ' ' , 'RGN002')를 실행시키면 되지만, 만약 다른 공연장에서 2층과 3층이 따로 보이게 된다면 해당 값을 잘 찾아서 넣어주면 될 것 같습니다. 2층으로 이동하기 위해 href 속성에 정의된 함수를 실행시키기 위해서 다음의 코드를 작성해야 한다고 ChatGPT가 말해주네요.

    href_value = area_element.get_attribute("href")
    # href 값이 javascript:로 시작하는지 확인
    if href_value.startswith("javascript:"):
        driver.execute_script(href_value)
    time.sleep(0.5)

창 전환이나 URL이 변경된다면 sleep으로 딜레이를 줘서 웹 브라우저가 html element 들을 정상적으로 불러올 수 있게 시간을 주도록 합시다.

2/ 3층으로 넘어가는 전체 코드를 실행시켜보도록 하겠습니다.

import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By

my_interpark_id = "인터파크 아이디"
my_interpark_pw = "인터파크 비밀번호"

login_url = "https://ticket.interpark.com/Gate/TPLogin.asp" # 로그인 창
my_url = "https://tickets.interpark.com/goods/L0000062" # 공연 URL

want_month = 1 # 원하는 월
want_day = 13 # 원하는 일
want_turn = 2 # 원하는 공연 회차 ( 1회 = 2시 , 2회 = 7 시)
want_floor = 3 # 원하는 관람 층 (1 = 1층, 2 = 2층, 3 = 3층)

service = Service('C:/Users/seong/chromedriver.exe')
service.start()

driver = webdriver.Remote(service.service_url)

driver.get(login_url)

iframes = driver.find_elements(By.TAG_NAME, "iframe")
driver.switch_to.frame(iframes[0])

time.sleep(0.2)
id_input = driver.find_element(By.CSS_SELECTOR, "#userId")
pw_input = driver.find_element(By.CSS_SELECTOR, "#userPwd")
id_input.send_keys(my_interpark_id)
time.sleep(0.2)
pw_input.send_keys(my_interpark_pw)
button = driver.find_element(By.CSS_SELECTOR, "#btn_login")
button.click()

driver.get(my_url)
time.sleep(0.3)

nxt_button = driver.find_element(By.XPATH, "//*[@id='productSide']/div/div[1]/div[1]/div[2]/div/div/div/div/ul[1]/li[3]")

while True:
    current_date = driver.find_element(By.XPATH,"//*[@id='productSide']/div/div[1]/div[1]/div[2]/div/div/div/div/ul[1]/li[2]")
    cur_month = int(current_date.text.split(' ')[1])
    if cur_month != want_month:
        nxt_button.click()
        time.sleep(0.3)
    else:
        time.sleep(0.3)
        break

find_day = driver.find_element(By.XPATH, "//li[text()='"+str(want_day)+"']")
find_day.click()

turn_list = driver.find_elements(By.CLASS_NAME, "timeTableItem")
turn_list[want_turn - 1].click()

go_button = driver.find_element(By.CSS_SELECTOR, "a.sideBtn.is-primary")
go_button.click()

time.sleep(1)

main_window_handle = driver.current_window_handle
all_window_handles = driver.window_handles
new_window_handle = [handle for handle in all_window_handles if handle != main_window_handle][0]
# 새 창으로 전환
driver.switch_to.window(new_window_handle)

iframes = driver.find_elements(By.TAG_NAME, "iframe")
for ifr in iframes:
    if ifr.get_attribute('name') == 'ifrmSeat':
        print("convert")
        driver.switch_to.frame(ifr)
        driver.switch_to.frame('ifrmSeatView')
        break

if want_floor != 1: # 2 or 3층
    Seat_region = driver.find_element(By.XPATH, "//*[@id='TmgsTable']/tbody/tr/td/map")
    area_element = Seat_region.find_element(By.TAG_NAME, "area")

    href_value = area_element.get_attribute("href")
    # href 값이 javascript:로 시작하는지 확인
    if href_value.startswith("javascript:"):
        driver.execute_script(href_value)
    time.sleep(0.5)

 

아래는 실행 영상입니다.

 

 

다음 포스팅에서는 이어서 선택 가능한 좌석 정보들을 가져와서 원하는 좌석을 선택하고 결제창까지 유도하는 방법에 대해 다루도록 하겠습니다.

2023.12.01 - [그냥 끄적끄적] - 인터파크 매크로 만들기 [4. 좌석 선점하기 - 마무리]

 

인터파크 매크로 만들기 [4. 좌석 선점하기 - 마무리]

2023.11.29 - [그냥 끄적끄적] - 인터파크 매크로 만들기. [1. 환경 구축] 2023.11.29 - [그냥 끄적끄적] - 인터파크 매크로 만들기. [2. 로그인] 2023.11.30 - [그냥 끄적끄적] - 인터파크 매크로 만들기 [3. 공연

seongjuk.tistory.com

 

반응형