转载自:http://www.360doc.com/content/13/0122/17/453497_261790962.shtml

我也记不清啥时候动了写bot刷票这个念头的。原因很简单,我一直认为作为一个以代码谋生的不合格程序员,只有把生产工具用好,才能增加自己存在的价值。

首先说明一下主要开发环境:Windows 7,PHP 5.3,php_curl。

翻到了 第一条关于刷票的微博,附了图

很不低调地炫耀。

要刷票,首先自然得熟悉目标系统,所谓踩点。firefox+firebug,抓了一个标准流程的请求:登录、查票、订票。确认订单一开始没敢点,怕会有什么影响,后来去注册了几个测试号,然后尝试了确认订单的操作。流程本身不复杂,但是提交参数有点太多,一步一步来。

回到图1,登录,其实核心在验证码。

1 验证码识别
登录的验证码处理起来很简单,图在 https://dynamic.12306.cn/otsweb/passCodeAction.do?rand=lrand,提供一个示例
这个验证码结构一直没变,字体比较规则,无变形,直接就想到了tesseract,上一次用这个的时候是2010年12月初为了刷顺丰快递的订单追踪。
流程很简单:
1 下载图片;
2 转tiff(使用了ImageMagick的convert);
3 tesseract识别;
4 读取识别文件;
5 简单判断识别输出是否合法;
6 拼登录请求。

代码里留了个 decaptcha_valid()的方法,不过只判断了是不是4位数字+字母。
写完第一版代码后,清理了一些个人信息,把代码发给了@也云,不过当时毕竟比较早,他没怎么看,但是后期验证码识别这块提供了一些改进,包括:
1 replace识别输出里的空字符,因为由于字符间距不确定,tesseract偶尔会识别出空格;
2 训练tesseract,优化识别效果;
3 这次tesseract用的是v3,已经支持多种图片格式,而我还是按上次使用的经验convert jpeg 2 tiff,这次直接省去这个过程;
4 最关键的,登录验证码在登录请求提交后并不会删除上次访问验证码图片生成的session字段,也就是说,只需要识别一次验证码,后续只需要暴力提交即可

按4调整了验证码识别方法,增加了人肉输入的支持。使用system(‘out.jpg’)直接利用Windows 7 CMD的高级功能,同时发现了Win7自带的图片查看器system执行后程序可以继续往下走而不必关掉图片查看器,这样可以alt+tab切换cmd和图片查看器,确认人肉识别的输入是否正确。

上述逻辑在1月19号之前也同样适用于确认订单的验证码,那天早起发现这块儿验证码需要每次请求了,幸好之前人肉识别的改造增加了配置开关,很轻松地就完成了改动(虽然19号刷票无一成功,但是20号回家客车上刷5张票轻松到手)。

2 查票
查票的过程其实没啥特别可以说的,简单拼个请求,查票就是了。不过返回值是需要处理的,处理的依据,从页面看,就是查票结果输出里的“预订”按钮。

预订的参数就是页面输出里的getSelected()这个js调用的参数,最初的结构我从另外一条微博里找到了例子。

正如页面上所示,结构是“车次号#历时(分钟单位)#发车时间#某个ID#始发站编号#目标站编号”,这个参数由页面解析后带入实际的预订请求。
不过后来某一天,这个参数变了,一个输出示例是“Z67#11:26#20:06#2400000Z6705#BXP#NCG#07:32#北京西#南昌#10175000003030800001404860000160895000001017503001”。同样按上边的解释,结构是“车次号#历时#发车时间#某个ID#始发站编号#目标站编号#到站时间#某个带入ypInfoDetail字段的参数”,@也云同学研究了一下最后这个字段,认定是“余票信息”的意思,对我们没有特别的意义,可无视(后续也证实了)。

这里可能有用的信息包括上述的“某个ID”。而查票的时候也需要输出里的始发站和目标站编号,这个编号可以从 这个地址里找到 。

3 订票 && 提交订单
订票使用了查票的输出参数,提交url是 https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=submutOrderRequest。明显有个Typo,而且这里名字是“提交订单”。不管那么多,说技术细节。

这个使用查票参数构造了一个POST请求,如果提交成功,服务器端会发一个302,重定向到一个新的页面 https://dynamic.12306.cn/otsweb/order/confirmPassengerAction.do?method=init。

流程很简单,curl实现只需要开 CURLOPT_FOLLOWLOCATION 即可。但是这个地方卡了我很久,直到12月初的某天才查出来为什么每次提交在这里总是出现 HTTP 500,虽然还是不知道原因,但是补上了几个http头,一切ok了(具体看代码)。

订票输出的页面,会有formtoken,参数名是 org.apache.struts.taglib.html.TOKEN。有点Web编程经验就应该能知道是干啥的。不多说,参数请求必须带上,所以正则匹配,无技术含量。
确认订单页只是拼参数,补上验证码识别就ok,无技术含量。

