TrainQuery.API
1.0.0
See the version list below for details.
dotnet add package TrainQuery.API --version 1.0.0
NuGet\Install-Package TrainQuery.API -Version 1.0.0
<PackageReference Include="TrainQuery.API" Version="1.0.0" />
<PackageVersion Include="TrainQuery.API" Version="1.0.0" />
<PackageReference Include="TrainQuery.API" />
paket add TrainQuery.API --version 1.0.0
#r "nuget: TrainQuery.API, 1.0.0"
#:package TrainQuery.API@1.0.0
#addin nuget:?package=TrainQuery.API&version=1.0.0
#tool nuget:?package=TrainQuery.API&version=1.0.0
TrainQuery.API - 12306火车票查询类库
📦 NuGet包信息
- 包名称:
TrainQuery.API - 当前版本: 1.0.0
- 作者: 孟煌喆
- 目标框架: .NET Framework 4.8.1
- 依赖项: Newtonsoft.Json (≥13.0.3)
🚀 快速开始
安装包
# Package Manager Console
Install-Package TrainQuery.API
# .NET CLI
dotnet add package TrainQuery.API
# PackageReference
<PackageReference Include="TrainQuery.API" Version="1.0.0" />
基础使用示例
using TrainQuery.API;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
using (var service = new TrainQueryService())
{
// 订阅调试信息
service.DebugMessage += (sender, message) =>
Console.WriteLine($"[DEBUG] {message}");
// 1. 初始化车站数据(必须首先调用)
Console.WriteLine("正在初始化车站数据...");
bool initSuccess = await service.InitializeStationsAsync();
if (!initSuccess)
{
Console.WriteLine("车站数据初始化失败");
return;
}
// 2. 查询车票
Console.WriteLine("正在查询车票...");
var tickets = await service.QueryDirectTicketsAsync(
fromStation: "北京",
toStation: "上海",
date: DateTime.Now.AddDays(1).ToString("yyyy-MM-dd")
);
// 3. 显示结果
Console.WriteLine($"找到 {tickets.Count} 个车次");
foreach (var ticket in tickets.Take(5))
{
Console.WriteLine($"\n车次: {ticket.TrainNo}");
Console.WriteLine($" 出发: {ticket.FromStation} ({ticket.DepartureTime})");
Console.WriteLine($" 到达: {ticket.ToStation} ({ticket.ArrivalTime})");
Console.WriteLine($" 历时: {ticket.Duration}");
Console.WriteLine($" 状态: {ticket.Status}");
}
}
}
}
📚 详细使用说明
1. 初始化服务
// 创建服务实例(推荐使用using语句确保资源释放)
using var service = new TrainQueryService();
// 可选:订阅调试信息
service.DebugMessage += (sender, message) =>
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {message}");
// 可选:订阅车站加载完成事件
service.StationsLoaded += (sender, count) =>
Console.WriteLine($"已加载 {count} 个车站");
2. 车站数据初始化
重要:必须首先调用此方法!
// 初始化车站数据
bool success = await service.InitializeStationsAsync();
if (!success)
{
// 初始化失败,可能是网络问题
Console.WriteLine("车站数据初始化失败,请检查网络连接");
return;
}
// 成功后可进行查询操作
3. 查询直达车票
var tickets = await service.QueryDirectTicketsAsync(
fromStation: "北京", // 出发站(中文站名)
toStation: "上海", // 到达站(中文站名)
date: "2024-01-20", // 日期格式:yyyy-MM-dd
trainTypes: new List<string> { "G", "D" } // 可选:过滤车次类型
);
4. 查询中转换乘方案
var transferSolutions = await service.QueryTransferSolutionsAsync(
fromStation: "北京",
toStation: "广州",
date: "2024-01-20"
);
foreach (var solution in transferSolutions)
{
Console.WriteLine($"中转方案: {solution.MiddleStationName}");
Console.WriteLine($" 总历时: {solution.AllDuration}");
Console.WriteLine($" 等待时间: {solution.WaitTime}");
foreach (var segment in solution.Segments)
{
Console.WriteLine($" 车次: {segment.StationTrainCode}");
Console.WriteLine($" {segment.FromStationName} → {segment.ToStationName}");
}
}
5. 查询票价信息
var priceInfo = await service.QueryTicketPriceAsync(
trainNo: "G1", // 车次
fromStation: "北京南", // 出发站
toStation: "上海虹桥", // 到达站
date: "2024-01-20" // 日期
);
Console.WriteLine($"车次 {priceInfo.TrainNo} 票价:");
foreach (var price in priceInfo.Prices)
{
Console.WriteLine($" {price.Key}: {price.Value:N1}元");
}
6. 查询列车经停站
var stopStations = await service.QueryTrainStopStationsAsync(
trainNo: "G1", // 车次
fromStation: "北京南", // 出发站
toStation: "上海虹桥", // 到达站
date: "2024-01-20" // 日期
);
Console.WriteLine($"车次 G1 经停站 ({stopStations.Count} 个):");
foreach (var station in stopStations)
{
string stationName = station.TryGetValue("station_name", out var name) ? name : "";
string arriveTime = station.TryGetValue("arrive_time", out var arrive) ? arrive : "--";
string startTime = station.TryGetValue("start_time", out var start) ? start : "--";
Console.WriteLine($" {stationName}: 到达 {arriveTime}, 出发 {startTime}");
}
🎯 进阶用法
Windows Forms 应用示例
using TrainQuery.API;
using System;
using System.Windows.Forms;
public partial class MainForm : Form
{
private TrainQueryService _service;
public MainForm()
{
InitializeComponent();
_service = new TrainQueryService();
// 订阅调试消息
_service.DebugMessage += (sender, message) =>
txtDebug.Invoke(new Action(() =>
txtDebug.AppendText(message + Environment.NewLine)));
}
private async void btnQuery_Click(object sender, EventArgs e)
{
try
{
btnQuery.Enabled = false;
lblStatus.Text = "查询中...";
// 初始化车站数据
if (!await _service.InitializeStationsAsync())
{
MessageBox.Show("车站数据初始化失败");
return;
}
// 查询车票
var tickets = await _service.QueryDirectTicketsAsync(
txtFrom.Text,
txtTo.Text,
dtpDate.Value.ToString("yyyy-MM-dd")
);
// 显示结果
dgvResults.Rows.Clear();
foreach (var ticket in tickets)
{
dgvResults.Rows.Add(
ticket.TrainNo,
ticket.FromStation,
ticket.ToStation,
ticket.DepartureTime,
ticket.ArrivalTime,
ticket.Duration,
ticket.Status
);
}
lblStatus.Text = $"找到 {tickets.Count} 个车次";
}
catch (Exception ex)
{
MessageBox.Show($"查询失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
btnQuery.Enabled = true;
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
_service?.Dispose();
base.OnFormClosing(e);
}
}
ASP.NET Web Forms 示例
using TrainQuery.API;
using System;
using System.Threading.Tasks;
using System.Web.UI;
public partial class QueryPage : Page
{
private TrainQueryService GetService()
{
// 使用Session存储服务实例
if (Session["TrainQueryService"] == null)
{
var service = new TrainQueryService();
Session["TrainQueryService"] = service;
}
return (TrainQueryService)Session["TrainQueryService"];
}
protected async void btnQuery_Click(object sender, EventArgs e)
{
try
{
lblMessage.Text = "查询中...";
var service = GetService();
// 异步初始化车站数据
if (!await service.InitializeStationsAsync())
{
lblMessage.Text = "车站数据初始化失败";
return;
}
// 查询车票
var tickets = await service.QueryDirectTicketsAsync(
txtFrom.Text,
txtTo.Text,
txtDate.Text
);
// 绑定到GridView
gvTickets.DataSource = tickets;
gvTickets.DataBind();
lblMessage.Text = $"找到 {tickets.Count} 个车次";
}
catch (Exception ex)
{
lblMessage.Text = $"查询失败: {ex.Message}";
}
}
}
⚠️ 重要注意事项
1. 初始化要求
必须首先调用 InitializeStationsAsync() 方法:
// 正确用法
using var service = new TrainQueryService();
await service.InitializeStationsAsync(); // 必须先调用
var tickets = await service.QueryDirectTicketsAsync(...);
// 错误用法(会抛出异常)
using var service = new TrainQueryService();
var tickets = await service.QueryDirectTicketsAsync(...); // 错误!未初始化
2. 异常处理
try
{
using var service = new TrainQueryService();
// 可能抛出异常的调用
var tickets = await service.QueryDirectTicketsAsync(...);
}
catch (ArgumentException ex)
{
// 参数错误,如车站不存在
Console.WriteLine($"参数错误: {ex.Message}");
}
catch (InvalidOperationException ex)
{
// 操作顺序错误,如未初始化
Console.WriteLine($"操作错误: {ex.Message}");
}
catch (HttpRequestException ex)
{
// 网络错误
Console.WriteLine($"网络错误: {ex.Message}");
}
catch (Exception ex)
{
// 其他错误
Console.WriteLine($"未知错误: {ex.Message}");
}
3. 线程安全
- 服务实例不是线程安全的
- 建议每个线程或请求创建独立的实例
- 避免在多线程中共享同一个实例
4. 资源管理
// 推荐:使用using语句确保资源释放
using (var service = new TrainQueryService())
{
// 使用服务...
}
// 或者手动调用Dispose()
var service = new TrainQueryService();
try
{
// 使用服务...
}
finally
{
service.Dispose();
}
🔧 配置和优化
1. 网络超时设置
类库内置了网络超时设置(默认30秒),但12306服务器响应时间可能变化:
- 正常情况:3-10秒
- 高峰期:可能超过15秒
2. 调试信息
// 启用调试信息输出
service.DebugMessage += (sender, message) =>
{
Console.WriteLine($"[DEBUG] {message}");
// 记录到文件
File.AppendAllText("train_query.log",
$"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}{Environment.NewLine}");
};
3. 性能优化建议
// 1. 重用服务实例(在同一线程中)
using var service = new TrainQueryService();
await service.InitializeStationsAsync();
// 多次查询使用同一个实例
var tickets1 = await service.QueryDirectTicketsAsync(...);
var tickets2 = await service.QueryDirectTicketsAsync(...);
// 2. 并行查询多个日期(谨慎使用,避免被限制)
var tasks = new List<Task<List<TicketInfo>>>();
for (int i = 0; i < 3; i++)
{
var date = DateTime.Now.AddDays(i).ToString("yyyy-MM-dd");
tasks.Add(service.QueryDirectTicketsAsync("北京", "上海", date));
}
var results = await Task.WhenAll(tasks);
🐛 常见问题解决
Q1: 出现"找不到车站代码"错误
原因: 车站名称不正确或车站数据未加载 解决:
// 1. 确保已调用InitializeStationsAsync()
// 2. 使用正确的中文站名(如"北京"不是"北京市")
// 3. 常见站名示例:
// - "北京", "上海", "广州", "深圳"
// - "北京南", "上海虹桥", "广州南"
Q2: 返回HTML而不是JSON数据
原因: 12306反爬机制触发 解决:
// 1. 等待一段时间后重试
await Task.Delay(2000);
// 2. 检查网络环境,避免使用VPN或代理
// 3. 确保使用最新版本
Q3: 查询速度慢
原因: 网络延迟或12306服务器繁忙 解决:
// 1. 使用异步编程避免阻塞UI线程
// 2. 添加进度提示
// 3. 考虑缓存查询结果
Q4: Newtonsoft.Json版本冲突
原因: 项目中存在多个Newtonsoft.Json版本 解决:
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
</dependentAssembly>
📋 数据模型说明
TicketInfo(车票信息)
public class TicketInfo
{
public string TrainNo { get; set; } // 车次
public string FromStation { get; set; } // 出发站
public string ToStation { get; set; } // 到达站
public string DepartureTime { get; set; } // 出发时间
public string ArrivalTime { get; set; } // 到达时间
public string Duration { get; set; } // 历时
public string Status { get; set; } // 状态(有票/无票)
// 座位余量信息
public Dictionary<string, string> SeatAvailability { get; set; }
}
TransferSolution(中转换乘方案)
public class TransferSolution
{
public string AllDuration { get; set; } // 总历时
public string MiddleStationName { get; set; } // 中转站
public string WaitTime { get; set; } // 等待时间
public List<TransferSegment> Segments { get; set; } // 行程分段
public Dictionary<string, decimal> TotalPrices { get; set; } // 总票价组合
}
PriceInfo(票价信息)
public class PriceInfo
{
public string TrainNo { get; set; } // 车次
public Dictionary<string, decimal> Prices { get; set; } // 座位类型 -> 价格
}
🔄 版本历史
版本 1.0.0 (2024-01-19)
- ✅ 车票查询(直达车次)
- ✅ 中转换乘方案查询
- ✅ 票价查询
- ✅ 列车经停站查询
- ✅ 车站数据自动加载
- ✅ 详细的错误处理和调试信息
- ✅ 完整的.NET Framework 4.8.1支持
- ✅ Newtonsoft.Json 13.0.3+ 依赖
📞 技术支持
- NuGet包页面: TrainQuery.API
- 问题反馈: 通过NuGet包页面留言
- 注意事项: 本库基于12306官方API实现,使用前请确保遵守相关服务条款
🚂 关于 12306 接口的说明
本项目在实现车票查询、余票监控等功能时,所调用的火车票数据接口,来源于中国铁路12306官方网站(kyfw.12306.cn)及其相关服务域名。
⚠️ 重要须知与风险提示
请注意以下几点:
- 非官方合作接口:本项目使用的接口为12306网站为自身前端功能所提供的服务,并非12306官方对外公开的合作或商业API。因此,不存在官方的《API使用规定》或服务条款。
- 接口不确定性:这些接口的结构、参数、返回数据格式可能在不经通知的情况下发生变更,导致项目功能暂时失效[citation:10]。
- 访问限制风险:12306系统对高频、非正常访问行为(如自动化脚本频繁查询)设有严格的防护机制,包括但不限于IP封禁、请求限流(返回403/429等状态码)等[citation:5]。
- 法律与合规风险:任何未经授权的自动化访问、大规模抓取数据、或干扰系统正常运行的行为,都可能违反《网络安全法》等相关法律法规及12306网站自身的用户协议[citation:5]。
- 项目目的:本项目仅限于技术学习与研究交流,旨在理解大型并发系统的设计(如缓存策略[citation:1]、分布式锁[citation:1]等),严禁用于任何商业盈利、大规模抢票、干扰12306系统正常运行或其他非法用途。
📖 技术参考与学习价值
项目中关于高并发、缓存、分布式锁等技术的实现(如责任链模式验证[citation:1]、分布式锁处理[citation:1]、令牌限流[citation:1]等),参考了业界对12306这类高流量系统的技术分析和开源学习项目。这些技术实现本身具有很高的学习价值,与实际使用的数据接口是解耦的。
📄 许可证
MIT License - 详见NuGet包中的LICENSE文件
开始使用: Install-Package TrainQuery.API
祝你使用愉快!如有问题,请查看常见问题部分或通过NuGet页面反馈。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET Framework | net481 is compatible. |
-
.NETFramework 4.8.1
- Newtonsoft.Json (>= 13.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
初始版本功能:
1. 车票查询(直达)
2. 中转换乘方案
3. 票价查询
4. 经停站信息
5. 车站数据自动加载