KTX의 마지막..! 기차표를 예매해보자
ktx 예매를 해보면, 꽤 많은 데이터를 전달하는 것을 확인할 수 있다.
스케쥴 조회했던 것과 마찬가지로 테스트해가며 하나씩 분석해보자..
예매를 여러번 해보면서 찾은 결과
- URL : https://www.letskorail.com/ebizprd/EbizPrdTicketPr12111_i1.do
- Method : POST
Data Field
- selGoTrain : 기차 종류 (05 - 전체, 00 - KTX, 09 - ITX-청춘, 18 - ITX-마음, 02 - 무궁화, 03 - 통근열차)
- txtSeatAttCd2 : 좌석방향 (000 - 기본, 009 - 순방향석, 010 - 역방향석)
- txtSeatAttCd3 : 좌석위치 (000 - 기본, 011 - 1인석, 012 - 창측좌석, 013 - 내측좌석)
- txtSeatAttCd4 : 좌석속성
- txtTotPsgCnt : 총 인원 수
- txtPsgTpCd1 : 고정값 - 1
- txtPsgTpCd2 : 고정값 - 3
- txtPsgTpCd3 : 고정값 - 1
- txtPsgTpCd5 : 고정값 - 1
- txtPsgTpCd7 : 고정값 - 1
- txtPsgTpCd8 : 고정값 - 3
- txtCompaCnt1 : 일반 어른 수
- txtCompaCnt2 : 일반 어린이 수
- txtCompaCnt3 : 중증 장애인 수
- txtCompaCnt5 : 노인 수
- txtCompaCnt7 : 경증 장애인 수
- txtCompaCnt8 : 유아 수
- txtJobId : 예약타입(1101 - 일반, 1102 - 예약, 1103 - 좌석선택)
- txtJrnyCnt : 여정 개수 - 1
- txtPsrmClCd1 : 좌석 등급 (1-일반실, 2-특실)
- txtJrnySqno1 : 여정경로 (001 - 직통)
- txtJrnyTpCd1 : 여정타입 (11 - 편도)
- txtDptDt1 : 출발일 - 스케쥴 정보에 포함
- txtDptRsStnCd1 : 출발역 코드 - 스케쥴 정보에 포함
- txtDptRsStnCdNm1 : 출발역 이름 - 스케쥴 정보에 포함
- txtDptTm1 : 출발 시간 - 스케쥴 정보에 포함
- txtArvRsStnCd1 : 도착역 코드 - 스케쥴 정보에 포함
- txtArvRsStnCdNm1 : 도착역 이름 - 스케쥴 정보에 포함
- txtArvTm1 : 열차 도착 시간 - 스케쥴 정보에 포함
- txtTrnNo1 : 열차 번호 - 스케쥴 정보에 포함
- txtRunDt1 : 출발일 - 스케쥴 정보에 포함
- txtTrnClsfCd1 : 열차 종류 - 스케쥴 정보에 포함
- txtTrnGpCd1 : 기차 종류 - 스케쥴 정보에 포함
전달하는 데이터 중에 strHmac등 암호화 관련된 코드가 있긴 했으나, 실제 예매를 하는데는 아무 영향이 없었다.
위 정보로 완성된 예약 코드..!
def book_ticket(self, adult, child, baby, senior, svrDsb, mldDsb, train_schedule, txtSeatAttCd_3='000',
txtSeatAttCd_2='000', txtSeatAttCd_4='015', isReservation=False, isBusiness=False):
reservation_url = "https://www.letskorail.com/ebizprd/EbizPrdTicketPr12111_i1.do"
txtTotPsgCnt = adult + child + baby + senior + svrDsb + mldDsb
body = {
"txtSeatAttCd2": txtSeatAttCd_2, # 좌석방향 (000 - 기본, 009 - 순방향석, 010 - 역방향석)
"txtSeatAttCd3": txtSeatAttCd_3, # 좌석위치 (000 - 기본, 011 - 1인석, 012 - 창측좌석, 013 - 내측좌석)
"txtSeatAttCd4": txtSeatAttCd_4, # 좌석속성
"txtTotPsgCnt": txtTotPsgCnt, # 총 인원 수
"txtPsgTpCd1": "1", # 고정값
"txtPsgTpCd2": "3", # 고정값
"txtPsgTpCd3": "1", # 고정값
"txtPsgTpCd5": "1", # 고정값
"txtPsgTpCd7": "1", # 고정값
"txtPsgTpCd8": "3", # 고정값
"txtCompaCnt1": str(adult), # 일반 어른
"txtCompaCnt2": str(child), # 일반 어린이
"txtCompaCnt3": str(svrDsb), # 중증 장애인
"txtCompaCnt5": str(senior), # 노인
"txtCompaCnt7": str(mldDsb), # 경증 장애인
"txtCompaCnt8": str(baby), # 유아
"txtJobId": "1102" if isReservation else "1101", # 예약타입(1101 - 일반, 1102 - 예약, 1103 - 좌석선택)
"txtJrnyCnt": "1", # 여정 개수
"txtPsrmClCd1": "2" if isBusiness else "1", # 좌석 등급 (1-일반실, 2-특실)
"txtJrnySqno1": "001", # 여정경로 (001 - 직통)
"txtJrnyTpCd1": "11", # 여정타입 (11 - 편도)
"txtDptDt1": train_schedule['h_dpt_dt'], # 출발일 - 스케쥴 정보에 포함
"txtDptRsStnCd1": train_schedule['h_dpt_rs_stn_cd'], # 출발역 코드 - 스케쥴 정보에 포함
"txtDptRsStnCdNm1": train_schedule['h_dpt_rs_stn_cd_nm'], # 출발역 이름 - 스케쥴 정보에 포함
"txtDptTm1": train_schedule['h_dpt_tm'], # 출발 시간 - 스케쥴 정보에 포함
"txtArvRsStnCd1": train_schedule['h_arv_rs_stn_cd'], # 도착역 코드 - 스케쥴 정보에 포함
"txtArvRsStnCdNm1": train_schedule['h_arv_rs_stn_cd_nm'], # 도착역 이름 - 스케쥴 정보에 포함
"txtArvTm1": train_schedule['h_arv_tm'], # 열차 도착 시간 - 스케쥴 정보에 포함
"txtTrnNo1": train_schedule['h_trn_no'], # 열차 번호 - 스케쥴 정보에 포함
"txtRunDt1": train_schedule['h_run_dt'], # 출발일 - 스케쥴 정보에 포함
"txtTrnClsfCd1": train_schedule['h_trn_clsf_cd'], # 열차 종류 - 스케쥴 정보에 포함
"txtTrnGpCd1": train_schedule['h_trn_gp_cd'], # 기차 종류 - 스케쥴 정보에 포함
}
try:
reservation_res = self.session.post(reservation_url, data=body, headers=self.get_req_headers(
'https://www.letskorail.com/ebizprd/EbizPrdTicketPr21111_i1.do'))
except Exception as e:
self.error_callback('KTX 예매 실패', f"HTTP 요청에 실패했습니다 - \n{e}")
return False
try:
if '로그아웃' not in reservation_res.text:
if not self.login():
self.error_callback('KTX 예매 실패', '예약 중 로그인 재시도 실패') # 로그인 실패
return False
try:
reservation_res = self.session.post(reservation_url, data=body, headers=self.get_req_headers(
'https://www.letskorail.com/ebizprd/EbizPrdTicketPr21111_i1.do'))
except Exception as e:
self.error_callback('KTX 예매 실패', f"예약 중 재로그인 후 HTTP 요청에 실패했습니다 - \n{e}")
return False
except Exception as e:
self.error_callback('KTX 예매 실패', f"알 수 없는 에러 - \n{e}")
return False
detail_info = f"[{'특실' if isBusiness else '일반실'}] " \
f"{train_schedule['h_dpt_rs_stn_cd_nm']}⇀{train_schedule['h_arv_rs_stn_cd_nm']} " \
f"{train_schedule['h_dpt_tm'][0:2] + ':' + train_schedule['h_dpt_tm'][2:4]} " \
f"{'' if adult == 0 else '성인 ' + str(adult) + '명'} " \
f"{'' if child == 0 else '어린이 ' + str(child) + '명'} " \
f"{'' if baby == 0 else '아기 ' + str(baby) + '명'} " \
f"{'' if senior == 0 else '노인 ' + str(senior) + '명'} " \
f"{'' if svrDsb == 0 else '중증장애인 ' + str(svrDsb) + '명'} " \
f"{'' if mldDsb == 0 else '경증장애인 ' + str(mldDsb) + '명'} "
if "20분 이내 결제" in reservation_res.text or "예약 대기" in reservation_res.text:
self.try_callback(True, "", detail_info)
return True
if "잔여석없음" in reservation_res.text:
self.try_callback(False, "잔여석 없음", detail_info)
elif "예약대기자한도수초과" in reservation_res.text:
self.try_callback(False, "예약대기자 한도수 초과", detail_info)
elif "20분 이내 열차는 예약" in reservation_res.text:
self.try_callback(False, "20분 이내 열차 예약 불가", detail_info)
elif "일반최대 단체최소" in reservation_res.text:
self.try_callback(False, "인원 수 오류, 9명 이하만 예약 가능", detail_info)
else:
self.try_callback(False, "기타 사유", detail_info + reservation_res.text)
return False
풀 코드는 깃허브로..!
'프로젝트 > SRT&KTX 매진표 예매' 카테고리의 다른 글
SRT&KTX 기차표 매크로 예매 - (13) 예매시 이메일 보내기(smtplib, email) (1) | 2024.01.17 |
---|---|
SRT&KTX 기차표 매크로 예매 - (12) 예매시 텔레그램 알림 보내기(python-telegram-bot) (0) | 2024.01.17 |
SRT&KTX 기차표 매크로 예매 - (10) KTX 승차권 조회 (0) | 2024.01.15 |
SRT&KTX 기차표 매크로 예매 - (9) KTX 역 리스트 조회 (0) | 2024.01.15 |
SRT&KTX 기차표 매크로 예매 - (8) KTX 로그인 (0) | 2024.01.15 |