第一个细节,这个页面是填身份证的页面,入口有两个,订票 和 确认订单失败(后期确认订单失败不再直接回到该页面,不过验证码错误的应该还是会回来),所以确认订单的错误处理是可以考虑增加的。这个一开始代码就加上了,不过后来@也云改的lite版把这个流程改为 提交订单 + 确认订单,两步走,确认失败直接重订票。

第二个细节,验证码URL不一样了,https://dynamic.12306.cn/otsweb/passCodeAction.do?rand=randp,不过输出还是一样的。

第三个细节,最关键的,某个晚上睡前突然意识到的问题。回到form token上,我们可以观察到这个系统很多地方都会有form token,包括但不限于确认订单、支付订单、撤销订单等等。但是我意识到一个问题,提交订单这个过程可能会很慢,慢到一个不能忍的状态,尤其是高峰期。而,用户中心的表单里,也有form token,而且参数名完全一样,那么,这两个token会是同一个session字段吗?
接下来做的事情是改造form token的获取方法,改从用户中心的页面匹配,仅作测试。测试结果很乐观,从用户中心匹配到的token能作为确认订单token,而且这个请求自然会比从提交订单拿到的页面匹配要快,于是匹配token的方法可以优化了。(但是16号早上,订单系统似乎出问题了,各种慢,未支付订单页面刷不出来,支付订单也失败了,3张票扣了我1.3k RMB,没出票,极度想粗口!!!)

说到第三细节,如果你顺着读下来,可能会觉得有疑问:不是有很多参数要从页面匹配吗?如果不去拿提交订单后的页面,匹配变量,怎么确认订单?
答案是:你所需要的参数从你拿到查票输出的时候就已经足够了。你所需要的车次相关的信息,查票的输出已经能满足所有字段的需求;你所需要的订票人信息,以及所需坐席,你自己是已经知道了的。而,经过观察,查票输出里除了余票信息字段会变,其他的都不变!!!所以,你只需要在确定要刷票的前一天晚上,做一下准备工作,查查你要刷票的车次的信息,第二天拿着刷票便是了!!!
具体不多说,看代码便知。

到此,基本能说的都说了。

后边还有一些其他的细节优化。
支付
最初的支付表单是在一个独立的页面上,从未完成订单里选择订单,点支付,弹出的一个新页面匹配几个参数再submit,输出页面只有一个简单的form,body onload的时候触发了submit操作。也就是说,只需要拿下这个页面完成支付即可,这个最早@也云实验成功了,后来我有几次支付也用这个方法完成。过了几天,支付的表单在未完成订单点支付后的页面里直接写死了,于是新的lite版bot直接匹配了页面表单,存了个独立页面。
完后,弹出IE,支付。
本来想做招行的手机支付自动化的,后来实在懒了,自己订票的需求满足了,没心做这种优化。

登录
登录是件苦力活,经常就人满了,频率高了IP也会被封。所以登录成功一次得好好珍惜。
做法是: CURLOPT_COOKIEFILE + CURLOPT_COOKIEJAR。
脚本执行结束后,手工改 cookie jar文件,把expiration时间改长点。
但是由于经常性在登录完成后ctrl+c,没法触发__destruct()的调用,按@也云的建议,改成了登录完成后触发一次curl close操作并改expiration,执行结束后的继续保留。

源码
/bot.php
/config/test.php

执行参数 php bot.php 0 test 2>err.txt
只保证win下可用,soff改过一个mac下可用的版本,没找他要。
test 是 config/ 下的 test.php
0 是 test.php 里的tickets_info字段的索引,其实叫train_info更合适

然后为了骚扰自己,加了个vbs文件,内容很简单,取名messagebox.vbs,这段内容感谢@linxinsnow

' Message box Script
Set objArgs = WScript.Arguments
For I = 0 to objArgs.Count - 1
msgbox objArgs(I)
Next

写在最后
虽然我经常在微博XY,但是一直没公开源码。最终可用的代码也只有也云和soff拿到了。
一直不开源或者不发布的原因很简单,我不希望我的代码成为别人系统“有压力”的理由。我也看到了几个网上放出来的刷票工具或者js解决方案,但是,越多人知道这个,就意味着越多人会用你的“刀”“杀”铁道部。
或许我想的有点多。

感谢也云同学对本年度刷票的支持。感谢soff提供的验证码识别优化方案,虽然效果还不如我们的。

