본문 바로가기
프로젝트/SRT&KTX 매진표 예매

SRT&KTX 기차표 매크로 예매 - (10) KTX 승차권 조회

by 매크로메이커 2024. 1. 15.

KTX 기차표를 조회해보자.

 

KTX 기차표 조회 화면

POST 요청의 Payload를 보면 데이터가 엄...청나게 많다.

 

불필요한 데이터가 많을 것 같으니, 천천히 분석해보자. 결과는 다음과 같다.

승차권 조회를 여러번 해보면서 찾은 결과

Data Field

  • selGoTrain : 기차 종류 (05 - 전체, 00 - KTX, 09 - ITX-청춘, 18 - ITX-마음, 02 - 무궁화, 03 - 통근열차)
  • txtPsgFlg_1 : 성인 수
  • txtPsgFlg_2 : 어린이 수(만6~12세)
  • txtPsgFlg_8 : 아기 수(만6세 미만)
  • txtPsgFlg_3 : 노인 수
  • txtPsgFlg_4 : 중증장애인 수
  • txtPsgFlg_5 : 경증장애인 수
  • txtSeatAttCd_3 : 좌석위치 (000 - 기본, 011 - 1인석, 012 - 창측좌석, 013 - 내측좌석)
  • txtSeatAttCd_2 : 좌석방향 (000 - 기본, 009 - 순방향석, 010 - 역방향석)
  • txtSeatAttCd_4 : 좌석속성 (015 - 일반, 019 - 유아동반/편한대화, 031 - 노트북,  021 - 수동휠체어, 028 - 전동휠체어, XXX - 수유실 인접, 018 - 2층석, 032 - 자전거거치대)
  • selGoTrainRa : [추정] selGoTrain과 동일
  • radJobId : 여정 경로(1 - 직통, 2 - 환승, 3 - 왕복)
  • adjcCheckYn : 인접역 포함 여부 ("Y", "N")
  • txtGoStart : 출발역 텍스트 (e.g. 서울)
  • txtGoEnd : 도착역 텍스트 (e.g. 청량리)
  • txtGoHour : 출발 시간 (e.g. 180000 - HHMMSS)
  • txtGoPage : 조회 페이지 - 항상 1
  • txtGoAbrdDt : 출발일(e.g. 20240120)
  • checkStnNm : 항상 "Y"
  • hidRsvTpCd : 예약구분 (03 - 일반예약, 09 - 단체예약)
  • 나머지 - 안보내도 됨

데이터 포맷을 맞춰서 post 요청을 보내면 아래와 같은 java script 포맷의 데이터를 얻을 수 있다.

열차 시간표 데이터

각 파라미터의 의미를 이해하려면 train_info 함수를 들어댜봐야한다.

train_info 파라미터

이 정보를 가지고 스케쥴을 정리해서 반환하게끔 해서 마무리하면 메서드는 아래와 같이 완성된다

