본문 바로가기
[자동화프로그램구현하기]

[SRT]기차표 자동화 예매하기 (결제화면 출력까지 개발)

by 슬쨩! 2024. 4. 16.

안녕하세요 !

오늘은 SRT 기차표 자동화 예매 프로그램을 만들어 보았습니다.

 

▶️자동로그인

▶️출발역, 도착역, 날짜, 시간 

▶️조회

 -. 예매하기 가능하면 결제 화면으로 이동

 -. 매진이면 계속 새로고침 하기

 

 

✅ 자동 로그인 

우선 자주 쓰일 변수들에 대해서 지정해 줍니다.

 

#변수 선언
member_num = "회원번호" # 회원번호
pwd = "비밀번호" # 비밀번호
depart_station = "평택지제" # 출발역
arrival_station = "광주송정" # 도착역
depart_date = "20240507" # 출발 날짜 YYYYMMDD 형식
depart_time = "10" # 출발 시간 00, 02, 04, ... ,20, 22 형식
number_of_trains = 4 # 검색 결과 상단에서부터 예약 가능 여부 확인할 기차 수

 

 

 

1. 로그인 CSS_SELECTOR 값을 읽어와서 클릭을 해줍니다!

#로그인선택
login_button=driver.find_element(By.CSS_SELECTOR, '#wrap > div.header.header-e > div.global.clear > div > a:nth-child(2)')
login_button.click()

 

 

2. 로그인 화면이 출력되었습니다.

 

 

4개의 요소외 CSS_SELECTOR를 읽어서 클릭하고

ID와 PW 칸에는 send_keys로 변수를 입력해줍니다!!

 

send_keys(member_num) 변수를 가져와서 입력하고

send_keys(pwd) 변수를 가져와서 비밀번호를 입력합니다.

 
#Radio 휴대폰 선택
radio_button=driver.find_element(By.CSS_SELECTOR, '#srchDvCd3')
radio_button.click()
time.sleep(1)

#로그인 id
login_id=driver.find_element(By.CSS_SELECTOR, '#srchDvNm03')
login_id.click()
login_id.send_keys(member_num)
time.sleep(1)

#로그인 pw
login_pw=driver.find_element(By.CSS_SELECTOR, '#hmpgPwdCphd03')
login_pw.click()
login_pw.send_keys(pwd)
time.sleep(1)

#로그인 확인 버튼
login=driver.find_element(By.CSS_SELECTOR, '#login-form > fieldset > div.input-area.loginpage.clear > div.fl_l > div.con.srchDvCd3.dis_none > div > div.fl_r > input')
login.click()
time.sleep(2)
print("1.로그인 성공")

 

 

* 개발자 도구를 열어서 요소를 클릭해서 id가 있으면 id로 접근하고 없으며 CSS_SELECTOR 또는 XPATH로 요소를

읽을 수 있습니다.

 

로그인 후 필요 없는 팝업이 나타나는데 아래 코드를 입력하여 코드를 close 해 줍니다.

# close pop-up window
driver.switch_to.window(driver.window_handles[1])
driver.close()

driver.switch_to.window(driver.window_handles[0])

 

 

✅ 출발역, 도착역, 날짜, 시간 입력하기

 

 

 

1. 출발역은 드롭다운 방식이기 때문에 자바스크립트 방식으로 요소를 클릭해 줍니다.

 

  -. 출발역 선택 요소를 찾고

  -. 자바스크립트를 사용하여 출발역 선택 요소를 화면에 표시 합니다.

  -. 출발역 선택 요소를 Select 객체로 변환합니다.

  -. select_by_visible_text(depart_station)으로 출발역 변수를 가져와 입력 합니다.

 

2. 도착역은 드롭다운 방식이기 때문에 자바스크립트 방식으로 요소를 클릭해 줍니다.

 

  -. 도착역 선택 요소를 찾고

  -. 자바스크립트를 사용하여 출발역 선택 요소를 화면에 표시 합니다.

  -. 도착역 선택 요소를 Select 객체로 변환합니다.

  -. select_by_visible_text(arrival_station)으로 출발역 변수를 가져와 입력 합니다.

 

3. 다음은 날짜를 자동 입력해야하는데 방법을 모르겠어서 다른 방법으로 우회했습니다.

  우선 조회부터 해줍니다.

#출발역 선택
elm_dptRsStnCd = driver.find_element(By.ID, "dptRsStnCd")# 출발역 선택 요소 찾기
driver.execute_script("arguments[0].setAttribute('style','display: True;')", elm_dptRsStnCd)# JavaScript를 사용하여 출발역 선택 요소를 화면에 표시
select_departure = Select(elm_dptRsStnCd)# 출발역 선택 요소를 Select 객체로 변환
select_departure.select_by_visible_text(depart_station)