转载--12306刷票记相关推荐

  1. Selenium 实战:自写 12306 刷票脚本

    每逢过年就到了 12306 的抢票高峰期,作为一枚程序员,当然不能把时间和金钱浪费在刷票上啦.这里分享自写的 12306 刷票脚本,有兴趣的欢迎一起用技术解决生活难题. 本 Chat 主要贡献内容如下 ...

  2. 你距离家只差一个刷票脚本而已——12306刷票脚本升级版

    马上就要回家了,票还没有.你是否用到了我去年发布的刷票脚本呢.传送门~ 我也在刷票,不过发现12306还是发生了一些变化,在使用过程中,发现会自动退出登录.所以对脚本做了一些改动.顺便加了一些新的功能 ...

  3. 12306刷票插件作者一席话

    然后才是一点自动化,比如自动帮你点预定,自动帮你提交等等.自动刷新则完全是为了刷票量身打造,因为等待放票,或没抢到票时,你需要去反复地点,难道让所有人都这样反复点就公平了?那你为啥不让所有人都走路回家 ...

  4. 转载 书籍推荐-记这几年看的书

    这几年看了不少书,大部分是自掏腰包,看一本好书是享受,我很喜欢这种感觉. 这些是我这几年看书的一些心得,对于一些新手来说,可能有点帮助. 这几年一直在走技术路线,所以看的大部分都是技术方面的书籍,而且 ...

  5. python刷票脚本在哪_可以挂在服务器的 12306 刷票脚本

    只是在刷出票后发送提醒消息,并不能自动购票.在收到消息后还是得拼手速. 脚本用 Python3 实现,可挂到服务器上 24 小时刷. 前言 总体来说火车票应当是越来越好买,因此一直没怎么太操心.哪知道 ...

  6. [转载]jQuery诞生记-原理与机制

    by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=3520 一.看似偶然 ...

  7. 一段超实用的12306刷票脚本

    写在前面: 国庆要回家,车票买迟了,打开12306一看,我的乖乖,全部卖完了,于是想着等系统退票的软件,于是便催生了如下一个脚本,该脚本会在发现有余票的情况下打开选择用户的页面,很简单但是很实用--- ...

  8. 记一次生产环境脚本入侵检测与报警案例(检测特定目录被改动,自动报警)

    需求 : 特定目录,改动之后,自动报警. 转载来源 : 记一次生产环境脚本入侵检测与报警案例(简易版入侵检测系统) : http://www.safebase.cn/article-259102-1. ...

  9. 使用Python模拟登陆12306并全自动下单

    最近一段时间一直在研究用Python模拟登陆12306网站并自动刷票下单,经过一段时间的摸索,终于完成了代码,实现了12306刷票的功能.话不多说,先给大伙儿看看成果.我录制了一段时间,展示了自动刷票 ...

  10. 收集资料库 插件,生成器 等等

    1.语义正则表达式生成器 https://github.com/VerbalExpressions/RubyVerbalExpressions  https://github.com/VerbalEx ...

最新文章

  1. 利用Python进行数据分析 Note 1
  2. ARM汇编伪指令介绍(全集)
  3. 使用SAP云平台 + JNDI访问Internet Service
  4. 不用虚机不用Docker使用Azure应用服务部署ASP.NET Core程序
  5. java二进制 字节数组 字符 十六进制 BCD编码转换
  6. 2020年研究生入学考试991考试大纲
  7. 专访肖仰华:知识图谱迅速“升温”下的学习方法与就业选择
  8. WCF系列教程之客户端异步调用服务
  9. PLC模糊控制之模糊化
  10. 计算机微软云同步怎样安装软件,云骑士Win10微软账户设置同步的方法
  11. win8 上如何真正禁用UAC
  12. php excel 保护工作表,PHPExcel 指定列表锁定受保护加密不可更改方法
  13. 用Changedetection监控网页的变化
  14. 解密阿里云IoT物联网平台MQTT Access Server核心架构
  15. 实时日志/数据库采集处理,实时用户行为属性个人总结
  16. word中插入手写的电子签名
  17. 手机充电总要充到100%吗?充电时先插手机还是充电器
  18. 显卡的GTX和RTX的实际意义在哪里?究竟该怎么选?
  19. python操作ipv6_python ipv6计算SQLAlchemy复杂查询
  20. 2022 199管综真题及答案解析

热门文章

  1. 根据经纬度获取地址(逆地址解析)
  2. 软件测试员的日常逗逼瞬间
  3. 按键精灵-自动化脚本
  4. 汉武帝不仅需要建功立业的董仲舒、汲黯、卫青,也需要能让他整天快乐的东方朔...
  5. mysql显示1146_MySQL查询报错:ERROR 1146 (42S02): Table 'craw.sitePageConfig' doesn't exist
  6. [统计学理论基础] 置信区间
  7. 【调色台】达芬奇调色台系列
  8. Maxima 的基本微积分操作
  9. 《谷歌大数据经典论文读后感》
  10. vuecli打包后html文件没有压缩的问题