刷火车票的shell脚本

要用这个脚本得懂点shell和web开发。
window下面需要装cygwin才有shell环境。

用法:

  1. 先把脚本存下来,比如起名叫order.sh。

  2. 登陆网站,取得当前登陆的cookie,填到脚本里面,这个也可以用firebug取,登陆网站之后,验证码页面请求的header里面都能看到cookie那一行。

    cookie: JSESSIONID=6009B4610F436D8023126256FB598BDD; BIGipServerotsweb=2413035786.48160.0000
    
  3. 手动把里面的订票参数改掉。主要就是座位,日期,订票人,车次的信息。
    车次的信息需要从网页源码或者页面请求参数里面取。比如从查询页面点击预定按钮进入预定页面时,会向这个页面发POST请求

    https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=submutOrderRequest
    

    用firebug能看到这些参数

    train_no=240000K2670V
    station_train_code=K267
    from_station_telecode=BXP
    from_station_name="北京西"
    to_station_telecode=LEQ
    to_station_name="澧县"
    start_time="12:10"
    end_time="09:01"
    

    如果只订一个人的票,代码最下面还要把passenger_2相关的代码删掉

        -d "passengerTickets=$seat_type,1,$id_card_name2,$cardtype2,$id_card_no2,$mobile_phone2,Y" \
        -d "passenger_2_seat=$seat_type" \
        -d "passenger_2_ticket=1" \
        -d "passenger_2_name=$id_card_name2" \
        -d "passenger_2_cardtype=$cardtype2" \
        -d "passenger_2_cardno=$id_card_no2" \
        -d "passenger_2_mobileno=$mobile_phone2" \
    
  4. 从查询车次的页面随便搜一个车次,可以和你订票的车次没有任何关系,也不用同一天,只要能点预定按钮就行,然后点预定按钮进入预定页面。
    这是技术上的原因。不好多解释。这个步骤主要是影响到脚本里面向下面这个页面发请求获取token参数。

    https://dynamic.12306.cn/otsweb/order/confirmPassengerAction.do?method=init
    
  5. 改完之后,打开下面的页面刷一个验证码出来

    https://dynamic.12306.cn/otsweb/passCodeAction.do?rand=randp&1234567890

  6. 比如验证码是9527,那么就执行

    ./order.sh 9527

  7. 祈祷!

几个重要的点:

  1. 每次提交时发生变化的参数只有2个:

    • org.apache.struts.taglib.html.TOKEN 这个是每次生成页面表单的时候自动重新生成的,网站用它来防止用户重复提交订单。
    • randCode 验证码,神奇的是,如果不刷新验证码的页面,验证码可以反复使用。当然验证码是有有效期的,但是不知道多久,5分钟应该有吧。
  2. 上面提到的第4步很重要,一旦某次预定成功之后,重新再预定别的车次之前需要重复执行这一步。

shell脚本如下:

#!/bin/bash

######################
# 需要手工修改的参数 #
######################

# 硬座 1 , 硬卧 3, 软卧 4
seat_type=3

# 乘车日期
train_date="2012-01-20"

# 1, 二代身份证; 2, 一代身份证; C, 港澳通行证; G, 台湾通行证; B, 护照;
cardtype1=1
id_card_no1="xxxxxxxxxxxxxxxxxx"
id_card_name1="xxxx"
mobile_phone1="xxxxxxxxxxx"

cardtype2=1
id_card_no2="xxxxxxxxxxxxxxxxxx"
id_card_name2="xxx"
mobile_phone2="xxxxxxxxxxx"

# 用firebug 从 headers里面取
COOKIE="JSESSIONID=6009B4610F436D8023126256FB598BDD; BIGipServerotsweb=2413035786.48160.0000"

# 从查询页面点击预定按钮进入预定页面时,会向这个页面发POST请求
# https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=submutOrderRequest
# 用firebug能看到这些参数
train_no=240000K2670V
station_train_code=K267
from_station_telecode=BXP
from_station_name="北京西"
to_station_telecode=LEQ
to_station_name="澧县"
start_time="12:10"
end_time="09:01"