#도착역 선택
elm_arvRsStnCd=driver.find_element(By.ID, 'arvRsStnCd')
driver.execute_script("arguments[0].setAttribute('style','display: True;')", elm_arvRsStnCd)# JavaScript를 사용하여 도착역 선택 요소를 화면에 표시
select_departure = Select(elm_arvRsStnCd)# 도착역 선택 요소를 Select 객체로 변환
select_departure.select_by_visible_text(arrival_station)


#조회하기
search=driver.find_element(By.CSS_SELECTOR, '#search-form > fieldset > a')
search.click()
time.sleep(2)

 

 

 

4. 일반 승차권 조회 하면이 출력 됩니다.

   날짜는 달력 형식에서 드롭다운 방식으로 변경되었습니다.

   그럼 위에 방법과 동일하게 진행 하시면 됩니다.

 

 

코드 작성 방식이 조금 다르지만 동일한 방법입니다.

#날짜 선택
elm_dptDt = driver.find_element(By.ID, 'dptDt')
driver.execute_script("arguments[0].setAttribute('style','display: True;')", elm_dptDt)
Select(driver.find_element(By.ID,"dptDt")).select_by_value(depart_date)

# 출발 시간
elm_dptTm = driver.find_element(By.ID, "dptTm")
driver.execute_script("arguments[0].setAttribute('style','display: True;')", elm_dptTm)
Select(driver.find_element(By.ID, "dptTm")).select_by_visible_text(depart_time)

time.sleep(2)

#최종 조회하기
last_search=driver.find_element(By.CSS_SELECTOR, '#search_top_tag > input')
last_search.click()
print("2.조회 성공")
time.sleep(10)

 

 

 

✅ 조회 

아래와 같이 예약 하기 목록 화면을 확인 할 수 있습니다.

 

여기서 로직이 추가 됩니다.

표가 있을 수도 있고, 없을 수도 있기 때문에 확인 후 결제 화면 까지 넘어 가는 로직입니다.

 

1. reserved 변수에 False를 넣어서 판정 기준을 작성합니다.

 

그리고 예약하기의 요소들의 CSS_SELECTOR를 확인합니다.

1번째 예약하기 요소의 값 

 -. #result-form > fieldset > div.tbl_wrap.th_thead > table > tbody > tr:nth-child(1) > td:nth-child(7) > a > span

2번째 예약하기 요소의 값

#result-form > fieldset > div.tbl_wrap.th_thead > table > tbody > tr:nth-child(2) > td:nth-child(7) > a > span

 

tr:nth-child가 +1증가하는 것을 볼수 있습니다. 그래서 아래 코드에 i를 넣어서 각 요소마다 text를 가져와서

standard_seat에 넣어 줍니다.

 

만약 "예약하기"가 있다면 클릭해서 reserved=True로 변경하고

결제화면은 클릭해 줍니다.

 

 

2. reserved=False이면 조회하기를 5초마다 클릭해줍니다.

새로고침이 될때마다 카운트도 됩니다.

refresh_count = 0 #새로고침
reserved = False

while True:
    for i in range(1, number_of_trains+1):
        standard_seat = driver.find_element(By.CSS_SELECTOR, f"#result-form > fieldset > div.tbl_wrap.th_thead > table > tbody > tr:nth-child({i}) > td:nth-child(7)").text

        if "예약하기" in standard_seat:
            print("3.예약 가능")          
            driver.find_element(By.XPATH, f"/html/body/div[1]/div[4]/div/div[3]/div[1]/form/fieldset/div[6]/table/tbody/tr[{i}]/td[7]/a/span").click()
            reserved = True
            driver.find_element(By.CSS_SELECTOR, '#list-form > fieldset > div.tal_c > a.btn_large.btn_blue_dark.val_m.mgr10 > span').click()
            print("4.결제 화면 - 결제 정보 입력 필요")
            time.sleep(10)
            break

    if not reserved:#False 이면
        # 5초 기다리기
        time.sleep(5)    
        # 다시 조회하기
        submit = driver.find_element(By.XPATH, "//input[@value='조회하기']")
        driver.execute_script("arguments[0].click();", submit)
        refresh_count += 1 # 새로고침 횟수 증가
        print("새로고침"+ str(refresh_count))
        driver.implicitly_wait(10)
        time.sleep(1)
    else:
        break

 

뎁스가 끝날때마다 로그를 설정해두어 프로세스 동작 여부를 확인 할 수 있습니다.

 

동작은 확인하였고 한 프로세스가 끝날 때마다 text 나 출력 화면을 판정하여 일치여부에 따라 웹 테스트 시나리오 케이스도 만들 수 있습니다.

 

 

더 구현이 필요 합니다.

다음 기회에,,

 

 

 

전체소스코드입니다.

id와 비밀번호는 개인것으로 변경해서 실행하시면 됩니다.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
import time


#변수 선언
member_num = "-" # 회원번호
pwd = "-" # 비밀번호
depart_station = "평택지제" # 출발역
arrival_station = "광주송정" # 도착역
depart_date = "20240507" # 출발 날짜 YYYYMMDD 형식
depart_time = "10" # 출발 시간 00, 02, 04, ... ,20, 22 형식
number_of_trains = 4 # 검색 결과 상단에서부터 예약 가능 여부 확인할 기차 수