def fetch_schedule(self, txtGoStart, txtGoEnd, txtGoAbrdDt, txtGoHour, adult, child, baby, senior, svrDsb, mldDsb,
                   radJobId='1', txtSeatAttCd_3='000', txtSeatAttCd_2 = '000', txtSeatAttCd_4='015', selGoTrain='00', dlayTnumAplFlg='Y'):
    schedule_url = "https://www.letskorail.com/ebizprd/EbizPrdTicketPr21111_i1.do"
    body = {
        "selGoTrain": selGoTrain,           # 기차 종류 (05-전체, 00-KTX, 09-ITX-청춘, 18-ITX-마음, 02-무궁화, 03-통근열차)
        "txtPsgFlg_1": adult,               # 성인 수
        "txtPsgFlg_2": child,               # 어린이 수(만6~12세)
        "txtPsgFlg_8": baby,                # 아기 수(만6세 미만)
        "txtPsgFlg_3": senior,              # 노인 수
        "txtPsgFlg_4": svrDsb,              # 중증장애인 수
        "txtPsgFlg_5": mldDsb,              # 경증장애인 수
        "txtSeatAttCd_3": txtSeatAttCd_3,   # 좌석위치 (000 - 기본, 011 - 1인석, 012 - 창측좌석, 013 - 내측좌석)
        "txtSeatAttCd_2": txtSeatAttCd_2,   #  좌석방향 (000 - 기본, 009 - 순방향석, 010 - 역방향석)
        "txtSeatAttCd_4": txtSeatAttCd_4,   # 좌석속성 (015 - 일반, 019 - 유아동반/편한대화, 031 - 노트북,  021 - 수동휠체어,
                                            # 028 - 전동휠체어, XXX - 수유실 인접, 018 - 2층석, 032 - 자전거거치대)
        "selGoTrainRa": selGoTrain,         # [추정] selGoTrain과 동일
        "radJobId": radJobId,               # 여정 경로(1 - 직통, 2 - 환승, 3 - 왕복)
        "adjcCheckYn": "N",                 # 인접역 포함 여부 ("Y", "N")
        "txtGoStart": txtGoStart,           # 출발역 텍스트 (e.g. 서울)
        "txtGoEnd": txtGoEnd,               # 도착역 텍스트 (e.g. 청량리)
        "txtGoHour": txtGoHour,             # 출발 시간 (e.g. 180000 - HHMMSS)
        "txtGoPage": "1",                   # 조회 페이지 - 항상 1
        "txtGoAbrdDt": txtGoAbrdDt,         # 출발일(e.g. 20240120)
        "checkStnNm": "Y",                  # 항상 "Y"
        "hidRsvTpCd": "03",                 # 예약구분 (03 - 일반예약, 09 - 단체예약)
    }
    try:
        res = self.session.post(schedule_url, data=body, headers=self.get_req_headers())
    except Exception as e:
        self.error_callback('KTX 열차 조회 실패', f"HTTP 요청에 실패했습니다 - \n{e}")
        return []

    try:
        soup = BeautifulSoup(res.text, 'html.parser')
        trains = soup.find_all("script", string=re.compile('new train_info'))
    except Exception as e:
        self.error_callback('KTX 열차 조회 실패', f"HTML 파싱에 실패했습니다 - \n{e}")
        return []

    result = []
    try:
        for tr in trains:
            tr = tr.text.replace('\t', '').replace(' ', '').replace("\r\n", "").replace("\"", "")
            tr = tr[tr.find('(')+1:]
            tr = tr[:tr.rfind(')')]
            tr = tr.split(',')

            schedule_info = dict()
            schedule_info["txtGoAbrdDt"] = tr[0]
            schedule_info["txtGoStartCode"] = tr[1]
            schedule_info["txtGoEndCode"] = tr[2]
            schedule_info["selGoTrain"] = tr[3]
            schedule_info["selGoRoom"] = tr[4]
            schedule_info["txtGoHour"] = tr[5]
            schedule_info["txtGoTrnNo"] = tr[6]
            schedule_info["useSeatFlg"] = tr[7]
            schedule_info["useServiceFlg"] = tr[8]
            schedule_info["selGoSeat"] = tr[9]
            schedule_info["selGoSeat1"] = tr[10]
            schedule_info["selGoSeat2"] = tr[11]
            schedule_info["txtPsgCnt1"] = tr[12]
            schedule_info["txtPsgCnt2"] = tr[13]
            schedule_info["selGoService"] = tr[14]
            schedule_info["h_trn_seq"] = tr[15]
            schedule_info["h_chg_trn_dv_cd"] = tr[16]
            schedule_info["h_chg_trn_seq"] = tr[17]
            schedule_info["h_dpt_rs_stn_cd"] = tr[18]
            schedule_info["h_dpt_rs_stn_cd_nm"] = tr[19]
            schedule_info["h_arv_rs_stn_cd"] = tr[20]
            schedule_info["h_arv_rs_stn_cd_nm"] = tr[21]
            schedule_info["h_trn_no"] = tr[22]
            schedule_info["h_yms_apl_flg"] = tr[23]
            schedule_info["h_trn_clsf_cd"] = tr[24]
            schedule_info["h_trn_gp_cd"] = tr[25]
            schedule_info["h_seat_att_cd"] = tr[26]
            schedule_info["h_run_dt"] = tr[27]
            schedule_info["h_dpt_dt"] = tr[28]
            schedule_info["h_dpt_tm"] = tr[29]
            schedule_info["h_arv_dt"] = tr[30]
            schedule_info["h_arv_tm"] = tr[31]
            schedule_info["h_dlay_hr"] = tr[32]
            schedule_info["h_rsv_wait_ps_cnt"] = tr[33]
            schedule_info["h_dtour_flg"] = tr[34]
            schedule_info["h_car_tp_cd"] = tr[35]
            schedule_info["h_trn_cps_cd1"] = tr[36]
            schedule_info["h_trn_cps_cd2"] = tr[37]
            schedule_info["h_trn_cps_cd3"] = tr[38]
            schedule_info["h_trn_cps_cd4"] = tr[39]
            schedule_info["h_trn_cps_cd5"] = tr[40]
            schedule_info["h_no_ticket_dpt_rs_stn_cd"] = tr[41]
            schedule_info["h_no_ticket_arv_rs_stn_cd"] = tr[42]
            schedule_info["h_nonstop_msg"] = tr[43]
            schedule_info["h_dpt_stn_cons_ordr"] = tr[44]
            schedule_info["h_arv_stn_cons_ordr"] = tr[45]
            schedule_info["h_dpt_stn_run_ordr"] = tr[46]
            schedule_info["h_arv_stn_run_ordr"] = tr[47]
            schedule_info["h_stnd_rest_seat_cnt"] = tr[48]
            schedule_info["h_free_rest_seat_cnt"] = tr[49]

            result.append(schedule_info)
    except Exception as e:
        self.error_callback('KTX 열차 조회 실패', f"열차 시간표 파싱에 실패했습니다 - \n{e}")

 

풀 코드는 깃허브로..!