안녕하세요 !
오늘은 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()