I、EDITORIAL
また、チケットの注文機能を実現し、私は、シミュレーションやチケットのお問い合わせを達成するためにログオンし、以前の12306匹の爬虫類サイトに書いたが、気持ちは十分ではありませんので、前のコードを変更します。
第二に、主なアイデア
アナログログイン12306サイトを行うにはセレンを使用する場合は成功したログインクッキー後に保存する必要があり、この背後にあるクッキーが必要です。それからちょうど要求が成功した後、我々はチケットを予約することができます、これらの要求を送信回し、ダース以上の要求が必要な予約を介して取得、解析、キャプチャするフィドラーソフトウェアを使用し、12306ウェブサイトの予約にチェックされています。
第三に、アナログログイン
コードは基本的に必要なクッキーを取得するための法律なので、コードの前に改善の必要性のログインをシミュレートする機能を実現しますが、していない前に。セレンモジュールはGET_COOKIES()メソッドを提供しますが、オープンセレンブラウザのCookie現在のページでクッキーの現在のセッションを、取得するには、このメソッドを使用している間、このクッキーとクッキー地元のブラウザが異なっています。残りのフィールドが生成されている間、以下では、記録する前にクエリ_jc_saveチケットの先頭にフィールドで地元クロム、からのCookieのコピーです。
JSESSIONID = A318817EEE594DE954CE352761DF4CD7。
_jc_save_fromStation =%u6B66%u6C49%2CWHN。
_jc_save_wfdc_flag = DC。
_jc_save_toStation =%u4E0A%u6D77%2CAOH。
RAIL_EXPIRATION = 1560095439082;
RAIL_DEVICEID = P2wunHEkKFe9MgTM56h-NxsWiIGNkK6JLCOVaG0DHzRm-RxYa7YnDwftPoumiZ0wL7GPsQ93YBHRHgMgB_GLWwZ9Vb65tNiVuwaIOytW8lVG7B1KopI4pSyUr1u06RWpKPhvExBg3FA7ed87WxO3E-68Wg-hXZLl。
_jc_save_fromDate = 2019年6月30日。
_jc_save_toDate = 2019年6月6日。
_jc_save_showIns =はtrue。
ルート= 495c805987d0f5c8c84b14f60212447d。
BIGipServerotn = 300941834.24610.0000。
BIGipServerpool_passport = 250413578.50215.0000
次はGET_COOKIESクッキー()の方法で得られたセレンを使用したモジュールであり、そしてあなたは、フィールドの多くが欠落している、ブラウザのクッキーは非常に異なっている見ることができます。
[{ 'ドメイン': 'kyfw.12306.cn'、 'HttpOnlyの' 偽 '名前': 'JSESSIONIDは'、 'パスは': '/ OTN'、 '安全な' 偽 '値': '672BAF8C694C50C49D3EFFCF9913A745' }、
{ 'ドメイン': 'kyfw.12306.cn'、 'HttpOnlyの' 偽 '名前': 'ルート'、 'パスは': '/'、 '安全な' 偽 '値': 'c5c62a339e7744272a54643b3be5bf64'}、
{ 'ドメイン': 'kyfw.12306.cn'、 'HttpOnlyの' 偽 '名前': 'BIGipServerotn'、 'パス': '/'、 '安全な' 偽 '値': '1139802634.24610.0000' }]
溶液は、ローカルブラウザの効果をシミュレートするために、セレンChromeで開くようにクッキー使用add_cookie()メソッドを追加することで、最終的に正常にログインすることができるであろう。ログインに成功した後、クッキーを取得するには、この時間は、GET_COOKIES()メソッドまたはGET_COOKIE()メソッドを除いて、あなたはまた、次のステートメントを使用することができます。
クッキー= browser.execute_script( "document.cookieを返します;")
しかし、それは成功したログインをしたかどうかを検証するために、あなたはそれが要求を送信する成功したログインコードを、以下の確認するためにいくつかのテストを実施する必要があり、要求がかどうか、ログイン情報の結果(すなわちis_login)とユーザー名などが含まれています情報:
1 DEF get_name(自己):
2 "" "
3 获取姓名用户
4 :リターン:
5 """
6 URL = " https://kyfw.12306.cn/otn/login/conf "
7つの RES = requests.post( URL、ヘッダー= self.headers)
8 is_login = res.json()' データ' ] [ ' is_login ' ]
9 なら is_login == ' Y ' :
10 self.name = res.json()' データ' ] [ "名" ]
11。 印刷(" ユーザーへようこそ:{} " .format(self.name))
12は、 他:
13は、 印刷(" 未登録ログインしてください!")
第四に、チケットを注文します
あなたがチケットを照会する前にそれをやったので、ので、ここでそれらを繰り返すありません。ここでは、次のページにジャンプします、最初の予約の旅行を選択する]をクリックし、サイト上で複数12306枚のチケットを確認し、そして、チケットクエリ操作の後に言います:
このページでは、乗客を選択座席の種類を選択し、注文を送信することができます。私たちは開発者ツールを使用して、袋をキャッチするページを更新しますが、要求の一部を逃し避けるためにすることができます。ここが、以下に示すように、私は12曲のリクエスト、URLと対応する意味を得るために練習した後、最終的な分析をフィドラーキャプチャソフトウェアを使用することにしました下記:
ここで私はすべての要求は再び、私が説明するには、いくつかの重要な要求を考え出すだろうと言うつもりはありません、ヘッダーには、これらの要求を使用したのと同じです、それは失敗につながる場合は、ログインクッキー、クッキーが含まれています予約に失敗しました。
1.初期ページ
第initDc要求は、この要求の結果に(下記参照)後リクエスト--token必要なパラメータが含まれ、比較的簡単な取得のプロセスは、正規表現に一致するように直接使用することができます。
次のようにトークン初期化コードのためのページです。
1 # 初始化,获取token值 2 def init_dc(): 3 global token 4 url = "https://kyfw.12306.cn/otn/confirmPassenger/initDc" 5 data = { 6 "_json_att": "" 7 } 8 res = requests.post(url, headers=headers, data=data) 9 result = re.findall(" var globalRepeatSubmitToken = '(.*?)';", res.text) 10 # print(result) 11 if len(result): 12 token = result[0] 13 else: 14 raise Exception("Error init")
2.提交车票预订信息
其次是提交车票预订信息,在Fiddler中点击Inspectors,然后选择WebForms,可以看到如下图所示信息,其中包含了出发城市、目的城市、出发日期等:
需要注意的是secretStr这个加密字符串,其来源于查询车票时的结果,在结果中每一条车次信息中都包含了一个字符串,不过这两个字符串并不完全一样。如下图所示就是两个字符串的对比,要得到加密字符串只需要使用unquote()方法:
3.确认订单信息
在选择完车次、座位类型、乘客之后会生成一个订单,然后就会发送一个确认订单信息的请求,其中包含了很多重要的信息。这里我放上该部分的代码:
1 # 确认订单信息
2 def check_order_info(name, uid, mobile, type_id):
3 # 商务座,一等座,二等座,软卧,硬卧,硬座
4 type_str = ["9,0,1,", "M,0,1,", "O,0,1,", "4,0,1,", "3,0,1,", "1,0,1,"][type_id]
5 url = "https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo"
6 data = {
7 "_json_att": "",
8 "bed_level_order_num": "000000000000000000000000000000",
9 "cancel_flag": "2",
10 "oldPassengerStr": name + ",1," + uid + ",1_",
11 "passengerTicketStr": type_str + name + ",1," + uid + "," + mobile + ",N",
12 "REPEAT_SUBMIT_TOKEN": token,
13 "randCode": "",
14 "tour_flag": "dc",
15 "whatsSelect": "1"
16 }
17 res = requests.post(url, headers=headers, data=data)
18 # print(res.text)
这个方法包含了四个参数,name、uid和mobile分别表示乘客的姓名、身份证号和电话号码,这三个值都是在获取乘客信息时得到的,第四个参数是座位类别id。在这个请求携带的参数中有一个REPEAT_SUBMIT_TOKEN,这就是前面说过的token,由于我已经将token设置为了全局变量,所以这里就不用作为参数传到方法里了。要注意的是每个座位类别对应的字符是不同的,我通过在页面上选择元素得到了每个座位类型对应的字符,最后生成一个列表,然后通过改变座位类别id就能完成选择座位类别的功能。
4.提交预订请求
在确认订单之后就是提交预订请求,还是在Fiddler软件中找到这个请求,然后查看其携带的参数,如下图所示:
其中包含了车次编码、出发站编码、目的站编码、token等信息,这些编码信息都可以在查询车票的结果中得到,需要注意的是train_date,可以看到这是一个日期信息,而且是一个格林威治标准时间,要得到这个时间可以使用如下方法,这就能将日期转变成格林威治标准时间:
train_date = datetime.datetime.strptime(train_date, "%Y-%m-%d").date()
this_date = train_date.strftime("%a+%b+%d+%Y")
5.检查提交状态
在提交预订请求之后,需要检查提交状态,这个请求包含了很多参数,其中一些参数的值都包含在提交预订请求的结果中,除此之外这些参数还有乘客姓名、身份证号、乘客电话、token等。这个请求返回的结果中有一个submitStatus,需要提取出来,该值表明了提交是否成功。该部分的代码如下所示:
1 # 检查提交状态
2 def confirm(key_check, left_ticket, passenger_name, passenger_id, passenger_mobile, location, type_id):
3 # 商务座,一等座,二等座,软卧,硬卧,硬座
4 type_str = ["9,0,1,", "M,0,1,", "O,0,1,", "4,0,1,", "3,0,1,", "1,0,1,"][type_id]
5 url = "https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue"
6 data = {
7 "choose_seats": "",
8 "dwAll": "N",
9 "key_check_isChange": key_check,
10 "leftTicketStr": left_ticket,
11 "oldPassengerStr": passenger_name + ",1," + passenger_id + ",1_",
12 "passengerTicketStr": type_str + passenger_name + ",1," + passenger_id + "," + passenger_mobile + ",N",
13 "purpose_codes": "00",
14 "randCode": "",
15 "REPEAT_SUBMIT_TOKEN": token,
16 "roomType": "00",
17 "seatDetailType": "000",
18 "train_location": location,
19 "whatsSelect": "1",
20 "_json_att": "", }
21 res = requests.post(url, headers=headers, data=data)
22 try:
23 js = json.loads(res.text)
24 status = js["data"]["submitStatus"]
25 # print(status)
26 return status
27 except Exception as e:
28 print(e)
29 raise Exception("Confirm Error!")
6.排队等待
当我们的订单提交成功之后,就需要排队等待了,此时会发送一个请求,该请求中携带了一个时间戳参数(random),如下图所示:
这是一个十三位的时间戳,在Python中可以使用 int(time() * 1000) 得到十三位时间戳。需要注意的是排队等待的结果是不确定的,正确的结果如下图所示:
其中有一个orderId,这个值是我们需要的。如果返回的结果中不包含orderId,就需要重新发送请求。
7.请求预订结果
在得到orderId之后,就可以请求预订结果了,请求无误的话就能够成功订到票了。下图是在Fiddler软件中截到的图,其中EF73361481就是前面得到的orderId:
五、运行结果
下图是在Pycharm中的运行截图,在登录成功之后查询余票,将查询的结果显示出来:
查询车票之后就是预订车票,需要输入车次名称、座位类别和选择乘客,然后提交订单,最终成功订到火车票。
订票成功之后,进入12306网站进行查看,可以看到成功订到票了, 如下图所示:
完整代码已上传到GitHub!如果觉得有用的话给我点个Star吧!