######################
######################

# A, 网上支付; B, 售票点自取, 看网页源码,有这个选项,但是网页上没有提供选择界面,所以不确定选项B能不能用
reserve_flag=A

FORM_HTML=form.html.tmp
RESULT_HTML=result.html.tmp

while true
do
    echo "==================="
    echo "Try to get token..."
    echo "==================="
    curl -k -b "$COOKIE" \
        "https://dynamic.12306.cn/otsweb/order/confirmPassengerAction.do?method=init" > $FORM_HTML

    TOKEN=$(grep "org.apache.struts.taglib.html.TOKEN" $FORM_HTML | sed -e 's/.*value="\(.*\)".*//')

    if test -z "$TOKEN"
    then
        #cat $FORM_HTML
        grep succde_fault.jpg $FORM_HTML
        echo "获取表单信息失败"
        echo "请确认cookie有效"
        echo "请确认通过车票查询页面点击预定进入预定页面并填写了相应的参数"
        continue
    fi

    if test -z "$1"
    then
        echo "请输入 https://dynamic.12306.cn/otsweb/passCodeAction.do?rand=randp&1234567890 验证码:"
        read randCode
    else
        randCode=$1
    fi

    echo "========="
    echo "submit..."
    echo "========="
    curl -k -b "$COOKIE" \
        -d "org.apache.struts.taglib.html.TOKEN=$TOKEN" \
        -d "randCode=$randCode" \
        -d "orderRequest.train_date=$train_date" \
        -d "orderRequest.train_no=$train_no" \
        -d "orderRequest.station_train_code=$station_train_code" \
        -d "orderRequest.from_station_telecode=$from_station_telecode" \
        -d "orderRequest.to_station_telecode=$to_station_telecode" \
        -d "orderRequest.seat_type_code=" \
        -d "orderRequest.ticket_type_order_num=" \
        -d "orderRequest.bed_level_order_num=000000000000000000000000000000" \
        -d "orderRequest.start_time=$start_time" \
        -d "orderRequest.end_time=$end_time" \
        -d "orderRequest.from_station_name=$from_station_name" \
        -d "orderRequest.to_station_name=$to_station_name" \
        -d "orderRequest.cancel_flag=1" \
        -d "orderRequest.id_mode=Y" \
        -d "orderRequest.reserve_flag=$reserve_flag" \
        -d "passengerTickets=$seat_type,1,$id_card_name1,$cardtype1,$id_card_no1,$mobile_phone1,Y" \
        -d "passenger_1_seat=$seat_type" \
        -d "passenger_1_ticket=1" \
        -d "passenger_1_name=$id_card_name1" \
        -d "passenger_1_cardtype=$cardtype1" \
        -d "passenger_1_cardno=$id_card_no1" \
        -d "passenger_1_mobileno=$mobile_phone1" \
        -d "passengerTickets=$seat_type,1,$id_card_name2,$cardtype2,$id_card_no2,$mobile_phone2,Y" \
        -d "passenger_2_seat=$seat_type" \
        -d "passenger_2_ticket=1" \
        -d "passenger_2_name=$id_card_name2" \
        -d "passenger_2_cardtype=$cardtype2" \
        -d "passenger_2_cardno=$id_card_no2" \
        -d "passenger_2_mobileno=$mobile_phone2" \
        "https://dynamic.12306.cn/otsweb/order/confirmPassengerAction.do?method=confirmPassengerInfoSingle" > $RESULT_HTML

    success=$(grep successTicketNum $RESULT_HTML)
    if test -z "$success"
    then
        #grep "succde_fault.jpg" $RESULT_HTML
        cat $RESULT_HTML
    else
        # 人品大爆发,赶紧去网页支付
        # 预定成功之后,有效期应该是50分钟,需要在50分钟之内支付完毕.
        echo "$success"
        exit 0
    fi

    # var message = "对不起,由于您取消次数过多,今日将不能继续受理您的订票请求。1 月9 日您可继续使用订票功能。";
done

Comments