driver = webdriver.Chrome()


# 홈페이지 주소 설정


# 홈페이지 열기
driver.get(homepage_url)
driver.set_window_position(0,0)
driver.set_window_size(1920,1080)


#로그인선택
login_button=driver.find_element(By.CSS_SELECTOR, '#wrap > div.header.header-e > div.global.clear > div > a:nth-child(2)')
login_button.click()


#Radio 휴대폰 선택
radio_button=driver.find_element(By.CSS_SELECTOR, '#srchDvCd3')
radio_button.click()
time.sleep(1)

#로그인 id
login_id=driver.find_element(By.CSS_SELECTOR, '#srchDvNm03')
login_id.click()
login_id.send_keys(member_num)
time.sleep(1)

#로그인 pw
login_pw=driver.find_element(By.CSS_SELECTOR, '#hmpgPwdCphd03')
login_pw.click()
login_pw.send_keys(pwd)
time.sleep(1)

#로그인 확인 버튼
login=driver.find_element(By.CSS_SELECTOR, '#login-form > fieldset > div.input-area.loginpage.clear > div.fl_l > div.con.srchDvCd3.dis_none > div > div.fl_r > input')
login.click()
time.sleep(2)
print("1.로그인 성공")

# close pop-up window
driver.switch_to.window(driver.window_handles[1])
driver.close()

driver.switch_to.window(driver.window_handles[0])



#출발역 선택(일반 값 읽어서 클릭)
#start_sation=driver.find_element(By.CSS_SELECTOR, '#dptRsStnCd > option:nth-child(4)')
#start_sation.click()
#time.sleep(2)

#출발역 선택
elm_dptRsStnCd = driver.find_element(By.ID, "dptRsStnCd")# 출발역 선택 요소 찾기
driver.execute_script("arguments[0].setAttribute('style','display: True;')", elm_dptRsStnCd)# JavaScript를 사용하여 출발역 선택 요소를 화면에 표시
select_departure = Select(elm_dptRsStnCd)# 출발역 선택 요소를 Select 객체로 변환
select_departure.select_by_visible_text(depart_station)

#도착역 선택
elm_arvRsStnCd=driver.find_element(By.ID, 'arvRsStnCd')
driver.execute_script("arguments[0].setAttribute('style','display: True;')", elm_arvRsStnCd)# JavaScript를 사용하여 도착역 선택 요소를 화면에 표시
select_departure = Select(elm_arvRsStnCd)# 도착역 선택 요소를 Select 객체로 변환
select_departure.select_by_visible_text(arrival_station)


#조회하기
search=driver.find_element(By.CSS_SELECTOR, '#search-form > fieldset > a')
search.click()
time.sleep(2)

#날짜 선택
elm_dptDt = driver.find_element(By.ID, 'dptDt')
driver.execute_script("arguments[0].setAttribute('style','display: True;')", elm_dptDt)
Select(driver.find_element(By.ID,"dptDt")).select_by_value(depart_date)

# 출발 시간
elm_dptTm = driver.find_element(By.ID, "dptTm")
driver.execute_script("arguments[0].setAttribute('style','display: True;')", elm_dptTm)
Select(driver.find_element(By.ID, "dptTm")).select_by_visible_text(depart_time)

time.sleep(2)

#최종 조회하기
last_search=driver.find_element(By.CSS_SELECTOR, '#search_top_tag > input')
last_search.click()
print("2.조회 성공")
time.sleep(10)

refresh_count = 0 #새로고침
reserved = False

while True:
    for i in range(1, number_of_trains+1):
        standard_seat = driver.find_element(By.CSS_SELECTOR, f"#result-form > fieldset > div.tbl_wrap.th_thead > table > tbody > tr:nth-child({i}) > td:nth-child(7)").text

        if "예약하기" in standard_seat:
            print("3.예약 가능")          
            driver.find_element(By.XPATH, f"/html/body/div[1]/div[4]/div/div[3]/div[1]/form/fieldset/div[6]/table/tbody/tr[{i}]/td[7]/a/span").click()
            reserved = True
            driver.find_element(By.CSS_SELECTOR, '#list-form > fieldset > div.tal_c > a.btn_large.btn_blue_dark.val_m.mgr10 > span').click()
            print("4.결제 화면 - 결제 정보 입력 필요")
            time.sleep(10)
            break

    if not reserved:#False 이면
        # 5초 기다리기
        time.sleep(5)    
        # 다시 조회하기
        submit = driver.find_element(By.XPATH, "//input[@value='조회하기']")
        driver.execute_script("arguments[0].click();", submit)
        refresh_count += 1 # 새로고침 횟수 증가
        print("새로고침"+ str(refresh_count))
        driver.implicitly_wait(10)
        time.sleep(1)
    else:
        break

# 작업 완료 후 웹 드라이버 종료
#driver.quit()