乌兹别克斯坦火车票查询

🤖 AGENT INSTRUCTION:查票先加载 uzbekistan-train-tickets skill(skill_view(name="uzbekistan-train-tickets")),然后走官网 API 直接查询(不需要登录、不需要 browser)。详细代码见 skill。监控脚本在 ~/.hermes/scripts/uzrail_*.py

官网 API 查票(Agent 首选)

**不需要登录。**两步即可:

① 获取 CSRF Token

GET https://eticket.railway.uz/api/v1/csrf-token

返回空 body,Set-Cookie 里有 XSRF-TOKEN

② 查询车次

POST https://eticket.railway.uz/api/v3/handbook/trains/list

必须带以下全部 Header:

X-XSRF-TOKEN: <csrf_token>
X-Custom-Language: en
Content-Type: application/json
Origin: https://eticket.railway.uz
Referer: https://eticket.railway.uz/en/home
User-Agent: Mozilla/5.0 Chrome/123 Safari/537.36
Accept: application/json
Accept-Language: en

⚠️ 仅带 X-XSRF-TOKEN 会返回 400 Bad RequestOriginReferer 缺一不可。

请求体示例(布哈拉 → 希瓦,5月7日):

{
  "directions": {
    "forward": {
      "date": "2026-05-07",
      "depStationCode": "2900800",
      "arvStationCode": "2900172"
    }
  }
}

返回 data.directions.forward.trains[],每个车次含 numberbranddepartureDatecars[].freeSeats

车站代码速查

车站代码
塔什干2900000
撒马尔罕2900700
布哈拉-12900800
希瓦2900172
乌尔根奇2900790

日期格式注意

出发日期格式为 DD.MM.YYYY HH:MM(不是 ISO 8601!),例如返回 06.05.2026 05:32

Python 一行流

http.cookiejar + urllib.request,不需要任何第三方包。完整可运行版本见 ~/.hermes/scripts/uzrail_samarkand_bukhara_monitor.pyuzrail_khiva_bukhara_20260504_monitor.py


🔧 常见错误排查

400 Bad Request

症状:第二步 POST 返回 HTTP 400,body 只有 {"status":400,"error":"Bad Request"}

根因:API 的安全层需要 Origin 和 Referer 头,仅带 X-XSRF-TOKEN 不够。

✅ 必须带的完整 Header:

headers = {
    "X-XSRF-TOKEN": xsrf_token,
    "X-Custom-Language": "en",
    "Content-Type": "application/json",
    "Origin": "https://eticket.railway.uz",
    "Referer": "https://eticket.railway.uz/en/home",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/123 Safari/537.36",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "en",
}

完整的 Python 片段(可直接运行):

import json, urllib.request, http.cookiejar
 
BASE = "https://eticket.railway.uz"
cj = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
 
# ① CSRF
opener.open(urllib.request.Request(BASE + "/api/v1/csrf-token"), timeout=15)
xsrf = next((c.value for c in cj if c.name == "XSRF-TOKEN"), None)
 
# ② Query
payload = json.dumps({
    "directions": {
        "forward": {
            "date": "2026-05-07",
            "depStationCode": "2900800",
            "arvStationCode": "2900172"
        }
    }
}).encode()
 
req = urllib.request.Request(
    BASE + "/api/v3/handbook/trains/list",
    data=payload,
    headers={
        "X-XSRF-TOKEN": xsrf,
        "X-Custom-Language": "en",
        "Content-Type": "application/json",
        "Origin": BASE,
        "Referer": BASE + "/en/home",
        "User-Agent": "Mozilla/5.0 Chrome/123 Safari/537.36",
        "Accept": "application/json, text/plain, */*",
        "Accept-Language": "en",
    }
)
with opener.open(req, timeout=25) as resp:
    data = json.loads(resp.read().decode())
 
trains = data["data"]["directions"]["forward"]["trains"]
for t in trains:
    print(t["number"], t.get("brand"), t["departureDate"])

日期解析错误

返回的日期是 DD.MM.YYYY HH:MM 格式,别用 datetime.fromisoformat()。用:

from datetime import datetime
dep_dt = datetime.strptime(dep_raw, "%d.%m.%Y %H:%M")

官网查票(人工)

打开 https://eticket.railway.uz/en/home,选 From/To/Date,点 Search。

⚠️ 不要用 browser_click 操作官网表单——Angular + Ant Design 下拉框不可交互。


备选方案

  • 12go.asia — 第三方聚合器:https://12go.asia/en/travel/samarkand/bukhara?date=YYYY-MM-DD
  • eurasia.travel — 第三方订票网站
  • Seat61 — 静态英文参考:seat61.com/Uzbekistan.htm

注意事项

  • 票提前 ~45 天开售
  • Afrosiyob 高铁座被旅行社团购快速抢光
  • 电子票手机出示即可
  • 购票需要护照号
  • 热线:1005