当前位置: 首页 > news >正文

别再手动查了!用Python+Requests 5分钟搞定12306时刻表数据抓取

用Python轻松抓取12306列车时刻表数据:5分钟从入门到实战

每次需要查询列车时刻表时,你是不是还在手动打开12306官网,输入车次、日期,然后一页页翻看?对于需要批量获取数据的研究者或数据分析师来说,这种方式效率实在太低。今天我们就用Python的Requests库,教你如何快速抓取12306的列车时刻表数据,整个过程不到5分钟就能搞定。

1. 准备工作:环境配置与接口分析

在开始编写代码前,我们需要先准备好Python环境和必要的库。打开你的终端或命令行工具,执行以下命令安装所需依赖:

pip install requests pandas

Requests库是Python中最流行的HTTP客户端库,而Pandas则是数据处理的神器,能让我们轻松地将抓取到的JSON数据转换为结构化的DataFrame。

通过分析12306的接口,我们发现获取列车时刻表数据主要分为两步:

  1. 根据车次查询列车编号:通过车次名称(如G123)和日期获取列车唯一编号
  2. 根据列车编号查询详细时刻表:使用上一步获取的列车编号查询该车次所有经停站的到发时间等信息

这两个接口都是GET请求,返回JSON格式数据,非常适合用Python处理。

2. 构建请求:模拟浏览器访问

12306的接口通常会有一些反爬机制,我们需要设置合理的请求头来模拟浏览器访问。以下是构建请求的关键点:

import requests headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Referer': 'https://www.12306.cn/' } def get_train_no(train_code, date): url = 'https://search.12306.cn/search/v1/train/search' params = { 'keyword': train_code, 'date': date # 格式: yyyyMMdd } response = requests.get(url, params=params, headers=headers) return response.json()

注意:日期格式在不同接口中可能不同,第一个接口使用yyyyMMdd格式,而第二个接口使用yyyy-MM-dd格式,这是常见的坑点。

3. 解析复杂JSON数据

从接口获取的数据通常是嵌套的JSON结构,我们需要学会如何提取所需信息。让我们看一个完整的示例:

