12306 Train Booking

Other

12306-specific knowledge for booking train tickets. Covers app UI structure, station search behavior, booking flow, and common pitfalls. Uses the appium-android-adb bridge for all screen interaction — NEVER use raw ADB commands on 12306.

Install

openclaw skills install 12306-android-adb

12306 Train Booking

12306-specific knowledge, workflows, and pitfalls. For screen interaction, use the appium-android-adb skill (bridge_daemon.py).

🚨 Before Any 12306 Action

Start the Appium bridge (once per session):

bash ~/.openclaw/workspace/skills/appium-android-adb/start_bridge.sh

All screen interactions use python3 ~/.openclaw/workspace/skills/appium-android-adb/bridge_daemon.py <command>.

⚠ Never Use Raw ADB on 12306

The 12306 app uses UC WebView for the train list and booking pages. ADB input tap is IGNORED. Always use bridge_daemon.py from appium-android-adb.

12306 App Structure

PagePackage/ActivityHow to Detect
Homecom.MobileTicket / MainActivityticket_home_btn_search button exists
Train listcom.MobileTicket / H5Activitytitle contains <> (e.g. "上海 <> 苏州")
Bookingsame H5Activity"预订" buttons exist
Confirmationsame H5Activity"提交订单" button exists
Paymentsame H5Activity"立即支付" or "去支付" button

Key Element IDs (Home Page)

ElementResource ID
Search buttonticket_home_btn_search
Departure stationhome_page_train_dep1
Arrival stationhome_page_train_arr1
Date containerhome_page_depart_date_view_container

⚠ Station Search Behavior

Any station in a city searches ALL stations in that city. Example:

  • "上海虹桥→苏州" also shows trains from 上海站, 上海南站, 上海松江 etc.
  • "上海→苏州北" also shows trains to 苏州站, 苏州园区, 苏州新区 etc.

Once you have ANY valid city-to-city search result, NEVER go back to change stations. If the target train isn't immediately visible, just scroll — it's in the list.

Booking Flow

Step 1: Home page — ensure valid city pair + date

dump → check current stations and date
If stations show any valid city pair (e.g. "上海虹桥→苏州" or "上海→苏州北"):
  → SKIP station changes. All trains from both cities will appear.
If stations are completely wrong:
  → tap departure, pick ANY station in correct city
  → tap arrival, pick ANY station in correct city
tap date container → pick target date
tap "查询车票"

Step 2: Find and select train

dump → check trains[] for target train number
scroll down → dump → repeat until target appears
tap train by text (e.g. '{"text": "G7004"}')
→ train detail / booking page appears

Step 3: Book seat

dump → see seat options, look for "预订" buttons
tap '{"text": "预订", "index": 0}'  → first is usually 二等座

Step 4: Fingerprint (manual — tell user)

If alert with "指纹" appears: tell user to authenticate on phone. Wait, then dump to verify.

Step 5: Confirm and submit

dump → verify train, passenger, seat, price
If passenger not selected: tap "选择乘车人" → tap passenger name
tap "提交订单"

Step 6: Payment (user handles Alipay/WeChat)

dump → tap "立即支付" or "去支付"
→ User handles Alipay/WeChat login manually

Decision Tree

dump the screen:
  ├─ package != "com.MobileTicket" → app not in foreground, tap app icon or adb shell monkey
  ├─ "ticket_home_btn_search" in buttons → HOME PAGE
  │   → ensure valid city pair (any station!) + date → tap 查询车票
  ├─ title contains "<>" → TRAIN LIST
  │   → scroll + dump to find target train → tap it
  │   → NEVER go back to change stations — scroll instead
  ├─ "预订" in buttons → BOOKING PAGE
  │   → tap 预订 for seat type
  ├─ "提交订单" in buttons → CONFIRMATION
  │   → verify details → select passenger → submit
  ├─ "立即支付" in buttons → PAYMENT
  │   → tap to pay, user handles auth
  └─ alerts not empty → dismiss first, re-dump

Common Pitfalls

  • Going back to change stations: Don't. Any station in a city shows all trains. Just scroll.
  • Train at viewport edge (h=6): Scroll slightly to bring it into view, then tap.
  • Fingerprint dialog: Cannot automate. Tell user to authenticate.
  • Session timeout: The bridge daemon holds a persistent session — no timeout issues.
  • Wrong date on train list: The results page has date tabs at the top. Tap the correct date there directly.

Files

  • adb_helper.py — Low-level ADB helper (native element dump/find/tap/swipe). Use for pre-Appium checks or native-only pages.
  • SKILL.md — This file. 12306-specific knowledge.
  • README.md — Reference docs.