Querying Train Tickets from 12306 Using Python

Prerequisites

Before writing any code, you need to understadn how the 12306 website handles ticket quereis. Open the official 12306 website in your browser and navigate to the ticket booking section. Enter a departure station, arrival station, and travel date, then click the search button to perform a query.

Discovering the API Endpoint

Once the search results load, open your browser's developer tools by pressing F12. Navigate to the Network tab and filter for XHR requests. Among the displayed files, you'll find one that contains the train schedule data. Click on this request to examine its details.

Inspect the request URL and HTTP method. The URL typically contains three essential parameters: the travel date, departure station code, and arrival station code. These station codes are three-letter identifiers rather than full station names. For example, Beijing Station is coded as "BJP" and Shanghai Hongqiao is "SHH".

To simplify the code, create a mapping dictionary that associates station names with their corresponding codes. This allows users to input readable station names while the application converts them to the required format.

Implementation

The following Python code demonstrates how to retrieve and parse train ticket information:

import requests

# Station code mapping
station_codes = {
    "Beijing": "BJP",
    "Shanghai": "SHH",
    "Guangzhou": "GZQ",
    "Shenzhen": "SZQ",
    "Hangzhou": "HZH",
    # Add more stations as needed
}

def get_train_schedule(departure, arrival, travel_date):
    """
    Retrieve train schedule from 12306 API.
    
    Args:
        departure: Departure station name
        arrival: Arrival station name
        travel_date: Travel date in YYYY-MM-DD format
    
    Returns:
        List of dictionaries containing train information
    """
    from_station = station_codes.get(departure)
    to_station = station_codes.get(arrival)
    
    if not from_station or not to_station:
        raise ValueError("Invalid station names provided")
    
    url = "https://kyfw.12306.cn/botgrade/otn/leftTicket/query"
    params = {
        "leftTicketDTO.train_date": travel_date,
        "leftTicketDTO.from_station": from_station,
        "leftTicketDTO.to_station": to_station,
        "purpose_codes": "ADULT"
    }
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
    }
    
    response = requests.get(url=url, params=params, headers=headers)
    data = response.json()
    
    trains = []
    for item in data['data']['result']:
        columns = item.split('|')
        train_info = {
            "train_number": columns[3],
            "departure_time": columns[8],
            "arrival_time": columns[9],
            "duration": columns[10],
            "business_class": columns[32],
            "first_class": columns[31],
            "second_class": columns[30],
            "hard_sleeper": columns[28],
            "hard_seat": columns[29],
            "no_seat": columns[26],
            "soft_sleeper": columns[25]
        }
        trains.append(train_info)
    
    return trains

# Example usage
if __name__ == "__main__":
    print("Enter departure station:")
    dep = input().strip()
    print("Enter arrival station:")
    arr = input().strip()
    print("Enter travel date (YYYY-MM-DD):")
    date = input().strip()
    
    results = get_train_schedule(dep, arr, date)
    
    for train in results:
        print(f"Train {train['train_number']}: "
              f"{train['departure_time']} → {train['arrival_time']} "
              f"({train['duration']})")

Understanding the Response Structure

The API returns a JSON response where the actual train data is nested within data.result. Each entry in the result array is a pipe-delimited string containing multiple fields. The code above extracts the most commonly needed information by index position:

  • Index 3: Train number
  • Index 8: Departure time
  • Index 9: Arrival time
  • Index 10: Duration
  • Index 25: Soft sleeper availability
  • Index 26: No-seat availability
  • Index 28: Hard sleeper availability
  • Index 29: Hard seat availability
  • Index 30: Second class availability
  • Index 31: First class availability
  • Index 32: Business class availability

Important Notes

The 12306 API requires a valid User-Agent header to function correct. Additionally, the API endpoint may change over time, so you should verify the current endpoint using your browser's developer tools before running the code. Some responses may contain fallback routes or special train services, so the actual field positions might vary slightly between different types of trains.

This approach provides a straightforward method for programmatically accessing train ticket information, which can be extended to build more sophisticated applications such as ticket monitoring systems or fare comparison tools.

Posted on Sat, 04 Jul 2026 17:56:20 +0000 by dips_007