def get_train_schedule(train_no, date): url = 'https://kyfw.12306.cn/otn/queryTrainInfo/query' params = { 'leftTicketDTO.train_no': train_no, 'leftTicketDTO.train_date': date, # 格式: yyyy-MM-dd 'rand_code': '' } response = requests.get(url, params=params, headers=headers) data = response.json() if data.get('status') and data.get('data'): stations = data['data']['data'] # 提取关键信息 schedule = [] for station in stations: item = { '站序': station['station_no'], '站名': station['station_name'], '到达时间': station['arrive_time'], '发车时间': station['start_time'], '停留时间': station['stopover_time'] if 'stopover_time' in station else '--', '历时天数': station['arrive_day_str'] } schedule.append(item) return schedule else: raise Exception(f"获取时刻表失败: {data.get('messages', '未知错误')}")

4. 完整工作流与数据保存

现在我们把所有步骤整合起来,形成一个完整的解决方案:

import pandas as pd from datetime import datetime def get_12306_schedule(train_code, search_date): # 第一步:获取列车编号 search_date_str = search_date.strftime('%Y%m%d') train_info = get_train_no(train_code, search_date_str) if not train_info.get('status') or not train_info.get('data'): raise Exception(f"未找到车次信息: {train_info.get('errorMsg', '未知错误')}") train_no = train_info['data'][0]['train_no'] # 第二步:获取时刻表 schedule_date_str = search_date.strftime('%Y-%m-%d') schedule = get_train_schedule(train_no, schedule_date_str) # 转换为DataFrame df = pd.DataFrame(schedule) df['车次'] = train_code df['查询日期'] = schedule_date_str # 保存为CSV filename = f"{train_code}_{search_date_str}.csv" df.to_csv(filename, index=False, encoding='utf_8_sig') return df # 使用示例 if __name__ == '__main__': df = get_12306_schedule('G123', datetime(2023, 7, 15)) print(df.head())

这段代码会输出一个包含列车所有经停站信息的表格,并自动保存为CSV文件。输出结果类似这样:

站序站名到达时间发车时间停留时间历时天数车次查询日期
01北京南--08:00--当日到达G1232023-07-15
02天津南08:3008:322分钟当日到达G1232023-07-15
........................

5. 高级技巧与错误处理

在实际使用中,你可能会遇到各种问题。下面分享几个实用技巧:

  1. 请求重试机制:网络请求可能会失败,添加重试逻辑提高稳定性
from time import sleep def safe_request(url, params, max_retries=3): for i in range(max_retries): try: response = requests.get(url, params=params, headers=headers, timeout=10) if response.status_code == 200: return response except Exception as e: print(f"请求失败,重试 {i+1}/{max_retries}: {e}") sleep(2) raise Exception(f"请求失败,已达到最大重试次数 {max_retries}")
  1. 日期验证:确保查询日期有效
def validate_date(date_str, fmt='%Y%m%d'): try: date = datetime.strptime(date_str, fmt) if date < datetime.now(): raise ValueError("查询日期不能早于当前日期") return date except ValueError as e: raise ValueError(f"日期格式错误: {e}")
  1. 批量查询:如果需要查询多个车次
def batch_query(train_codes, date): results = [] for code in train_codes: try: df = get_12306_schedule(code, date) results.append(df) print(f"成功获取 {code} 时刻表") except Exception as e: print(f"获取 {code} 时刻表失败: {e}") return pd.concat(results) if results else None

6. 数据应用场景

获取到的列车时刻表数据可以用于多种分析场景:

  • 旅行时间分析:计算不同车次的全程耗时
  • 站点流量统计:分析各站的经停车次数量
  • 票价与时间关系:结合票价数据研究性价比
  • 延误分析:如果有历史数据,可以研究常见延误区间

这里有一个简单的分析示例,计算车次的总运行时间:

def calculate_duration(df): first_station = df.iloc[0] last_station = df.iloc[-1] start_time = first_station['发车时间'] end_time = last_station['到达时间'] # 转换为时间对象进行计算 fmt = '%H:%M' start = datetime.strptime(start_time, fmt) end = datetime.strptime(end_time, fmt) duration = end - start # 处理跨天情况 if duration.days < 0: duration = timedelta(days=1) + duration return str(duration)

7. 法律与道德注意事项

在使用这类技术时,请务必注意:

  1. 遵守网站的使用条款:不要过度频繁请求,避免对服务器造成压力
  2. 合理设置请求间隔:建议在请求间添加1-2秒的延迟
  3. 仅用于合法用途:获取的数据不要用于商业用途或违反相关法规
  4. 尊重数据版权:明确数据的版权归属和使用限制

在实际项目中,我发现最实用的技巧是将这些函数封装成一个类,方便复用和管理。比如可以创建一个TrainScheduleFetcher类,初始化时设置headers和请求参数,然后提供各种查询方法。

http://www.jsqmd.com/news/565686/

相关文章:

  • Oni-Duplicity:3分钟掌握《缺氧》存档编辑,告别资源焦虑
  • 直击制造业六大核心痛点,MES解决方案全解析
  • Argos Translate:如何为你的应用构建企业级离线翻译能力?
  • 【实战指南】Docker中PostgreSQL数据库的备份与恢复全流程解析
  • Qwen3-Coder-30B-A3B-Instruct:面向企业级代码工程的混合专家架构实践
  • 2026年恒压变频供水设备选购指南:A品牌与B品牌深度对比与决策分析 - 速递信息
  • 2026永州找GEO推广服务怕被坑?湖南企拓官方电话与避坑指南 - 精选优质企业推荐榜
  • 如何快速掌握Markdown预览:终极浏览器插件使用教程
  • X11桌面自动化实战指南:用xdotool提升Linux工作效率的终极解决方案
  • Windows 10/11下用StyleGAN2-ADA-PyTorch训练自己的数据集(避坑Visual Studio编译错误)
  • 告别混乱!「秒云Tokens管家」一个API Key搞定所有大模型!
  • 全球燃料电池堆:高增27.8%,2032年剑指401.5亿
  • 2026年3月展览展示公司推荐,卓越展览展示、智慧展览展示、定制化展览展示、创意展览展示、特装展览展示,一站式全流程创意落地服务商 - 品牌企业推荐师(官方)
  • 2026果蔬脆源头工厂推荐榜:全产业链定制服务商TOP4,B端健康零食解决方案权威参考 - 博客湾
  • VS Code + MSVC 编译C++17代码报错?手把手教你配置tasks.json和c_cpp_properties.json
  • AIVideo效果实测:输入“夏日旅行”,看AI如何生成完整Vlog视频
  • 缠论量化架构演进:从理论数学化到系统工程化的范式重构
  • Open-Sora:面向大众的视频生成技术全攻略
  • TradingAgents-CN 多智能体金融分析系统:企业级容器化部署实战指南
  • 2026年面粉选哪家好?B端采购必看的5个评估维度 - 速递信息
  • CVE-2024-36401复现
  • RetroArch缩略图显示异常终极解决方案:三步排查与长效优化指南
  • SPI通信协议详解
  • 非阻塞写的完整逻辑
  • 2026年天津学面点/学西点蛋糕/学烹饪技术公司推荐:天津新东方职业培训学校,初中毕业学技术优选 - 品牌推荐官
  • 告别重复查询:用快马ai为solidworks工程师定制效率提升工具
  • site指令实战:精准定位与高效屏蔽的搜索艺术
  • A实验:AI人工智能T型迷宫 AI人工智能T迷宫组成资料。
  • 2026年电网储能系统厂家推荐:江苏阿诗特能源科技,工商业/户用储能及储能逆变器等全系产品解析 - 品牌推荐官
  • ARM Cortex-M嵌入式通用头文件sarmfsw深度解析