안녕하세요 모두의 파이썬입니다. 크롤링에 대해 지금까지 약 20개 작성을 하였습니다. 그런데 지금까지는 작성한 글을 보면 사이트에 존재하는 정보들에 대해 크롤링을 하였습니다. 로그인을 하거나 입력값을 필요로 하지 않는 종류의 크롤링이었습니다. 하지만 파이썬을 알고, 크롤링 구현 실력이 증가하면서 자동화를 하고 싶은 영역이 확장되어 실생활에 적용할 사례들이 폭발적으로 증가할 것이라 생각됩니다. 그래서 국내 가장 빠른 기차인 SRT 표를 자동 예매하는 방법에 대해 알아보겠습니다
전체 글을 요약하면, SRT 로그인에서부터 결제 직전인 예매까지 구현한다
우선 SRT 홈페이지로 접속한다. 예매를 해봤다면, 한 번쯤은 홈페이지에 들어와 봤을 것이다. 다음과 같은 화면을 볼 수 있다. 예매를 하기 위해서는 로그인이 필수이다. 로그인 버튼을 눌러서 로그인 절차를 거친다.
다음과 같은 화면을 볼 수 있다. 로그인이 주목적이므로 코드에서는 메인화면은 스킵하고, 로그인 화면부터 접속할 예정이다.
자동 예매를 진행하기 위해 자동화 브라우저가 우선 필요하다. 자동화 브라우저 사용을 위해 pip install selenium으로 selenium 패키지 설치와 Chrome 드라이버 다운로드는 구글 검색을 통해 선행하길 권장한다. 설치가 완료되었다면, 크롬 자동화 브라우저를 활성화하고, SRT 로그인 화면으로 접속해 본다. 크롬 드라이버는 d:에 저장을 한다. SRT 로그인 주소는 https://etk.srail.kr/cmc/01/selectLoginForm.do 이며, driver.get(login_url)을 수행하여, SRT로그인 화면으로 접속을 완료한다.
In [1]:
##자동화 크롬 브라우저를 위한 필수 패키지
from selenium import webdriver
##크롬드라이버 경로
path = "D:\\chromedriver.exe"
##브라우저 활성화
driver = webdriver.Chrome(path)
##SRT 로그인 url
login_url = 'https://etk.srail.kr/cmc/01/selectLoginForm.do'
##SRT 로그인페이지로 연결
driver.get(login_url)
ⓒ 자동크롬 브라우저로 접속한 SRT 로그인화면 , 출처 SRT
회원번호 입력란에 정확히 음영이 처리될 때까지 html을 구조를 스캔했고, 해당 id가 "srchDvNm01" 임을 확인 완료하였다. html에 id가 존재한다면, id를 활용할 수 있는 코드로 접근한다.
ⓒ 자동크롬 브라우저로 접속한 SRT 로그인화면 , 출처 SRT
custom_id에 회원번호 Element를 정의한 다음 clear()로 빈칸으로 초기화한다. 그리고 send_keys를 통해 회원번호 입력을 실행한다. 회원번호 '12345678'이 이상 없이 입력된 것을 확인할 수 있다.
ⓒ 회원번호를 자동으로 입력한 SRT 로그인화면 , 출처 SRT
In [6]:
## html id활용 용이하기 위해 선언
from selenium.webdriver.common.by import By
## 회원번호
custom_id_num = '12345678'
## 회원번호 입력을 위한 Element
custom_id = driver.find_element(By.ID, 'srchDvNm01')
## 빈칸으로 초기화
custom_id.clear()
## send_keys를 통해 회원번호 입력
custom_id.send_keys(custom_id_num)
비밀번호 입력 구현은 회원번호 구현 방식과 유사하며 id는 'hmpgPwdCphd01'이다. 코드 구현한 결과는 다음과 같다.
ⓒ 회원번호, 비밀번호를 자동으로 입력한 SRT 로그인화면 , 출처 SRT
In [7]:
## 비밀번호
passwd_num = '87654321'
## 비밀번호 입력을 위한 Element
passwd = driver.find_element(By.ID, 'hmpgPwdCphd01')
## 빈칸으로 초기화
passwd.clear()
## send_keys를 통해 비밀번호 입력
passwd.send_keys(passwd_num)
3확인 클릭을 구현하는 방법도 앞 1-2과 유사하다. 확인 버튼에 음영이 나타날 때까지 html을 찾는다 찾았지만, id가 존재하지 않는다. 그래서 xpath 방식으로 구현한다
ⓒ 확인버튼 구현하는 과정의 SRT 로그인화면 , 출처 SRT
In [8]:
## 확인버튼 xpath
btn_add = '/html/body/div/div[4]/div/div[2]/form/fieldset/div[1]/div[1]/div[2]/div/div[2]/input'
## 확인버튼 클릭을 위한 Element
login_btn = driver.find_element_by_xpath(btn_add)
## 확인버튼 클릭
login_btn.click()
ⓒ 회원번호, 비밀번호를 자동으로 입력한 SRT 로그인화면 , 출처 SRT
일반승차권, 단체 승차권, 할인 승차권 세 가지가 있지만, 가장 많이 사용하는 일반승차권 예매에 대해서만 확인한다. 자동화하려는 항목이 여러 가지이지만, 크게 2가지로 나눠본다. 첫째는 출발지, 도착지, 출발 일자, 출발 일시이다. 둘째는 인원 정보와 차종 구분이다.
출발지, 도착지, 출발 일자, 출발 일시 모두 id가 존재하기에 driver.find_element(By.ID, 'id 이름') 사용하여 구한다. 출발지와 도착지의 경우에는 지역명을 입력해야 하며, 입력하기 전에는 초기화하기 위해서 clear() 함수를 사용한다. 그리고 지역명을 다시 한번 살펴 보면 다음과 같다. station_list = ['수서','동탄','평택지제','천안아산','오송', '대전','김천(구미)','서대구','동대구','신경주', '울산(통도사)','부산','공주','익산','정읍','광주송정','나주','목포'] 출발지와 도착지를 정확하게 입력해야 한다. 출발 일자와 출발시간은 리스트 형태의 값을 선택해야 하며, 22년 6월 13일 경우 '20220613'의 문자 형태로 입력해야 한다. 출발 일자의 경우 금일보다 미래여야 하며, 한 달 이내만 선택할 수 있다. 날짜를 한 달 이후 또는 과거의 날짜를 입력할 경우, 당일로 설정되게 예외처리를 하였다. 출발 시간의 경우 00시에서 22시까지 2시간 단위이며, 0시의 경우 00 + 0000 그리고 10시의 경우 '100000'을 입력해야 한다. 잘못 입력할 시에는 이전 값으로 설정하게 코드를 구현하였다.
In [13]:
##승차권 예약으로 접속
driver.get('https://etk.srail.kr/hpg/hra/01/selectScheduleList.do?pageId=TK0101010000')
## 지역명 예시
station_list = ['수서','동탄','평택지제','천안아산','오송',
'대전','김천(구미)','서대구','동대구','신경주',
'울산(통도사)','부산','공주','익산','정읍','광주송정','나주','목포']
##출발지 선택
##출발지 정보
departure_areaName = "동탄"
##출발지 입력을 위한 Element
departure_area = driver.find_element(By.ID, 'dptRsStnCdNm')
##사전에 입력된 내용 지우기
departure_area.clear()
##출발지 입력
departure_area.send_keys(departure_areaName)
##도착지 선택
##도착지 정보
arrival_areaName = "수서"
##도착지 입력을 위한 Element
arrival_area = driver.find_element(By.ID, 'arvRsStnCdNm')
##사전에 입력된 내용 지우기
arrival_area.clear()
##도착지 입력
arrival_area.send_keys(arrival_areaName)
##리스트를 포함하는 Element를 다루기 위한 package선언
from selenium.webdriver.support.select import Select
##출발일자 선택
##출발일자
target_date = 20220613
##출발지 입력을 위한 Element
departure_date = driver.find_element(By.ID, 'dptDt')
##숫자로 입력 없거나 에러이면 오늘로 진행
try:
##일자 리스트 중에서 출발일자 선택
Select(departure_date).select_by_value(str(target_date))
except:
##오늘년월일 정보 입력
today = datetime.now().strftime('%Y%m%d')
##일자 리스트 중에서 오늘을 선택
Select(departure_date).select_by_value(str(today))
##출발시간 선택
##출발시간
target_time = 18
## 문자열 구성을 위해 10 미만은 문자 0을 앞에 추가
if target_time < 10:
target_time = '0'+ str(target_time)
else:
target_time = str(target_time)
##출발시간 입력을 위한 Element
departure_time = driver.find_element(By.ID, 'dptTm')
try:
## 타겟 시간 선택
Select(departure_time).select_by_value(target_time+ '0000')
except:
pass
인원 정보도 출발 일자와 유사하게 리스트 형태의 Element 형태로 코드 구현해야 하며, 어른과 어린이 그리고 경로만 다뤄본다. 중증 및 경증장애인은 여러분이 쉽게 해결할 수 있으리라 판단된다. 어른, 어린이 그리고 경로 탑승객 수 구현 방식은 모두 동일하다. 어른을 살펴보면, id가 없기 때문에 xpath를 사용하여 구현해야 한다. 그리고 리스트 형태이기 Select 클래스로 탑승객 수를 입력한다. 0-9명까지 입력 가능하며, 범위를 벗어나는 인원일 경우 0명으로 선택한다. 다음은 차종 구분이다. SRT 표 예매만 구현한다. 차종 구분은 id 형태이며, id는 'trnGpCd300'이다. click()으로 차종 선택을 완료한다. 그리고 이 페이지에서 마지막인 조회 버튼도 id 형태이므로 id 'search_top_tag'로 element를 구현하고, click()으로 일반승차권 예매를 완료한다.
##어른 탑승객 수
adult_num = 3
##어른탑승객수 Element xpath (id가 아닌 xpath형태로 코드구현)
adult_select_add = '/html/body/div[1]/div[4]/div/div[2]/form/fieldset/div[1]/div/ul/li[2]/div[2]/div[1]/select'
##어른 탑승객 수를 위한 Element
adult_passenger = driver.find_element_by_xpath(adult_select_add)
##어른 탑승객 수 선택
try:
Select(adult_passenger).select_by_value(str(adult_num))
except:
## 에러가 나면 탑승객수 0명으로 선택
Select(adult_passenger).select_by_value(str(0))
##어린이 탑승객 수
child_num = 0
##어린이 탑승객 수 Element xpath (id가 아닌 xpath형태로 코드구현)
child_select_add = '/html/body/div[1]/div[4]/div/div[2]/form/fieldset/div[1]/div/ul/li[2]/div[2]/div[2]/select'
##어린이 탑승객 수를 위한 Element
child_passenger = driver.find_element_by_xpath(child_select_add)
##어린이 탑승객 수 선택
try:
Select(child_passenger).select_by_value(str(child_num))
except:
## 에러가 나면 탑승객수 0명으로 선택
Select(child_passenger).select_by_value(str(0))
##경로탑승색 수
senior_num = 0
##경로 탑승객 수 Element xpath (id가 아닌 xpath형태로 코드구현)
senior_select_add = '/html/body/div[1]/div[4]/div/div[2]/form/fieldset/div[1]/div/ul/li[2]/div[2]/div[3]/select'
##경로 탑승객 수를 위한 Element
senior_passenger = driver.find_element_by_xpath(senior_select_add)
##경로 탑승객 수 선택
try:
Select(senior_passenger).select_by_value(str(senior_num))
except:
## 에러가 나면 탑승객수 0명으로 선택
Select(senior_passenger).select_by_value(str(0))
##STR차량선택
srt_select_radio_btn = driver.find_element(By.ID, 'trnGpCd300')
srt_select_radio_btn.click()
##조회버튼클릭
serch_btn = driver.find_element(By.ID, 'search_top_tag')
serch_btn.click()
특실과 일반실 중에서 특실 경우만 다뤄보고 사용자의 선택에 따라 일반실만 다룰 수도 있고, 우선순위를 부여하여 특실이 없다면, 일반실 또는 일반실이 없다면, 특실 예약하기 등 사용자의 의도에 맞게 알고리즘을 설계할 수 있다. 구현된 알고리즘은 지정된 일자/시간의 가장 빠른 스케줄 예매이며, 특실 예매이다. 그래서 화면과 같이 예약하기 버튼이 활성화되어 있어서 반복문 없이도 바로 예약하고, break 문으로 진입할 수 있다. 예약하기 버튼은 xpath로 구현하였다. click()으로 예약하기를 완료하면, 코로나 관련 팝업창이 활성화된다. ok 버튼을 클릭하면 예약하기가 완료된다.
##조회버튼클릭
serch_btn = driver.find_element(By.ID, 'search_top_tag')
serch_btn.click()
##sleep을 위해서 time package 선언
import time
##운행시간 확인으로 페이지 안정화 이후 예매선택
train_schedule_add = '/html/body/div/div[4]/div/div[3]/div[1]/form/fieldset/div[6]/table/tbody/tr[1]/td[10]/a'
for i in range(10):
try:
driver.find_element_by_xpath(train_schedule_add)
print('pass')
break
except:
print('delay count: ', i)
time.sleep(0.05)
##예약이 될때까지 반복문수행
while True:
try:
##특실예약
vip_seat_btn_add = '/html/body/div/div[4]/div/div[3]/div[1]/form/fieldset/div[6]/table/tbody/tr[1]/td[6]/a'
vip_seat_btn = driver.find_element_by_xpath(vip_seat_btn_add)
vip_seat_btn.click()
##일반예약
#normal_seat = '/html/body/div/div[4]/div/div[3]/div[1]/form/fieldset/div[6]/table/tbody/tr[1]/td[7]/a'
#normal_seat_btn = driver.find_element_by_xpath(normal_seat_btn_add)
#normal_seat_btn.click()
except:
print('try book again ......')
pass
##예약이 완료되면, 코로나 관련 안내문이 활성화
try:
popup_add = '/html/body/div[2]/div[3]/div/button'
popup = driver.find_element_by_xpath(popup_add)
popup.click()
break
except:
print('popup is not activate')
pass
time.sleep(3)
driver.refresh()
print('book finished')
※좋아요/댓글은 서로를 응원합니다!
'파이썬 > 셀레늄크롤링' 카테고리의 다른 글
[python-파이썬] 네이버 블로그 자동 글쓰기 (1) | 2022.08.20 |
---|