mirror of https://github.com/testerSunshine/12306
parent
009b989a64
commit
6b849c1201
|
@ -2,10 +2,11 @@
|
|||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 2.7.10 (/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7)" jdkType="Python SDK" />
|
||||
<orderEntry type="jdk" jdkName="Python 2.7 (qt12306)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||
<option name="projectConfiguration" value="Nosetests" />
|
||||
<option name="PROJECT_TEST_RUNNER" value="Nosetests" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 2.7.10 (/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectCodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value>
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
|
||||
<MarkdownNavigatorCodeStyleSettings>
|
||||
<option name="RIGHT_MARGIN" value="72" />
|
||||
</MarkdownNavigatorCodeStyleSettings>
|
||||
</value>
|
||||
</option>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,3 +0,0 @@
|
|||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="wenxianping" />
|
||||
</component>
|
|
@ -1,10 +1,49 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="LongLine" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ProblematicWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SSBasedInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TodoComment" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="11">
|
||||
<item index="0" class="java.lang.String" itemvalue="nose" />
|
||||
<item index="1" class="java.lang.String" itemvalue="locust" />
|
||||
<item index="2" class="java.lang.String" itemvalue="selenium" />
|
||||
<item index="3" class="java.lang.String" itemvalue="locustio" />
|
||||
<item index="4" class="java.lang.String" itemvalue="pymssql" />
|
||||
<item index="5" class="java.lang.String" itemvalue="python-hessian" />
|
||||
<item index="6" class="java.lang.String" itemvalue="suds" />
|
||||
<item index="7" class="java.lang.String" itemvalue="DBUtils" />
|
||||
<item index="8" class="java.lang.String" itemvalue="MySQL-python" />
|
||||
<item index="9" class="java.lang.String" itemvalue="redis" />
|
||||
<item index="10" class="java.lang.String" itemvalue="redis_py_cluster" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="E501" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N801" />
|
||||
<option value="N803" />
|
||||
<option value="N806" />
|
||||
<option value="N802" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
<option value="list.__setitem__" />
|
||||
<option value="dict.json" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
|
@ -1,7 +0,0 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="useProjectProfile" value="false" />
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
|
@ -1,4 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.10 (/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7)" project-jdk-type="Python SDK" />
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7 (qt12306)" project-jdk-type="Python SDK" />
|
||||
</project>
|
1810
.idea/workspace.xml
1810
.idea/workspace.xml
File diff suppressed because it is too large
Load Diff
166
README.md
166
README.md
|
@ -1,60 +1,16 @@
|
|||
### 12306
|
||||
#### 12306 购票小助手
|
||||
|
||||
- python版本支持
|
||||
- 2.7
|
||||
- 2.7.10 - 2.7.15
|
||||
- 依赖库
|
||||
- 依赖打码兔 需要去打码兔注册(用户)账号,打码兔账号地址:http://www.dama2.com, 一般充值1元就够用了,充值打码兔之后,首次运行是需要到官网黑白名单授权
|
||||
- 依赖若快 若快注册地址:http://www.ruokuai.com/client/index?6726 推荐用若快,打码兔在12306验证码更新之后识别率不是很高
|
||||
- 依赖若快 若快注册地址:http://www.ruokuai.com/client/index?6726 推荐用若快,打码兔平台已经关闭
|
||||
- 项目依赖包 requirements.txt
|
||||
- 安装方法 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
|
||||
|
||||
- 项目使用说明
|
||||
- 需要配置邮箱,可以配置可以不配置,配置邮箱的格式在yaml里面可以看到ex
|
||||
- 提交订单验证码哪里依赖打码兔,所以如果是订票遇到验证码的时候,没有打码兔是过不了的,不推荐手动,手动太慢
|
||||
- 配置yaml文件的时候,需注意空格和遵循yaml语法格式,项目的yaml配置ex:
|
||||
- ticket_config.yaml 配置说明
|
||||
```
|
||||
#station_date:出发日期改为多日期查询,格式ex:
|
||||
- "2018-02-03"
|
||||
- "2018-02-04"
|
||||
- "2018-02-05"
|
||||
#station_trains:过滤车次,格式ex:
|
||||
# - "G1353"
|
||||
# - "G1329"
|
||||
# - "G1355"
|
||||
# - "G1303"
|
||||
# - "G1357"
|
||||
# - "G1305"
|
||||
# - "G1359"
|
||||
# - "G1361"
|
||||
# - "G1373"
|
||||
# - "G1363"
|
||||
#from_station: 始发站
|
||||
#to_station: 到达站
|
||||
#set_type: 坐席(商务座,二等座,特等座,软卧,硬卧,硬座,无座)
|
||||
#is_more_ticket:余票不足是否自动提交
|
||||
#select_refresh_interval:抢票刷新间隔时间,1为一秒,0.1为100毫秒,以此类推 如果捡漏推荐为1秒,刷票设置0.01
|
||||
#expect_refresh_interval:售票未开始,等待刷新间隔时间,1为一秒,0.1为100毫秒,以此类推
|
||||
#ticket_black_list:加入小黑屋的等待时间,默认3 min 小黑屋的功能是上次买票失败,证明此票已无机会,下次刷新看到此票跳过
|
||||
#enable_proxy:是否开启代理模式,代理速度比较慢,如果是抢票阶段,不建议开启
|
||||
#ticke_peoples: 乘客 ex: "张三"
|
||||
#damatu:打码兔账号,用于自动登录和订单自动打码
|
||||
#is_aotu_code是否自动打码,如果选择Ture,则调用打码兔打码,默认不使用打码兔
|
||||
#is_email: 是否需要邮件通知 ex: True or False 切记,邮箱加完一定到config目录下测试emailConf功能是否正常
|
||||
|
||||
#邮箱配置 列举163
|
||||
# email: "xxx@163.com"
|
||||
# notice_email_list: "123@qq.com"
|
||||
# username: "xxxxx"
|
||||
# password: "xxxxx
|
||||
# host: "smtp.163.com"
|
||||
#邮箱配置 列举qq ,qq设置比较复杂,需要在邮箱--账户--开启smtp服务,取得授权码==邮箱登录密码
|
||||
# email: "xxx@qq.com"
|
||||
# notice_email_list: "123@qq.com"
|
||||
# username: "xxxxx"
|
||||
# password: "授权码"
|
||||
# host: "smtp.qq.com"
|
||||
```
|
||||
- 配置yaml文件的时候,需注意空格和遵循yaml语法格式
|
||||
|
||||
- 项目开始
|
||||
- 修改config/ticket_config.yaml文件,按照提示更改自己想要的信息
|
||||
|
@ -94,118 +50,6 @@
|
|||
恭喜您订票成功,订单号为:EB52743573, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!
|
||||
```
|
||||
|
||||
- 2017.5.13跟新
|
||||
- 增加登陆错误判断(密码错误&ip校验)
|
||||
- 修改queryOrderWaitTime,校验orderId字段bug,校验msg字段bug,校验messagesbug
|
||||
- 修改checkQueueOrder 校验 data 字段的列表推导式bug
|
||||
- 增加代理ip方法,目前已可以过滤有用ip
|
||||
|
||||
|
||||
- 2018.1.7 号更新
|
||||
- 增加自动配置
|
||||
```
|
||||
#station_date:出发日期,格式ex:2018-01-06
|
||||
#from_station: 始发站
|
||||
#to_station: 到达站
|
||||
#set_type: 坐席(商务座,二等座,特等座,软卧,硬卧,硬座,无座)
|
||||
#is_more_ticket:余票不足是否自动提交
|
||||
#select_refresh_interval:刷新间隔时间,1为一秒,0.1为100毫秒,以此类推
|
||||
#ticke_peoples: 乘客
|
||||
#damatu:打码图账号,用于自动登录
|
||||
```
|
||||
- 优化订票流程
|
||||
- 支持自动刷票,自动订票
|
||||
|
||||
- 2018.1.8 更新
|
||||
- 增加小黑屋功能
|
||||
- 修复bug若干
|
||||
- 增加多账号同时订票功能
|
||||
- 增加按照选定车次筛选购买车次
|
||||
|
||||
- 2018.1.9 更新
|
||||
|
||||
- 增加手动打码,只是登录接口,完全不用担心提交票的效率问题,要挂linux系统的话,还是去注册个打码兔吧
|
||||
```
|
||||
思路
|
||||
1.调用PIL显示图片
|
||||
2.图片位置说明,验证码图片中每个图片代表一个下标,依次类推,1,2,3,4,5,6,7,8
|
||||
3.控制台输入对应下标,按照英文逗号分开,即可手动完成打码,
|
||||
```
|
||||
- 修改无座和硬座的座位号提交是个字符串的问题
|
||||
- 增加校验下单需要验证码功能
|
||||
- 增强下单成功判断接口校验
|
||||
|
||||
- 2018.1.10 更新
|
||||
- 优化查票流程
|
||||
- 修改二等座的余票数返回为字符串的问题
|
||||
- 优化订单查询bug
|
||||
- 2018.1.12更新
|
||||
- 优化抢票页面逻辑
|
||||
-增强代码稳定性
|
||||
|
||||
- 2018.1.13更新
|
||||
- 修改下单验证码功能
|
||||
- 优化大量调用user接口导致联系人不能用,理论加快订票速度
|
||||
- 增加邮箱功能
|
||||
```
|
||||
#is_email: 是否需要邮件通知 ex: True or False 切记,邮箱加完一定要到config目录下测试emailConf功能是否正常
|
||||
#email: 发送的邮箱地址 ex: 1@qq.com
|
||||
#notice_email_list: 被通知人邮箱 ex: 2@qq.com
|
||||
#username: 邮箱账号
|
||||
#password: 邮箱密码
|
||||
#host: 邮箱地址
|
||||
```
|
||||
|
||||
- 2018.1.14更新
|
||||
- 优化订票流程
|
||||
- 优化挂机功能
|
||||
- 修改之前程序到11点自动跳出功能,现在修改为到早上7点自动开启刷票
|
||||
- 需要开启打码兔代码功能,is_aotu_code 设置为True
|
||||
- 增加异常判断
|
||||
|
||||
- 2018.1.15更新
|
||||
- 增加捡漏自动检测是否登录功能,建议捡漏不要刷新太快,2S最好,否则会封IP
|
||||
- 优化提交订单有很大记录无限排队的情况,感谢群里的小伙伴提供的思路
|
||||
- 修改休眠时间为早上6点
|
||||
|
||||
- 2018.1.20更新,好久没跟新了,群里的小伙伴说登录不行了,今晚抽空改了一版登录,妥妥的
|
||||
- 更新新版登录功能,经测试,更稳定有高效
|
||||
- 优化手动打码功能
|
||||
- 更新请求第三方库
|
||||
- 优化若干代码,小伙伴尽情的放肆起来
|
||||
|
||||
- 2018.1.21跟新
|
||||
- 修复若干bug
|
||||
- 合并dev
|
||||
- 恢复之前因为12306改版引起的订票功能
|
||||
- 增加派对失败自动取消订单功能
|
||||
- 优化接口请求规范
|
||||
- 增加多日期查询,请严格按照yaml格式添加 即可
|
||||
- 注意:如果多日期查询的话,可能查询时间会比较长
|
||||
- 增加如果排队时间超过一分钟,自动取消订单
|
||||
|
||||
- 2018.1.23更新
|
||||
- 增加若快平台打码,yaml新增字段aotu_code_type,1=打码兔,2=若快 若快注册地址:http://www.ruokuai.com/client/index?6726
|
||||
- 修改is_aotu_code字段为全部是否自动打码字段,也就是说字段为rue,则全部自动打码,为False全部手动打码,包括提交订单,注意centOs不可设置手动打码
|
||||
- 修复bug
|
||||
- 优化抢票功能
|
||||
|
||||
- 2018.1.25更新
|
||||
- 删除 expect_refresh_interval 无用字段,优化代码
|
||||
|
||||
- 2018.1.29更新
|
||||
- 增加cdn轮训功能,优势, is_cdn=1为开启cdn,2为普通查询
|
||||
- 能够一定程度躲避封ip
|
||||
- 查询余票快人一步
|
||||
- 提交订单快人一步
|
||||
- 僵尸票可能会少很多
|
||||
- 兼容Windows cmd命令乱码问题
|
||||
- 规范12306接口提交参数
|
||||
- 修改已知bug
|
||||
- 最后感谢群里提供测试和代码的小伙伴,能为你们买到一张回家的票真的感到灰常开心
|
||||
|
||||
- 2018.2.28更新,收12306风控影响,代码可能有时候会进入慢排队,请自行调整刷新参数
|
||||
- 修改已知bug
|
||||
- 优化接口提交参数规范
|
||||
- [更新日志](Update.md)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
- 2017.5.13跟新
|
||||
- 增加登陆错误判断(密码错误&ip校验)
|
||||
- 修改queryOrderWaitTime,校验orderId字段bug,校验msg字段bug,校验messagesbug
|
||||
- 修改checkQueueOrder 校验 data 字段的列表推导式bug
|
||||
- 增加代理ip方法,目前已可以过滤有用ip
|
||||
|
||||
|
||||
- 2018.1.7 号更新
|
||||
- 增加自动配置
|
||||
```
|
||||
#station_date:出发日期,格式ex:2018-01-06
|
||||
#from_station: 始发站
|
||||
#to_station: 到达站
|
||||
#set_type: 坐席(商务座,二等座,特等座,软卧,硬卧,硬座,无座)
|
||||
#is_more_ticket:余票不足是否自动提交
|
||||
#select_refresh_interval:刷新间隔时间,1为一秒,0.1为100毫秒,以此类推
|
||||
#ticke_peoples: 乘客
|
||||
#damatu:打码图账号,用于自动登录
|
||||
```
|
||||
- 优化订票流程
|
||||
- 支持自动刷票,自动订票
|
||||
|
||||
- 2018.1.8 更新
|
||||
- 增加小黑屋功能
|
||||
- 修复bug若干
|
||||
- 增加多账号同时订票功能
|
||||
- 增加按照选定车次筛选购买车次
|
||||
|
||||
- 2018.1.9 更新
|
||||
|
||||
- 增加手动打码,只是登录接口,完全不用担心提交票的效率问题,要挂linux系统的话,还是去注册个打码兔吧
|
||||
```
|
||||
思路
|
||||
1.调用PIL显示图片
|
||||
2.图片位置说明,验证码图片中每个图片代表一个下标,依次类推,1,2,3,4,5,6,7,8
|
||||
3.控制台输入对应下标,按照英文逗号分开,即可手动完成打码,
|
||||
```
|
||||
- 修改无座和硬座的座位号提交是个字符串的问题
|
||||
- 增加校验下单需要验证码功能
|
||||
- 增强下单成功判断接口校验
|
||||
|
||||
- 2018.1.10 更新
|
||||
- 优化查票流程
|
||||
- 修改二等座的余票数返回为字符串的问题
|
||||
- 优化订单查询bug
|
||||
- 2018.1.12更新
|
||||
- 优化抢票页面逻辑
|
||||
-增强代码稳定性
|
||||
|
||||
- 2018.1.13更新
|
||||
- 修改下单验证码功能
|
||||
- 优化大量调用user接口导致联系人不能用,理论加快订票速度
|
||||
- 增加邮箱功能
|
||||
```
|
||||
#is_email: 是否需要邮件通知 ex: True or False 切记,邮箱加完一定要到config目录下测试emailConf功能是否正常
|
||||
#email: 发送的邮箱地址 ex: 1@qq.com
|
||||
#notice_email_list: 被通知人邮箱 ex: 2@qq.com
|
||||
#username: 邮箱账号
|
||||
#password: 邮箱密码
|
||||
#host: 邮箱地址
|
||||
```
|
||||
|
||||
- 2018.1.14更新
|
||||
- 优化订票流程
|
||||
- 优化挂机功能
|
||||
- 修改之前程序到11点自动跳出功能,现在修改为到早上7点自动开启刷票
|
||||
- 需要开启打码兔代码功能,is_auto_code 设置为True
|
||||
- 增加异常判断
|
||||
|
||||
- 2018.1.15更新
|
||||
- 增加捡漏自动检测是否登录功能,建议捡漏不要刷新太快,2S最好,否则会封IP
|
||||
- 优化提交订单有很大记录无限排队的情况,感谢群里的小伙伴提供的思路
|
||||
- 修改休眠时间为早上6点
|
||||
|
||||
- 2018.1.20更新,好久没跟新了,群里的小伙伴说登录不行了,今晚抽空改了一版登录,妥妥的
|
||||
- 更新新版登录功能,经测试,更稳定有高效
|
||||
- 优化手动打码功能
|
||||
- 更新请求第三方库
|
||||
- 优化若干代码,小伙伴尽情的放肆起来
|
||||
|
||||
- 2018.1.21跟新
|
||||
- 修复若干bug
|
||||
- 合并dev
|
||||
- 恢复之前因为12306改版引起的订票功能
|
||||
- 增加派对失败自动取消订单功能
|
||||
- 优化接口请求规范
|
||||
- 增加多日期查询,请严格按照yaml格式添加 即可
|
||||
- 注意:如果多日期查询的话,可能查询时间会比较长
|
||||
- 增加如果排队时间超过一分钟,自动取消订单
|
||||
|
||||
- 2018.1.23更新
|
||||
- 增加若快平台打码,yaml新增字段auto_code_type,1=打码兔,2=若快 若快注册地址:http://www.ruokuai.com/client/index?6726
|
||||
- 修改is_auto_code字段为全部是否自动打码字段,也就是说字段为rue,则全部自动打码,为False全部手动打码,包括提交订单,注意centOs不可设置手动打码
|
||||
- 修复bug
|
||||
- 优化抢票功能
|
||||
|
||||
- 2018.1.25更新
|
||||
- 删除 expect_refresh_interval 无用字段,优化代码
|
||||
|
||||
- 2018.1.29更新
|
||||
- 增加cdn轮训功能,优势, is_cdn=1为开启cdn,2为普通查询
|
||||
- 能够一定程度躲避封ip
|
||||
- 查询余票快人一步
|
||||
- 提交订单快人一步
|
||||
- 僵尸票可能会少很多
|
||||
- 兼容Windows cmd命令乱码问题
|
||||
- 规范12306接口提交参数
|
||||
- 修改已知bug
|
||||
- 最后感谢群里提供测试和代码的小伙伴,能为你们买到一张回家的票真的感到灰常开心
|
||||
|
||||
- 2018.2.28更新,收12306风控影响,代码可能有时候会进入慢排队,请自行调整刷新参数
|
||||
- 修改已知bug
|
||||
- 优化接口提交参数规范
|
||||
|
||||
- 2018.8.29更新,解决慢排队问题,增加双订票接口
|
||||
- 修改已知bug
|
||||
- 优化代码结构
|
||||
- 新增第三方库wrapcache,需要重新安装requirements.txt
|
|
@ -33,3 +33,8 @@ class ticket(object):
|
|||
CANCEL_ORDER_SUCCESS = u"排队超时,已为您自动取消订单,订单编号: {0}"
|
||||
CANCEL_ORDER_FAIL = u"排队超时,取消订单失败, 订单号{0}"
|
||||
|
||||
REST_TIME = u"12306休息时间,本程序自动停止,明天早上6点将自动运行"
|
||||
REST_TIME_PAST = u"休息时间已过,重新开启检票功能"
|
||||
|
||||
LOGIN_SESSION_FAIL = u"用户检查失败:{0},可能未登录,可能session已经失效, 正在重新登录中"
|
||||
|
||||
|
|
|
@ -13,19 +13,4 @@ def _get_yaml():
|
|||
f = open(path)
|
||||
s = yaml.load(f)
|
||||
f.close()
|
||||
return s
|
||||
|
||||
|
||||
# def get_set_info():
|
||||
# return _get_yaml()["set"]
|
||||
#
|
||||
#
|
||||
# def get_ticke_peoples():
|
||||
# return _get_yaml()["ticke_peoples"]
|
||||
#
|
||||
#
|
||||
# def get_damatu():
|
||||
# return _get_yaml()["damatu"]
|
||||
#
|
||||
#
|
||||
# print _get_yaml()["set"]["12306count"]
|
||||
return s
|
|
@ -1,78 +1,63 @@
|
|||
---
|
||||
#station_date:出发日期,格式ex:2018-01-06
|
||||
#station_trains:过滤车次,格式ex:
|
||||
# - "G1353"
|
||||
# - "G1329"
|
||||
# - "G1355"
|
||||
# - "G1303"
|
||||
# - "G1357"
|
||||
# - "G1305"
|
||||
# - "G1359"
|
||||
# - "G1361"
|
||||
# - "G1373"
|
||||
# - "G1363"
|
||||
#from_station: 始发站
|
||||
#to_station: 到达站
|
||||
#set_type: 坐席(商务座,二等座,特等座,软卧,硬卧,硬座,无座)
|
||||
#is_more_ticket:余票不足是否自动提交
|
||||
#select_refresh_interval:抢票刷新间隔时间,1为一秒,0.1为100毫秒,以此类推 如果捡漏推荐为1秒,刷票设置0.01
|
||||
#expect_refresh_interval:售票未开始,等待刷新间隔时间,1为一秒,0.1为100毫秒,以此类推
|
||||
#ticket_black_list:加入小黑屋的等待时间,默认3 min
|
||||
#enable_proxy:是否开启代理模式,代理速度比较慢,如果是抢票阶段,不建议开启
|
||||
#ticke_peoples: 乘客
|
||||
#damatu:打码兔账号,用于自动登录
|
||||
#is_aotu_code是否自动打码,如果选择Ture,则调用打码兔打码,默认不使用打码兔
|
||||
#aotu_code_type 1为打码兔,2为若快
|
||||
#is_email: 是否需要邮件通知 ex: True or False 切记,邮箱加完一定到config目录下测试emailConf功能是否正常
|
||||
set:
|
||||
# 出发日期,格式ex:2018-01-06
|
||||
station_dates:
|
||||
- "2018-09-05"
|
||||
|
||||
#邮箱配置 列举163
|
||||
# 过滤车次,格式ex:- "G1353" - "G1329"
|
||||
station_trains:
|
||||
- "G6504"
|
||||
|
||||
# 出发城市,比如深圳北,就填深圳就搜得到
|
||||
from_station: "深圳"
|
||||
|
||||
# 到达城市 比如深圳北,就填深圳就搜得到
|
||||
to_station: "广州"
|
||||
|
||||
# 座位 多个座位ex: - "二等座" - "一等座"
|
||||
set_type:
|
||||
- "二等座"
|
||||
|
||||
# 余票不足是否自动提交,目前应该没什么卵用
|
||||
is_more_ticket: True
|
||||
|
||||
# 乘车人 多个乘车人ex: - "张三" - "李四"
|
||||
ticke_peoples:
|
||||
- ""
|
||||
# 12306登录账号
|
||||
12306account:
|
||||
- uesr: ""
|
||||
- pwd: ""
|
||||
|
||||
select_refresh_interval: 1
|
||||
|
||||
# 加入小黑屋时间,此功能为了防止僵尸票导致一直下单不成功错过正常的票
|
||||
ticket_black_list_time: 5
|
||||
|
||||
# 自动打码
|
||||
is_auto_code: False
|
||||
|
||||
# 打码平台, 2 为若快平台(目前只支持若快平台打码,打码兔已经关闭), 若快注册地址:http://www.ruokuai.com/client/index?6726
|
||||
auto_code_type: 2
|
||||
|
||||
# 打码平台账号
|
||||
auto_code_account:
|
||||
uesr: ""
|
||||
pwd: ""
|
||||
|
||||
# 邮箱配置,如果抢票成功,将通过邮件配置通知给您
|
||||
# 列举163
|
||||
# email: "xxx@163.com"
|
||||
# notice_email_list: "123@qq.com"
|
||||
# username: "xxxxx"
|
||||
# password: "xxxxx
|
||||
# host: "smtp.163.com"
|
||||
#邮箱配置 列举qq ,qq设置比较复杂,需要在邮箱--账户--开启smtp服务,取得授权码==邮箱登录密码
|
||||
# 列举qq ,qq设置比较复杂,需要在邮箱-->账户-->开启smtp服务,取得授权码==邮箱登录密码
|
||||
# email: "xxx@qq.com"
|
||||
# notice_email_list: "123@qq.com"
|
||||
# username: "xxxxx"
|
||||
# password: "授权码"
|
||||
# host: "smtp.qq.com"
|
||||
|
||||
|
||||
set:
|
||||
station_dates:
|
||||
- "2018-06-21"
|
||||
- "2018-06-22"
|
||||
|
||||
station_trains:
|
||||
- "G1321"
|
||||
|
||||
from_station: "上海"
|
||||
to_station: "长沙"
|
||||
set_type:
|
||||
- "二等座"
|
||||
- "商务座"
|
||||
- "一等座"
|
||||
is_more_ticket: True
|
||||
ticke_peoples:
|
||||
- "文贤平"
|
||||
# - "彭淑杰"
|
||||
12306count:
|
||||
# - uesr: ""
|
||||
# - pwd: "apple1995"
|
||||
- uesr: "931128603@qq.com"
|
||||
- pwd: "QWERTY"
|
||||
|
||||
select_refresh_interval: 1
|
||||
ticket_black_list_time: 5
|
||||
is_aotu_code: False
|
||||
aotu_code_type: 2
|
||||
#enable_proxy: False
|
||||
|
||||
damatu:
|
||||
uesr: ""
|
||||
pwd: "qazWSX1995"
|
||||
|
||||
email_conf:
|
||||
is_email: True
|
||||
email: "@qq.com "
|
||||
|
@ -81,8 +66,11 @@ email_conf:
|
|||
password: ""
|
||||
host: "smtp.qq.com"
|
||||
|
||||
# 是否开启cdn查询,可以更快的检测飘飘 1为开启,2为关闭
|
||||
is_cdn: 2
|
||||
|
||||
# 下单接口分为两种,1 为快速下单,2 是普通下单
|
||||
order_type: 1
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ urls = {
|
|||
"req_type": "get",
|
||||
"Referer": "https://kyfw.12306.cn/otn/index/init",
|
||||
"Host": "kyfw.12306.cn",
|
||||
"re_try": 10,
|
||||
"re_try": 1,
|
||||
"re_time": 0.1,
|
||||
"s_time": 0.1,
|
||||
"is_logger": False,
|
||||
|
@ -157,7 +157,7 @@ urls = {
|
|||
},
|
||||
"select_url": { # 查询余票
|
||||
"req_url": "/otn/leftTicket/query?leftTicketDTO.train_date={0}&leftTicketDTO.from_station={1}&leftTicketDTO.to_station={2}&purpose_codes=ADULT",
|
||||
"req_type": "post",
|
||||
"req_type": "get",
|
||||
"Referer": "https://kyfw.12306.cn/otn/leftTicket/init",
|
||||
"Host": "kyfw.12306.cn",
|
||||
"re_try": 10,
|
||||
|
|
|
@ -1,292 +0,0 @@
|
|||
# -*- coding=utf-8 -*-
|
||||
import datetime
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import urllib
|
||||
from collections import OrderedDict
|
||||
|
||||
import collections
|
||||
|
||||
from agency.cdn_utils import CDNProxy
|
||||
from config import urlConf
|
||||
from config.TicketEnmu import ticket
|
||||
from config.emailConf import sendEmail
|
||||
from config.ticketConf import _get_yaml
|
||||
from init import login
|
||||
from init.login import GoLogin
|
||||
from inter.AutoSubmitOrderRequest import autoSubmitOrderRequest
|
||||
from inter.ConfirmSingleForQueueAsys import confirmSingleForQueueAsys
|
||||
from inter.GetPassengerDTOs import getPassengerDTOs
|
||||
from inter.GetQueueCountAsync import getQueueCountAsync
|
||||
from inter.LiftTicketInit import liftTicketInit
|
||||
from inter.Query import query
|
||||
from inter.QueryOrderWaitTime import queryOrderWaitTime
|
||||
from myException.PassengerUserException import PassengerUserException
|
||||
from myException.UserPasswordException import UserPasswordException
|
||||
from myException.ticketConfigException import ticketConfigException
|
||||
from myException.ticketIsExitsException import ticketIsExitsException
|
||||
from myException.ticketNumOutException import ticketNumOutException
|
||||
from myUrllib.httpUtils import HTTPClient
|
||||
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
|
||||
|
||||
class selectFast:
|
||||
"""
|
||||
快速提交车票通道
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, self.ticke_peoples, self.select_refresh_interval, self.station_trains, self.ticket_black_list_time = self.get_ticket_info()
|
||||
self.is_aotu_code = _get_yaml()["is_aotu_code"]
|
||||
self.aotu_code_type = _get_yaml()["aotu_code_type"]
|
||||
self.is_cdn = _get_yaml()["is_cdn"]
|
||||
self.httpClint = HTTPClient()
|
||||
self.urls = urlConf.urls
|
||||
self.login = GoLogin(self.httpClint, self.urls, self.is_aotu_code, self.aotu_code_type)
|
||||
self.is_download_img = False
|
||||
self.cdn_list = []
|
||||
self.is_check_user = dict()
|
||||
self.ticket_black_list = dict()
|
||||
self.passengerTicketStrList = ""
|
||||
self.oldPassengerStr = ""
|
||||
|
||||
|
||||
def get_ticket_info(self):
|
||||
"""
|
||||
获取配置信息
|
||||
:return:
|
||||
"""
|
||||
ticket_info_config = _get_yaml()
|
||||
from_station = ticket_info_config["set"]["from_station"].encode("utf8")
|
||||
to_station = ticket_info_config["set"]["to_station"].encode("utf8")
|
||||
station_dates = ticket_info_config["set"]["station_dates"]
|
||||
set_type = ticket_info_config["set"]["set_type"]
|
||||
is_more_ticket = ticket_info_config["set"]["is_more_ticket"]
|
||||
ticke_peoples = ticket_info_config["set"]["ticke_peoples"]
|
||||
select_refresh_interval = ticket_info_config["select_refresh_interval"]
|
||||
station_trains = ticket_info_config["set"]["station_trains"]
|
||||
ticket_black_list_time = ticket_info_config["ticket_black_list_time"]
|
||||
print u"*" * 20
|
||||
print u"12306刷票小助手,最后更新于2018.2.28,请勿作为商业用途,交流群号:286271084"
|
||||
print u"如果有好的margin,请联系作者,表示非常感激\n"
|
||||
print u"当前配置:出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票自动提交:{4}\n乘车人:{5}\n刷新间隔:随机(1-4S)\n候选购买车次:{7}\n僵尸票关小黑屋时长:{8}\n".format \
|
||||
(
|
||||
from_station,
|
||||
to_station,
|
||||
station_dates,
|
||||
",".join(set_type),
|
||||
is_more_ticket,
|
||||
",".join(ticke_peoples),
|
||||
select_refresh_interval,
|
||||
",".join(station_trains),
|
||||
ticket_black_list_time,
|
||||
)
|
||||
print u"*" * 20
|
||||
return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, select_refresh_interval, station_trains, ticket_black_list_time
|
||||
|
||||
def station_table(self, from_station, to_station):
|
||||
"""
|
||||
读取车站信息
|
||||
:param station:
|
||||
:return:
|
||||
"""
|
||||
result = open('station_name.txt')
|
||||
info = result.read().split('=')[1].strip("'").split('@')
|
||||
del info[0]
|
||||
station_name = {}
|
||||
for i in range(0, len(info)):
|
||||
n_info = info[i].split('|')
|
||||
station_name[n_info[1]] = n_info[2]
|
||||
from_station = station_name[from_station.encode("utf8")]
|
||||
to_station = station_name[to_station.encode("utf8")]
|
||||
return from_station, to_station
|
||||
|
||||
def call_login(self, auth=False):
|
||||
"""
|
||||
登录回调方法
|
||||
:return:
|
||||
"""
|
||||
if auth:
|
||||
return self.login.auth()
|
||||
else:
|
||||
self.login.go_login()
|
||||
|
||||
def check_user(self):
|
||||
"""
|
||||
检查用户是否达到订票条件
|
||||
:return:
|
||||
"""
|
||||
check_user_url = self.urls["check_user_url"]
|
||||
data = {"_json_att": ""}
|
||||
check_user = self.httpClint.send(check_user_url, data)
|
||||
check_user_flag = check_user['data']['flag']
|
||||
if check_user_flag is True:
|
||||
self.is_check_user["user_time"] = datetime.datetime.now()
|
||||
else:
|
||||
if check_user['messages']:
|
||||
print (u'用户检查失败:%s,可能未登录,可能session已经失效' % check_user['messages'][0])
|
||||
print (u'正在尝试重新登录')
|
||||
self.call_login()
|
||||
self.is_check_user["user_time"] = datetime.datetime.now()
|
||||
else:
|
||||
print (u'用户检查失败: %s,可能未登录,可能session已经失效' % check_user)
|
||||
print (u'正在尝试重新登录')
|
||||
self.call_login()
|
||||
self.is_check_user["user_time"] = datetime.datetime.now()
|
||||
|
||||
def main(self):
|
||||
l = liftTicketInit(session=self)
|
||||
l.reqLiftTicketInit()
|
||||
self.call_login()
|
||||
self.check_user()
|
||||
from_station, to_station = self.station_table(self.from_station, self.to_station)
|
||||
passengerTicketStrList, oldPassengerStr, set_type = "", "", ""
|
||||
num = 1
|
||||
while 1:
|
||||
try:
|
||||
num += 1
|
||||
if "user_time" in self.is_check_user and (
|
||||
datetime.datetime.now() - self.is_check_user["user_time"]).seconds / 60 > 5:
|
||||
# 5分钟检查一次用户是否登录
|
||||
self.check_user()
|
||||
time.sleep(self.select_refresh_interval)
|
||||
if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00" or time.strftime('%H:%M:%S',
|
||||
time.localtime(
|
||||
time.time())) < "06:00:00":
|
||||
print(u"12306休息时间,本程序自动停止,明天早上6点将自动运行")
|
||||
while 1:
|
||||
time.sleep(1)
|
||||
if "06:00:00" < time.strftime('%H:%M:%S', time.localtime(time.time())) < "23:00:00":
|
||||
print(u"休息时间已过,重新开启检票功能")
|
||||
self.call_login()
|
||||
break
|
||||
start_time = datetime.datetime.now()
|
||||
|
||||
q = query(session=self,
|
||||
from_station=from_station,
|
||||
to_station=to_station,
|
||||
from_station_h=self.from_station,
|
||||
to_station_h=self.to_station,
|
||||
_station_seat=self._station_seat,
|
||||
station_trains=self.station_trains,
|
||||
station_dates=self.station_dates,)
|
||||
queryResult = q.sendQuery()
|
||||
# 查询接口
|
||||
if queryResult.get("status", False):
|
||||
secretStr = queryResult.get("secretStr", "")
|
||||
train_no = queryResult.get("train_no", "")
|
||||
stationTrainCode = queryResult.get("stationTrainCode", "")
|
||||
train_date = queryResult.get("train_date", "")
|
||||
query_from_station_name = queryResult.get("query_from_station_name", "")
|
||||
query_to_station_name = queryResult.get("query_to_station_name", "")
|
||||
set_type = queryResult.get("set_type", "")
|
||||
leftTicket = queryResult.get("leftTicket", "")
|
||||
if self.ticket_black_list.has_key(train_no) and (
|
||||
datetime.datetime.now() - self.ticket_black_list[train_no]).seconds / 60 < int(
|
||||
self.ticket_black_list_time):
|
||||
print(ticket.QUEUE_WARNING_MSG.format(train_no))
|
||||
else:
|
||||
# 获取联系人
|
||||
if not self.passengerTicketStrList and not self.oldPassengerStr:
|
||||
s = getPassengerDTOs(session=self, ticket_peoples=self.ticke_peoples, set_type=set_type)
|
||||
getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr()
|
||||
if getPassengerDTOsResult.get("status", False):
|
||||
self.passengerTicketStrList = getPassengerDTOsResult.get("passengerTicketStrList", "")
|
||||
self.oldPassengerStr = getPassengerDTOsResult.get("oldPassengerStr", "")
|
||||
set_type = getPassengerDTOsResult.get("set_type", "")
|
||||
# 提交订单
|
||||
a = autoSubmitOrderRequest(session=self,
|
||||
secretStr=secretStr,
|
||||
train_date=train_date,
|
||||
query_from_station_name=self.from_station,
|
||||
query_to_station_name=self.to_station,
|
||||
passengerTicketStr=self.passengerTicketStrList,
|
||||
oldPassengerStr=self.oldPassengerStr
|
||||
)
|
||||
submitResult = a.sendAutoSubmitOrderRequest()
|
||||
if submitResult.get("status", False):
|
||||
result = submitResult.get("result", "")
|
||||
# 订单排队
|
||||
time.sleep(submitResult.get("ifShowPassCodeTime", 1))
|
||||
g = getQueueCountAsync(session=self,
|
||||
train_no=train_no,
|
||||
stationTrainCode=stationTrainCode,
|
||||
fromStationTelecode=query_from_station_name,
|
||||
toStationTelecode=query_to_station_name,
|
||||
leftTicket=leftTicket,
|
||||
set_type=set_type,
|
||||
users=len(self.ticke_peoples),
|
||||
)
|
||||
getQueueCountAsyncResult = g.sendGetQueueCountAsync()
|
||||
time.sleep(submitResult.get("ifShowPassCodeTime", 1))
|
||||
if getQueueCountAsyncResult.get("is_black", False):
|
||||
black_train_no = getQueueCountAsyncResult.get("train_no", "")
|
||||
self.ticket_black_list[black_train_no] = datetime.datetime.now()
|
||||
if getQueueCountAsyncResult.get("status", False):
|
||||
# 请求订单快读接口
|
||||
c = confirmSingleForQueueAsys(session=self,
|
||||
passengerTicketStr=self.passengerTicketStrList,
|
||||
oldPassengerStr=self.oldPassengerStr,
|
||||
result=result, )
|
||||
confirmSingleForQueueAsysResult = c.sendConfirmSingleForQueueAsys()
|
||||
# 排队
|
||||
if confirmSingleForQueueAsysResult.get("status", False):
|
||||
qwt = queryOrderWaitTime(session=self)
|
||||
qwt.sendQueryOrderWaitTime()
|
||||
else:
|
||||
self.httpClint.del_cookies()
|
||||
|
||||
else:
|
||||
s_time = random.randint(0, 4)
|
||||
time.sleep(s_time)
|
||||
print u"正在第{0}次查询 随机停留时长:{6} 乘车日期: {1} 车次:{2} 查询无票 cdn轮询IP:{4}当前cdn总数:{5} 总耗时:{3}ms".format(num,
|
||||
",".join(
|
||||
self.station_dates),
|
||||
",".join(
|
||||
self.station_trains),
|
||||
(
|
||||
datetime.datetime.now() - start_time).microseconds / 1000,
|
||||
self.httpClint.cdn,
|
||||
len(
|
||||
self.cdn_list),
|
||||
s_time)
|
||||
except PassengerUserException as e:
|
||||
print e.message
|
||||
break
|
||||
except ticketConfigException as e:
|
||||
print e.message
|
||||
break
|
||||
except ticketIsExitsException as e:
|
||||
print e.message
|
||||
break
|
||||
except ticketNumOutException as e:
|
||||
print e.message
|
||||
break
|
||||
except UserPasswordException as e:
|
||||
print e.message
|
||||
break
|
||||
except ValueError as e:
|
||||
if e.message == "No JSON object could be decoded":
|
||||
print(u"12306接口无响应,正在重试")
|
||||
else:
|
||||
print(e.message)
|
||||
except KeyError as e:
|
||||
print(e.message)
|
||||
# except TypeError as e:
|
||||
# print(u"12306接口无响应,正在重试 {0}".format(e.message))
|
||||
except socket.error as e:
|
||||
print(e.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
s = selectFast()
|
||||
s.main()
|
||||
# a = select('上海', '北京')
|
||||
# a.main()
|
150
init/login.py
150
init/login.py
|
@ -1,5 +1,6 @@
|
|||
#!/bin/env python
|
||||
# -*- coding=utf-8 -*-
|
||||
import copy
|
||||
import random
|
||||
import json
|
||||
import re
|
||||
|
@ -10,118 +11,25 @@ from config.ticketConf import _get_yaml
|
|||
from PIL import Image
|
||||
from damatuCode.damatuWeb import DamatuApi
|
||||
from damatuCode.ruokuai import RClient
|
||||
from inter.GetPassCodeNewOrderAndLogin import getPassCodeNewOrderAndLogin
|
||||
from inter.GetRandCode import getRandCode
|
||||
from myException.UserPasswordException import UserPasswordException
|
||||
from myException.balanceException import balanceException
|
||||
from myUrllib import myurllib2
|
||||
|
||||
|
||||
class GoLogin:
|
||||
def __init__(self, httpClint, urlConf, is_aotu_code, aotu_code_type):
|
||||
self.httpClint = httpClint
|
||||
def __init__(self, session, is_auto_code, auto_code_type):
|
||||
self.session = session
|
||||
self.randCode = ""
|
||||
self.urlConf = urlConf
|
||||
self.is_aotu_code = is_aotu_code
|
||||
self.aotu_code_type = aotu_code_type
|
||||
|
||||
def cookietp(self):
|
||||
print(u"正在获取cookie")
|
||||
url = self.urlConf["loginInit"]
|
||||
self.httpClint.send(url)
|
||||
|
||||
def getRandCode(self):
|
||||
"""
|
||||
识别验证码
|
||||
:return: 坐标
|
||||
"""
|
||||
try:
|
||||
if self.is_aotu_code:
|
||||
if self.aotu_code_type == 1:
|
||||
return DamatuApi(_get_yaml()["damatu"]["uesr"], _get_yaml()["damatu"]["pwd"], "./tkcode").main()
|
||||
elif self.aotu_code_type == 2:
|
||||
rc = RClient(_get_yaml()["damatu"]["uesr"], _get_yaml()["damatu"]["pwd"])
|
||||
im = open('./tkcode', 'rb').read()
|
||||
Result = rc.rk_create(im, 6113)
|
||||
if "Result" in Result:
|
||||
return self.codexy(Ofset=",".join(list(Result["Result"])), is_raw_input=False)
|
||||
else:
|
||||
if "Error" in Result and Result["Error"]:
|
||||
print Result["Error"]
|
||||
return ""
|
||||
else:
|
||||
img = Image.open('./tkcode')
|
||||
img.show()
|
||||
return self.codexy()
|
||||
except:
|
||||
pass
|
||||
|
||||
def readImg(self, code_url):
|
||||
"""
|
||||
增加手动打码,只是登录接口,完全不用担心提交订单效率
|
||||
思路
|
||||
1.调用PIL显示图片
|
||||
2.图片位置说明,验证码图片中每个图片代表一个下标,依次类推,1,2,3,4,5,6,7,8
|
||||
3.控制台输入对应下标,按照英文逗号分开,即可手动完成打码,
|
||||
:return:
|
||||
"""
|
||||
print (u"下载验证码...")
|
||||
codeimgUrl = code_url
|
||||
img_path = './tkcode'
|
||||
result = self.httpClint.send(codeimgUrl)
|
||||
try:
|
||||
print(u"下载验证码成功")
|
||||
open(img_path, 'wb').write(result)
|
||||
except OSError as e:
|
||||
print (e)
|
||||
|
||||
def codexy(self, Ofset=None, is_raw_input=True):
|
||||
"""
|
||||
获取验证码
|
||||
:return: str
|
||||
"""
|
||||
if is_raw_input:
|
||||
Ofset = raw_input(u"请输入验证码: ")
|
||||
select = Ofset.split(',')
|
||||
post = []
|
||||
offsetsX = 0 # 选择的答案的left值,通过浏览器点击8个小图的中点得到的,这样基本没问题
|
||||
offsetsY = 0 # 选择的答案的top值
|
||||
for ofset in select:
|
||||
if ofset == '1':
|
||||
offsetsY = 46
|
||||
offsetsX = 42
|
||||
elif ofset == '2':
|
||||
offsetsY = 46
|
||||
offsetsX = 105
|
||||
elif ofset == '3':
|
||||
offsetsY = 45
|
||||
offsetsX = 184
|
||||
elif ofset == '4':
|
||||
offsetsY = 48
|
||||
offsetsX = 256
|
||||
elif ofset == '5':
|
||||
offsetsY = 36
|
||||
offsetsX = 117
|
||||
elif ofset == '6':
|
||||
offsetsY = 112
|
||||
offsetsX = 115
|
||||
elif ofset == '7':
|
||||
offsetsY = 114
|
||||
offsetsX = 181
|
||||
elif ofset == '8':
|
||||
offsetsY = 111
|
||||
offsetsX = 252
|
||||
else:
|
||||
pass
|
||||
post.append(offsetsX)
|
||||
post.append(offsetsY)
|
||||
randCode = str(post).replace(']', '').replace('[', '').replace("'", '').replace(' ', '')
|
||||
print(u"验证码识别坐标为{0}".format(randCode))
|
||||
return randCode
|
||||
self.is_auto_code = is_auto_code
|
||||
self.auto_code_type = auto_code_type
|
||||
|
||||
def auth(self):
|
||||
"""认证"""
|
||||
authUrl = self.urlConf["auth"]
|
||||
authUrl = self.session.urls["auth"]
|
||||
authData = {"appid": "otn"}
|
||||
tk = self.httpClint.send(authUrl, authData)
|
||||
tk = self.session.httpClint.send(authUrl, authData)
|
||||
return tk
|
||||
|
||||
def codeCheck(self):
|
||||
|
@ -129,13 +37,13 @@ class GoLogin:
|
|||
验证码校验
|
||||
:return:
|
||||
"""
|
||||
codeCheck = self.urlConf["codeCheck"]
|
||||
codeCheck = self.session.urls["codeCheck"]
|
||||
codeCheckData = {
|
||||
"answer": self.randCode,
|
||||
"rand": "sjrand",
|
||||
"login_site": "E"
|
||||
}
|
||||
fresult = self.httpClint.send(codeCheck, codeCheckData)
|
||||
fresult = self.session.httpClint.send(codeCheck, codeCheckData)
|
||||
if "result_code" in fresult and fresult["result_code"] == "4":
|
||||
print (u"验证码通过,开始登录..")
|
||||
return True
|
||||
|
@ -143,7 +51,7 @@ class GoLogin:
|
|||
if "result_message" in fresult:
|
||||
print(fresult["result_message"])
|
||||
sleep(1)
|
||||
self.httpClint.del_cookies()
|
||||
self.session.httpClint.del_cookies()
|
||||
|
||||
def baseLogin(self, user, passwd):
|
||||
"""
|
||||
|
@ -152,13 +60,13 @@ class GoLogin:
|
|||
:param passwd:
|
||||
:return: 权限校验码
|
||||
"""
|
||||
logurl = self.urlConf["login"]
|
||||
logurl = self.session.urls["login"]
|
||||
logData = {
|
||||
"username": user,
|
||||
"password": passwd,
|
||||
"appid": "otn"
|
||||
}
|
||||
tresult = self.httpClint.send(logurl, logData)
|
||||
tresult = self.session.httpClint.send(logurl, logData)
|
||||
if 'result_code' in tresult and tresult["result_code"] == 0:
|
||||
print (u"登录成功")
|
||||
tk = self.auth()
|
||||
|
@ -185,9 +93,9 @@ class GoLogin:
|
|||
if not uamtk:
|
||||
return u"权限校验码不能为空"
|
||||
else:
|
||||
uamauthclientUrl = self.urlConf["uamauthclient"]
|
||||
uamauthclientUrl = self.session.urls["uamauthclient"]
|
||||
data = {"tk": uamtk}
|
||||
uamauthclientResult = self.httpClint.send(uamauthclientUrl, data)
|
||||
uamauthclientResult = self.session.httpClint.send(uamauthclientUrl, data)
|
||||
if uamauthclientResult:
|
||||
if "result_code" in uamauthclientResult and uamauthclientResult["result_code"] == 0:
|
||||
print(u"欢迎 {} 登录".format(uamauthclientResult["username"]))
|
||||
|
@ -195,9 +103,9 @@ class GoLogin:
|
|||
else:
|
||||
return False
|
||||
else:
|
||||
self.httpClint.send(uamauthclientUrl, data)
|
||||
url = self.urlConf["getUserInfo"]
|
||||
self.httpClint.send(url)
|
||||
self.session.httpClint.send(uamauthclientUrl, data)
|
||||
url = self.session.urls["getUserInfo"]
|
||||
self.session.httpClint.send(url)
|
||||
|
||||
def go_login(self):
|
||||
"""
|
||||
|
@ -206,27 +114,17 @@ class GoLogin:
|
|||
:param passwd: 密码
|
||||
:return:
|
||||
"""
|
||||
if self.is_aotu_code and self.aotu_code_type == 1:
|
||||
balance = DamatuApi(_get_yaml()["damatu"]["uesr"], _get_yaml()["damatu"]["pwd"]).getBalance()
|
||||
if self.is_auto_code and self.auto_code_type == 1:
|
||||
balance = DamatuApi(_get_yaml()["auto_code_account"]["uesr"], _get_yaml()["auto_code_account"]["pwd"]).getBalance()
|
||||
if int(balance) < 40:
|
||||
raise balanceException(u'余额不足,当前余额为: {}'.format(balance))
|
||||
user, passwd = _get_yaml()["set"]["12306count"][0]["uesr"], _get_yaml()["set"]["12306count"][1]["pwd"]
|
||||
user, passwd = _get_yaml()["set"]["12306acount"][0]["uesr"], _get_yaml()["set"]["12306account"][1]["pwd"]
|
||||
if not user or not passwd:
|
||||
raise UserPasswordException(u"温馨提示: 用户名或者密码为空,请仔细检查")
|
||||
login_num = 0
|
||||
while True:
|
||||
self.cookietp()
|
||||
# self.httpClint.set_cookies(_jc_save_showIns="true",
|
||||
# _jc_save_wfdc_flag="dc",
|
||||
# _jc_save_toDate="2018-06-06",
|
||||
# _jc_save_fromDate=_get_yaml()["set"]["station_dates"][0],
|
||||
# RAIL_EXPIRATION="1528337042724",
|
||||
# RAIL_DEVICEID="O6DFHLmFChFrZUI7QyY9xcqj94eZG9JH_kD3zSZt53tkCUq0uqdvlo1fm_CmNxr_QAnMOU79JmHI8jbtj2vaNUnOZKCqcsMNbhCaoDIB3vxgsyzMMGOZF-CknXKEFaCLPGyDNXEknPDs7xgSbanwKqsiSRT41xti",
|
||||
#
|
||||
# )
|
||||
self.urlConf["getCodeImg"]["req_url"] = self.urlConf["getCodeImg"]["req_url"].format(random.random())
|
||||
self.readImg(self.urlConf["getCodeImg"])
|
||||
self.randCode = self.getRandCode()
|
||||
getPassCodeNewOrderAndLogin(session=self.session, imgType="login")
|
||||
self.randCode = getRandCode(self.is_auto_code, self.auto_code_type)
|
||||
login_num += 1
|
||||
self.auth()
|
||||
if self.codeCheck():
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
# -*- coding=utf-8 -*-
|
||||
import datetime
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import urllib
|
||||
from collections import OrderedDict
|
||||
|
||||
import collections
|
||||
import wrapcache
|
||||
|
||||
from agency.cdn_utils import CDNProxy
|
||||
from config import urlConf
|
||||
from config.emailConf import sendEmail
|
||||
from config.TicketEnmu import ticket
|
||||
from config.ticketConf import _get_yaml
|
||||
from init import login
|
||||
from init.login import GoLogin
|
||||
from inter.AutoSubmitOrderRequest import autoSubmitOrderRequest
|
||||
from inter.CheckUser import checkUser
|
||||
from inter.GetPassengerDTOs import getPassengerDTOs
|
||||
from inter.LiftTicketInit import liftTicketInit
|
||||
from inter.Query import query
|
||||
from inter.SubmitOrderRequest import submitOrderRequest
|
||||
from myException.PassengerUserException import PassengerUserException
|
||||
from myException.UserPasswordException import UserPasswordException
|
||||
from myException.ticketConfigException import ticketConfigException
|
||||
|
@ -30,28 +29,23 @@ sys.setdefaultencoding('utf-8')
|
|||
|
||||
|
||||
class select:
|
||||
"""
|
||||
快速提交车票通道
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, self.ticke_peoples, self.select_refresh_interval, self.station_trains, self.ticket_black_list_time = self.get_ticket_info()
|
||||
self.is_aotu_code = _get_yaml()["is_aotu_code"]
|
||||
self.aotu_code_type = _get_yaml()["aotu_code_type"]
|
||||
self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, \
|
||||
self.ticke_peoples, self.select_refresh_interval, self.station_trains, self.ticket_black_list_time, \
|
||||
self.order_type = self.get_ticket_info()
|
||||
self.is_auto_code = _get_yaml()["is_auto_code"]
|
||||
self.auto_code_type = _get_yaml()["auto_code_type"]
|
||||
self.is_cdn = _get_yaml()["is_cdn"]
|
||||
self.order_request_params = {} # 订单提交时的参数
|
||||
self.ticketInfoForPassengerForm = {} # 初始化当前页面参数
|
||||
self.current_seats = {} # 席别信息
|
||||
self.token = ""
|
||||
self.set_type = ""
|
||||
self.user_info = ""
|
||||
self.secretStr = ""
|
||||
self.ticket_black_list = dict()
|
||||
self.ticket_black_list_time = dict()
|
||||
self.is_check_user = dict()
|
||||
self.httpClint = HTTPClient()
|
||||
self.confUrl = urlConf.urls
|
||||
self.login = GoLogin(self.httpClint, self.confUrl, self.is_aotu_code, self.aotu_code_type)
|
||||
self.is_download_img = False
|
||||
self.randCode = ""
|
||||
self.urls = urlConf.urls
|
||||
self.login = GoLogin(self, self.is_auto_code, self.auto_code_type)
|
||||
self.cdn_list = []
|
||||
self.buy_ticket_time = ""
|
||||
self.passengerTicketStrList = ""
|
||||
self.oldPassengerStr = ""
|
||||
|
||||
def get_ticket_info(self):
|
||||
"""
|
||||
|
@ -68,58 +62,26 @@ class select:
|
|||
select_refresh_interval = ticket_info_config["select_refresh_interval"]
|
||||
station_trains = ticket_info_config["set"]["station_trains"]
|
||||
ticket_black_list_time = ticket_info_config["ticket_black_list_time"]
|
||||
print u"*"*20
|
||||
order_type = ticket_info_config["order_type"]
|
||||
print u"*" * 20
|
||||
print u"12306刷票小助手,最后更新于2018.2.28,请勿作为商业用途,交流群号:286271084"
|
||||
print u"如果有好的margin,请联系作者,表示非常感激\n"
|
||||
print u"当前配置:出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票自动提交:{4}\n乘车人:{5}\n刷新间隔:{6}s(如果想随机刷新,请自行修改)\n候选购买车次:{7}\n僵尸票关小黑屋时长:{8}\n".format\
|
||||
(
|
||||
from_station,
|
||||
to_station,
|
||||
station_dates,
|
||||
",".join(set_type),
|
||||
is_more_ticket,
|
||||
",".join(ticke_peoples),
|
||||
select_refresh_interval,
|
||||
",".join(station_trains),
|
||||
ticket_black_list_time,
|
||||
print u"当前配置:出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票自动提交:{4}\n乘车人:{5}\n" \
|
||||
u"刷新间隔:随机(1-4S)\n候选购买车次:{7}\n僵尸票关小黑屋时长:{8}\n 下单接口:{9}\n".format \
|
||||
(
|
||||
from_station,
|
||||
to_station,
|
||||
station_dates,
|
||||
",".join(set_type),
|
||||
is_more_ticket,
|
||||
",".join(ticke_peoples),
|
||||
select_refresh_interval,
|
||||
",".join(station_trains),
|
||||
ticket_black_list_time,
|
||||
order_type,
|
||||
)
|
||||
print u"*"*20
|
||||
return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, select_refresh_interval, station_trains, ticket_black_list_time
|
||||
|
||||
def get_order_request_params(self):
|
||||
return self.order_request_params
|
||||
|
||||
def get_ticketInfoForPassengerForm(self):
|
||||
return self.ticketInfoForPassengerForm
|
||||
|
||||
def get_current_seats(self):
|
||||
return self.current_seats
|
||||
|
||||
def get_token(self):
|
||||
return self.token
|
||||
|
||||
def get_set_type(self):
|
||||
return self.set_type
|
||||
|
||||
def conversion_int(self, str):
|
||||
return int(str)
|
||||
|
||||
def station_seat(self, index):
|
||||
"""
|
||||
获取车票对应坐席
|
||||
:param seat_type:
|
||||
:return:
|
||||
"""
|
||||
seat = {'商务座': 32,
|
||||
'一等座': 31,
|
||||
'二等座': 30,
|
||||
'特等座': 25,
|
||||
'软卧': 23,
|
||||
'硬卧': 28,
|
||||
'硬座': 29,
|
||||
'无座': 26,
|
||||
}
|
||||
return seat[index]
|
||||
print u"*" * 20
|
||||
return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, select_refresh_interval, station_trains, ticket_black_list_time, order_type
|
||||
|
||||
def station_table(self, from_station, to_station):
|
||||
"""
|
||||
|
@ -138,534 +100,6 @@ class select:
|
|||
to_station = station_name[to_station.encode("utf8")]
|
||||
return from_station, to_station
|
||||
|
||||
def time(self):
|
||||
"""
|
||||
获取日期
|
||||
:return:
|
||||
"""
|
||||
today = datetime.date.today()
|
||||
# tomorrow = today+datetime.timedelta(1)
|
||||
return today.strftime('%Y-%m-%d')
|
||||
|
||||
def callReadImg(self, code_url):
|
||||
"""
|
||||
下载验证码
|
||||
:param code_url: 验证码url
|
||||
:return:
|
||||
"""
|
||||
self.login.readImg(code_url=code_url)
|
||||
self.is_aotu_code = True
|
||||
|
||||
def callRandCode(self):
|
||||
"""
|
||||
识别验证码
|
||||
:return:
|
||||
"""
|
||||
while True:
|
||||
if self.is_aotu_code:
|
||||
self.randCode = self.login.getRandCode()
|
||||
self.is_aotu_code = False
|
||||
|
||||
def getRepeatSubmitToken(self):
|
||||
"""
|
||||
获取提交车票请求token
|
||||
:return: token
|
||||
"""
|
||||
initdc_url = self.confUrl["initdc_url"]
|
||||
initdc_result = self.httpClint.send(initdc_url,)
|
||||
token_name = re.compile(r"var globalRepeatSubmitToken = '(\S+)'")
|
||||
ticketInfoForPassengerForm_name = re.compile(r'var ticketInfoForPassengerForm=(\{.+\})?')
|
||||
order_request_params_name = re.compile(r'var orderRequestDTO=(\{.+\})?')
|
||||
self.token = re.search(token_name, initdc_result).group(1)
|
||||
re_tfpf = re.findall(ticketInfoForPassengerForm_name, initdc_result)
|
||||
re_orp = re.findall(order_request_params_name, initdc_result)
|
||||
if re_tfpf:
|
||||
self.ticketInfoForPassengerForm = json.loads(re_tfpf[0].replace("'", '"'))
|
||||
else:
|
||||
pass
|
||||
if re_orp:
|
||||
self.order_request_params = json.loads(re_orp[0].replace("'", '"'))
|
||||
else:
|
||||
pass
|
||||
|
||||
def GetJS(self):
|
||||
getJSUrl = self.confUrl["GetJS"]
|
||||
self.httpClint.send(getJSUrl)
|
||||
odxmfwgUrl = self.confUrl["odxmfwg"]
|
||||
self.httpClint.send(odxmfwgUrl)
|
||||
|
||||
def getPassengerDTOs(self):
|
||||
"""
|
||||
获取乘客信息
|
||||
:return:
|
||||
"""
|
||||
get_passengerDTOs = self.confUrl["get_passengerDTOs"]
|
||||
get_data = {
|
||||
'_json_att': None,
|
||||
'REPEAT_SUBMIT_TOKEN': self.token
|
||||
}
|
||||
jsonData = self.httpClint.send(get_passengerDTOs, get_data)
|
||||
if 'data' in jsonData and jsonData['data'] and 'l' in jsonData['data'] and jsonData['data'][
|
||||
'normal_passengers']:
|
||||
normal_passengers = jsonData['data']['normal_passengers']
|
||||
_normal_passenger = [normal_passengers[i] for i in range(len(normal_passengers))if normal_passengers[i]["passenger_name"] in self.ticke_peoples]
|
||||
return _normal_passenger if _normal_passenger else [normal_passengers[0]] # 如果配置乘车人没有在账号,则默认返回第一个用户
|
||||
else:
|
||||
if 'data' in jsonData and 'exMsg' in jsonData['data'] and jsonData['data']['exMsg']:
|
||||
print(jsonData['data']['exMsg'])
|
||||
elif 'messages' in jsonData and jsonData['messages']:
|
||||
print(jsonData['messages'][0])
|
||||
else:
|
||||
print(u"未查找到常用联系人")
|
||||
raise PassengerUserException(u"未查找到常用联系人,请先添加联系人在试试")
|
||||
|
||||
def submitOrderRequestFunc(self, from_station, to_station, station_date=None):
|
||||
self.confUrl["select_url"]["req_url"] = self.confUrl["select_url"]["req_url"].format(
|
||||
station_date, from_station, to_station)
|
||||
station_ticket = self.httpClint.send(self.confUrl["select_url"])
|
||||
return json.loads(station_ticket)
|
||||
|
||||
def submitOrderRequestImplement(self, from_station, to_station,):
|
||||
"""
|
||||
提交车次信息
|
||||
车次对应字典
|
||||
{32: '商务座 ',
|
||||
31: '一等座 ',
|
||||
30: '二等座 ',
|
||||
25: '特等座 ',
|
||||
23: '软卧 ',
|
||||
28: '硬卧 ',
|
||||
29: '硬座 ',
|
||||
26: '无座 '
|
||||
} 参照station_seat()方法
|
||||
:return:
|
||||
"""
|
||||
station_tickets = [self.submitOrderRequestFunc(from_station, to_station, station_date) for station_date in self.station_dates]
|
||||
for station_ticket in station_tickets:
|
||||
value = station_ticket['data']
|
||||
if not value:
|
||||
print (u'{0}-{1} 车次坐席查询为空...'.format(self.from_station, self.to_station))
|
||||
else:
|
||||
if value['result']:
|
||||
for i in value['result']:
|
||||
ticket_info = i.split('|')
|
||||
if ticket_info[11] == "Y" and ticket_info[1].encode("utf8") == "预订": # 筛选未在开始时间内的车次
|
||||
for j in range(len(self._station_seat)):
|
||||
is_ticket_pass = ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))]
|
||||
# print self._station_seat[j]
|
||||
if is_ticket_pass != '' and is_ticket_pass != '无' and ticket_info[3] in self.station_trains and is_ticket_pass != '*': # 过滤有效目标车次
|
||||
# tiket_values = [k for k in value['map'].values()]
|
||||
self.secretStr = ticket_info[0]
|
||||
train_no = ticket_info[3]
|
||||
print (u'车次: ' + train_no + ' 始发车站: ' + self.from_station + ' 终点站: ' +
|
||||
self.to_station + ' ' + self._station_seat[j].encode("utf8") + ':' + ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))])
|
||||
if self.ticket_black_list.has_key(train_no) and (datetime.datetime.now() - self.ticket_black_list[train_no]).seconds/60 < int(self.ticket_black_list_time):
|
||||
print(u"该车次{} 正在被关小黑屋,跳过此车次".format(train_no))
|
||||
break
|
||||
else:
|
||||
print (u'正在尝试提交订票...')
|
||||
self.buy_ticket_time = datetime.datetime.now()
|
||||
# self.submitOrderRequestFunc(from_station, to_station, self.time())
|
||||
self.submit_station()
|
||||
self.getPassengerTicketStr(self._station_seat[j].encode("utf8"))
|
||||
self.getRepeatSubmitToken()
|
||||
if not self.user_info: # 修改每次都调用用户接口导致用户接口不能用
|
||||
self.user_info = self.getPassengerDTOs()
|
||||
codeImgByOrder = self.confUrl["codeImgByOrder"]
|
||||
self.login.readImg(codeImgByOrder)
|
||||
if self.checkOrderInfo(train_no, self._station_seat[j].encode("utf8")):
|
||||
break
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
# time.sleep(self.expect_refresh_interval)
|
||||
else:
|
||||
print u"车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket)
|
||||
|
||||
def check_user(self):
|
||||
"""
|
||||
检查用户是否达到订票条件
|
||||
:return:
|
||||
"""
|
||||
check_user_url = self.confUrl["check_user_url"]
|
||||
data = {"_json_att": ""}
|
||||
check_user = self.httpClint.send(check_user_url, data)
|
||||
check_user_flag = check_user['data']['flag']
|
||||
if check_user_flag is True:
|
||||
self.is_check_user["user_time"] = datetime.datetime.now()
|
||||
else:
|
||||
if check_user['messages']:
|
||||
print (u'用户检查失败:%s,可能未登录,可能session已经失效' % check_user['messages'][0])
|
||||
print (u'正在尝试重新登录')
|
||||
self.call_login()
|
||||
self.is_check_user["user_time"] = datetime.datetime.now()
|
||||
else:
|
||||
print (u'用户检查失败: %s,可能未登录,可能session已经失效' % check_user)
|
||||
print (u'正在尝试重新登录')
|
||||
self.call_login()
|
||||
self.is_check_user["user_time"] = datetime.datetime.now()
|
||||
|
||||
def submit_station(self):
|
||||
"""
|
||||
提交车次
|
||||
预定的请求参数,注意参数顺序
|
||||
注意这里为了防止secretStr被urllib.parse过度编码,在这里进行一次解码
|
||||
否则调用HttpTester类的post方法将会将secretStr编码成为无效码,造成提交预定请求失败
|
||||
:param self:
|
||||
:param secretStr: 提交车次加密
|
||||
:return:
|
||||
"""
|
||||
submit_station_url = self.confUrl["submit_station_url"]
|
||||
data = [('secretStr', urllib.unquote(self.secretStr)), # 字符串加密
|
||||
('train_date', self.station_dates[0]), # 出发时间
|
||||
('back_train_date', self.time()), # 返程时间
|
||||
('tour_flag', 'dc'), # 旅途类型
|
||||
('purpose_codes', 'ADULT'), # 成人票还是学生票
|
||||
('query_from_station_name', self.from_station), # 起始车站
|
||||
('query_to_station_name', self.to_station), # 终点车站
|
||||
]
|
||||
submitResult = self.httpClint.send(submit_station_url, data)
|
||||
if 'data' in submitResult and submitResult['data']:
|
||||
if submitResult['data'] == 'N':
|
||||
print (u'出票成功')
|
||||
else:
|
||||
print (u'出票失败')
|
||||
elif 'messages' in submitResult and submitResult['messages']:
|
||||
raise ticketIsExitsException(submitResult['messages'][0])
|
||||
|
||||
def getPassengerTicketStr(self, set_type):
|
||||
"""
|
||||
获取getPassengerTicketStr 提交对应的代号码
|
||||
:param str: 坐席
|
||||
:return:
|
||||
"""
|
||||
passengerTicketStr = {
|
||||
'一等座': 'M',
|
||||
'特等座': 'P',
|
||||
'二等座': 'O',
|
||||
'商务座': 9,
|
||||
'硬座': 1,
|
||||
'无座': 1,
|
||||
'软卧': 4,
|
||||
'硬卧': 3,
|
||||
}
|
||||
self.set_type = str(passengerTicketStr[set_type.replace(' ', '')])
|
||||
|
||||
def ticket_type(self):
|
||||
"""订单票的类型,目前只考虑成人票,此方法暂时搁置,做备案"""
|
||||
ticket_type = {'adult': "1", 'child': "2", 'student': "3", 'disability': "4"}
|
||||
return ticket_type
|
||||
|
||||
def getPassengerTicketStrListAndOldPassengerStr(self):
|
||||
"""
|
||||
获取提交车次人内容格式
|
||||
passengerTicketStr O,0,1,文贤平,1,43052419950223XXXX,15618715583,N_O,0,1,梁敏,1,43052719920118XXXX,,N
|
||||
oldPassengerStr 文贤平,1,43052719920118XXXX,1_梁敏,1,43052719920118XXXX,1_
|
||||
:return:
|
||||
"""
|
||||
passengerTicketStrList = []
|
||||
oldPassengerStr = []
|
||||
if not self.user_info:
|
||||
raise PassengerUserException(u"联系人不在列表中,请查证后添加")
|
||||
if len(self.user_info) is 1:
|
||||
passengerTicketStrList.append(
|
||||
'0,' + self.user_info[0]['passenger_type'] + "," + self.user_info[0][
|
||||
"passenger_name"] + "," +
|
||||
self.user_info[0]['passenger_id_type_code'] + "," + self.user_info[0]['passenger_id_no'] + "," +
|
||||
self.user_info[0]['mobile_no'] + ',N')
|
||||
oldPassengerStr.append(
|
||||
self.user_info[0]['passenger_name'] + "," + self.user_info[0]['passenger_id_type_code'] + "," +
|
||||
self.user_info[0]['passenger_id_no'] + "," + self.user_info[0]['passenger_type'] + '_')
|
||||
else:
|
||||
for i in range(len(self.user_info)):
|
||||
passengerTicketStrList.append(
|
||||
'0,' + self.user_info[i]['passenger_type'] + "," + self.user_info[i][
|
||||
"passenger_name"] + "," + self.user_info[i]['passenger_id_type_code'] + "," + self.user_info[i][
|
||||
'passenger_id_no'] + "," + self.user_info[i]['mobile_no'] + ',N_' + self.set_type)
|
||||
oldPassengerStr.append(
|
||||
self.user_info[i]['passenger_name'] + "," + self.user_info[i]['passenger_id_type_code'] + "," +
|
||||
self.user_info[i]['passenger_id_no'] + "," + self.user_info[i]['passenger_type'] + '_')
|
||||
return passengerTicketStrList, oldPassengerStr
|
||||
|
||||
def checkOrderInfo(self, train_no, set_type):
|
||||
"""
|
||||
检查支付订单,需要提交REPEAT_SUBMIT_TOKEN
|
||||
passengerTicketStr : 座位编号,0,票类型,乘客名,证件类型,证件号,手机号码,保存常用联系人(Y或N)
|
||||
oldPassengersStr: 乘客名,证件类型,证件号,乘客类型
|
||||
:return:
|
||||
"""
|
||||
passengerTicketStrList, oldPassengerStr = self.getPassengerTicketStrListAndOldPassengerStr()
|
||||
checkOrderInfoUrl = self.confUrl["checkOrderInfoUrl"]
|
||||
data = collections.OrderedDict()
|
||||
data['cancel_flag'] = 2
|
||||
data['bed_level_order_num'] = "000000000000000000000000000000"
|
||||
data['passengerTicketStr'] = self.set_type + "," + ",".join(passengerTicketStrList).rstrip("_{0}".format(self.set_type))
|
||||
data['oldPassengerStr'] = "".join(oldPassengerStr)
|
||||
data['tour_flag'] = 'dc'
|
||||
data['whatsSelect'] = 1
|
||||
data['REPEAT_SUBMIT_TOKEN'] = self.token
|
||||
checkOrderInfo = self.httpClint.send(checkOrderInfoUrl, data)
|
||||
if 'data' in checkOrderInfo:
|
||||
if "ifShowPassCode" in checkOrderInfo["data"] and checkOrderInfo["data"]["ifShowPassCode"] == "Y":
|
||||
is_need_code = True
|
||||
if self.getQueueCount(train_no, set_type, is_need_code):
|
||||
return True
|
||||
if "ifShowPassCode" in checkOrderInfo["data"] and checkOrderInfo['data']['submitStatus'] is True:
|
||||
print (u'车票提交通过,正在尝试排队')
|
||||
is_need_code = False
|
||||
if self.getQueueCount(train_no, set_type, is_need_code):
|
||||
return True
|
||||
else:
|
||||
if "errMsg" in checkOrderInfo['data'] and checkOrderInfo['data']["errMsg"]:
|
||||
print checkOrderInfo['data']["errMsg"]
|
||||
|
||||
else:
|
||||
print checkOrderInfo
|
||||
elif 'messages' in checkOrderInfo and checkOrderInfo['messages']:
|
||||
print (checkOrderInfo['messages'][0])
|
||||
|
||||
def getQueueCount(self, train_no, set_type, is_need_code):
|
||||
"""
|
||||
# 模拟查询当前的列车排队人数的方法
|
||||
# 返回信息组成的提示字符串
|
||||
:param token:
|
||||
:return:
|
||||
"""
|
||||
l_time = time.localtime(time.time())
|
||||
new_train_date = time.strftime("%a %b %d %Y", l_time)
|
||||
getQueueCountUrl = self.confUrl["getQueueCountUrl"]
|
||||
data = collections.OrderedDict()
|
||||
data['train_date'] = str(new_train_date) + " 00:00:00 GMT+0800 (中国标准时间)",
|
||||
data['train_no'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['train_no'],
|
||||
data['stationTrainCode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['station_train_code'],
|
||||
data['seatType'] = self.set_type,
|
||||
data['fromStationTelecode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['from_station'],
|
||||
data['toStationTelecode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['to_station'],
|
||||
data['leftTicket'] = self.get_ticketInfoForPassengerForm()['leftTicketStr'],
|
||||
data['purpose_codes'] = self.get_ticketInfoForPassengerForm()['purpose_codes'],
|
||||
data['train_location'] = self.get_ticketInfoForPassengerForm()['train_location'],
|
||||
data['REPEAT_SUBMIT_TOKEN'] = self.get_token(),
|
||||
getQueueCountResult = self.httpClint.send(getQueueCountUrl, data)
|
||||
if "status" in getQueueCountResult and getQueueCountResult["status"] is True:
|
||||
if "countT" in getQueueCountResult["data"]:
|
||||
ticket = getQueueCountResult["data"]["ticket"]
|
||||
ticket_split = sum(map(self.conversion_int, ticket.split(","))) if ticket.find(",") != -1 else ticket
|
||||
countT = getQueueCountResult["data"]["countT"]
|
||||
if int(countT) is 0:
|
||||
if int(ticket_split) < len(self.user_info):
|
||||
print(u"当前余票数小于乘车人数,放弃订票")
|
||||
else:
|
||||
print(u"排队成功, 当前余票还剩余: {0} 张".format(ticket_split))
|
||||
if self.checkQueueOrder(is_need_code):
|
||||
return True
|
||||
else:
|
||||
print(u"当前排队人数: {1} 当前余票还剩余:{0} 张,继续排队中".format(ticket_split, countT))
|
||||
else:
|
||||
print(u"排队发现未知错误{0},将此列车 {1}加入小黑屋".format(getQueueCountResult, train_no))
|
||||
self.ticket_black_list[train_no] = datetime.datetime.now()
|
||||
elif "messages" in getQueueCountResult and getQueueCountResult["messages"]:
|
||||
print(u"排队异常,错误信息:{0}, 将此列车 {1}加入小黑屋".format(getQueueCountResult["messages"][0], train_no))
|
||||
self.ticket_black_list[train_no] = datetime.datetime.now()
|
||||
else:
|
||||
if "validateMessages" in getQueueCountResult and getQueueCountResult["validateMessages"]:
|
||||
print(str(getQueueCountResult["validateMessages"]))
|
||||
self.ticket_black_list[train_no] = datetime.datetime.now()
|
||||
else:
|
||||
print(u"未知错误 {0}".format("".join(getQueueCountResult)))
|
||||
|
||||
def checkRandCodeAnsyn(self, randCode):
|
||||
"""
|
||||
识别验证码
|
||||
:return: 识别结果
|
||||
"""
|
||||
checkRandCodeAnsyn = self.confUrl["checkRandCodeAnsyn"]
|
||||
randData = {
|
||||
"randCode": randCode,
|
||||
"rand": "randp",
|
||||
"_json_att": None,
|
||||
"REPEAT_SUBMIT_TOKEN": self.get_token()
|
||||
}
|
||||
fresult = self.httpClint.send(checkRandCodeAnsyn, randData) # 校验验证码是否正确
|
||||
return fresult['data']['msg']
|
||||
|
||||
def checkQueueOrder(self, is_node_code=False):
|
||||
"""
|
||||
模拟提交订单是确认按钮,参数获取方法还是get_ticketInfoForPassengerForm 中获取
|
||||
:return:
|
||||
"""
|
||||
|
||||
passengerTicketStrList, oldPassengerStr = self.getPassengerTicketStrListAndOldPassengerStr()
|
||||
checkQueueOrderUrl = self.confUrl["checkQueueOrderUrl"]
|
||||
data = {
|
||||
"passengerTicketStr": self.set_type + "," + ",".join(passengerTicketStrList).rstrip("_{0}".format(self.set_type)),
|
||||
"oldPassengerStr": "".join(oldPassengerStr),
|
||||
"purpose_codes": self.get_ticketInfoForPassengerForm()["purpose_codes"],
|
||||
"key_check_isChange": self.get_ticketInfoForPassengerForm()["key_check_isChange"],
|
||||
"leftTicketStr": self.get_ticketInfoForPassengerForm()["leftTicketStr"],
|
||||
"train_location": self.get_ticketInfoForPassengerForm()["train_location"],
|
||||
"seatDetailType": "000", # 开始需要选择座位,但是目前12306不支持自动选择作为,那这个参数为默认
|
||||
"roomType": "00", # 好像是根据一个id来判断选中的,两种 第一种是00,第二种是10,但是我在12306的页面没找到该id,目前写死是00,不知道会出什么错
|
||||
"dwAll": "N",
|
||||
"whatsSelect": 1,
|
||||
"_json_at": "",
|
||||
"randCode": "",
|
||||
"choose_seats": "",
|
||||
"REPEAT_SUBMIT_TOKEN": self.get_token(),
|
||||
}
|
||||
try:
|
||||
if is_node_code:
|
||||
print(u"正在使用自动识别验证码功能")
|
||||
for i in range(3):
|
||||
randCode = self.login.getRandCode()
|
||||
checkcode = self.checkRandCodeAnsyn(randCode)
|
||||
if checkcode == 'TRUE':
|
||||
print(u"验证码通过,正在提交订单")
|
||||
data['randCode'] = randCode
|
||||
break
|
||||
else:
|
||||
print (u"验证码有误, {0}次尝试重试".format(i+1))
|
||||
print(u"验证码超过限定次数3次,放弃此次订票机会!")
|
||||
else:
|
||||
print(u"不需要验证码")
|
||||
buy_end_time = (datetime.datetime.now() - self.buy_ticket_time).seconds
|
||||
print(u"总共花费时长{0}S".format(buy_end_time))
|
||||
time.sleep(8-buy_end_time if buy_end_time<8 else 0)
|
||||
checkQueueOrderResult = self.httpClint.send(checkQueueOrderUrl, data)
|
||||
if "status" in checkQueueOrderResult and checkQueueOrderResult["status"]:
|
||||
c_data = checkQueueOrderResult["data"] if "data" in checkQueueOrderResult else {}
|
||||
if 'submitStatus' in c_data and c_data['submitStatus'] is True:
|
||||
print(u"提交订单成功!")
|
||||
self.queryOrderWaitTime()
|
||||
else:
|
||||
if 'errMsg' in c_data and c_data['errMsg']:
|
||||
print(u"提交订单失败,{0}".format(c_data['errMsg']))
|
||||
else:
|
||||
print(c_data)
|
||||
print(u'订票失败!很抱歉,请重试提交预订功能!')
|
||||
elif "messages" in checkQueueOrderResult and checkQueueOrderResult["messages"]:
|
||||
print(u"提交订单失败,错误信息: " + checkQueueOrderResult["messages"])
|
||||
else:
|
||||
print(u"提交订单中,请耐心等待:" + checkQueueOrderResult["message"])
|
||||
except ValueError:
|
||||
print(u"接口 {} 无响应".format(checkQueueOrderUrl))
|
||||
|
||||
def queryOrderWaitTime(self):
|
||||
"""
|
||||
排队获取订单等待信息,每隔3秒请求一次,最高请求次数为20次!
|
||||
:return:
|
||||
"""
|
||||
num = 1
|
||||
while True:
|
||||
_random = int(round(time.time() * 1000))
|
||||
num += 1
|
||||
if num > 30:
|
||||
print(u"超出排队时间,自动放弃,正在重新刷票")
|
||||
order_id = self.queryMyOrderNoComplete() # 排队失败,自动取消排队订单
|
||||
if order_id:
|
||||
self.cancelNoCompleteMyOrder(order_id)
|
||||
break
|
||||
try:
|
||||
data = {"random": _random, "tourFlag": "dc"}
|
||||
queryOrderWaitTimeUrl = self.confUrl["queryOrderWaitTimeUrl"]
|
||||
queryOrderWaitTimeResult = self.httpClint.send(queryOrderWaitTimeUrl, data)
|
||||
except ValueError:
|
||||
queryOrderWaitTimeResult = {}
|
||||
if queryOrderWaitTimeResult:
|
||||
if "status" in queryOrderWaitTimeResult and queryOrderWaitTimeResult["status"]:
|
||||
if "orderId" in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["orderId"] is not None:
|
||||
sendEmail(u"恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!".format(queryOrderWaitTimeResult["data"]["orderId"]))
|
||||
raise ticketIsExitsException(u"恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!".format(queryOrderWaitTimeResult["data"]["orderId"]))
|
||||
elif "msg" in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["msg"]:
|
||||
print queryOrderWaitTimeResult["data"]["msg"]
|
||||
break
|
||||
elif "waitTime"in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["waitTime"]:
|
||||
print(u"排队等待时间预计还剩 {0} ms".format(0-queryOrderWaitTimeResult["data"]["waitTime"]))
|
||||
else:
|
||||
print (u"正在等待中")
|
||||
elif "messages" in queryOrderWaitTimeResult and queryOrderWaitTimeResult["messages"]:
|
||||
print(u"排队等待失败: " + queryOrderWaitTimeResult["messages"])
|
||||
else:
|
||||
print(u"第{}次排队中,请耐心等待".format(num+1))
|
||||
else:
|
||||
print(u"排队中")
|
||||
time.sleep(2)
|
||||
|
||||
else:
|
||||
print(ticketNumOutException(u"订单提交失败!,正在重新刷票"))
|
||||
|
||||
def queryMyOrderNoComplete(self):
|
||||
"""
|
||||
获取订单列表信息
|
||||
:return:
|
||||
"""
|
||||
self.initNoComplete()
|
||||
queryMyOrderNoCompleteUrl = self.confUrl["queryMyOrderNoCompleteUrl"]
|
||||
data = {"_json_att": ""}
|
||||
try:
|
||||
queryMyOrderNoCompleteResult = self.httpClint.send(queryMyOrderNoCompleteUrl, data)
|
||||
except ValueError:
|
||||
queryMyOrderNoCompleteResult = {}
|
||||
if queryMyOrderNoCompleteResult:
|
||||
if "data" in queryMyOrderNoCompleteResult and queryMyOrderNoCompleteResult["data"] and "orderDBList" in queryMyOrderNoCompleteResult["data"] and queryMyOrderNoCompleteResult["data"]["orderDBList"]:
|
||||
orderId = queryMyOrderNoCompleteResult["data"]["orderDBList"][0]["sequence_no"]
|
||||
return orderId
|
||||
elif "data" in queryMyOrderNoCompleteResult and "orderCacheDTO" in queryMyOrderNoCompleteResult["data"] and queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]:
|
||||
if "message" in queryMyOrderNoCompleteResult["data"]["orderCacheDTO"] and queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]:
|
||||
print(queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]["message"])
|
||||
raise ticketNumOutException(queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]["message"])
|
||||
else:
|
||||
if "message" in queryMyOrderNoCompleteResult and queryMyOrderNoCompleteResult["message"]:
|
||||
print queryMyOrderNoCompleteResult["message"]
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
print(u"接口 {} 无响应".format(queryMyOrderNoCompleteUrl))
|
||||
|
||||
def initNoComplete(self):
|
||||
"""
|
||||
获取订单前需要进入订单列表页,获取订单列表页session
|
||||
:return:
|
||||
"""
|
||||
self.httpClint.set_cookies(acw_tc="AQAAAEnFJnekLwwAtGHjZZCr79B6dpXk", current_captcha_type="Z")
|
||||
initNoCompleteUrl = self.confUrl["initNoCompleteUrl"]
|
||||
data = {"_json_att": ""}
|
||||
self.httpClint.send(initNoCompleteUrl, data)
|
||||
|
||||
def cancelNoCompleteMyOrder(self, sequence_no):
|
||||
"""
|
||||
取消订单
|
||||
:param sequence_no: 订单编号
|
||||
:return:
|
||||
"""
|
||||
cancelNoCompleteMyOrderUrl = self.confUrl["cancelNoCompleteMyOrder"]
|
||||
cancelNoCompleteMyOrderData = {
|
||||
"sequence_no": sequence_no,
|
||||
"cancel_flag": "cancel_order",
|
||||
"_json_att": ""
|
||||
}
|
||||
cancelNoCompleteMyOrderResult = self.httpClint.send(cancelNoCompleteMyOrderUrl, cancelNoCompleteMyOrderData)
|
||||
if "data" in cancelNoCompleteMyOrderResult and "existError" in cancelNoCompleteMyOrderResult["data"] and cancelNoCompleteMyOrderResult["data"]["existError"] == "N":
|
||||
print(u"排队超时,已为您自动取消订单,订单编号: {0}".format(sequence_no))
|
||||
time.sleep(2)
|
||||
return True
|
||||
else:
|
||||
print(u"排队超时,取消订单失败, 订单号{0}".format(sequence_no))
|
||||
|
||||
def set_cdn(self):
|
||||
"""
|
||||
设置cdn
|
||||
:return:
|
||||
"""
|
||||
if self.is_cdn == 1:
|
||||
while True:
|
||||
if self.cdn_list:
|
||||
self.httpClint.cdn = self.cdn_list[random.randint(0, len(self.cdn_list)-1)]
|
||||
break
|
||||
else:
|
||||
pass
|
||||
|
||||
def call_login(self, auth=False):
|
||||
"""
|
||||
登录回调方法
|
||||
|
@ -676,67 +110,96 @@ class select:
|
|||
else:
|
||||
self.login.go_login()
|
||||
|
||||
def cdn_req(self, cdn):
|
||||
for i in range(len(cdn)-1):
|
||||
http = HTTPClient()
|
||||
urls = self.confUrl["loginInit"]
|
||||
start_time = datetime.datetime.now()
|
||||
http.cdn = cdn[i].replace("\n", "")
|
||||
rep = http.send(urls)
|
||||
if rep and "message" not in rep and (datetime.datetime.now() - start_time).microseconds / 1000 < 200:
|
||||
self.cdn_list.append(cdn[i].replace("\n", ""))
|
||||
print(u"所有cdn解析完成...")
|
||||
|
||||
def cdn_certification(self):
|
||||
"""
|
||||
cdn 认证
|
||||
:return:
|
||||
"""
|
||||
if self.is_cdn == 1:
|
||||
CDN = CDNProxy()
|
||||
all_cdn = CDN.all_cdn()
|
||||
if all_cdn:
|
||||
print(u"开启cdn查询")
|
||||
print(u"本次待筛选cdn总数为{}".format(len(all_cdn)))
|
||||
t = threading.Thread(target=self.cdn_req, args=(all_cdn,))
|
||||
t.start()
|
||||
else:
|
||||
raise ticketConfigException(u"cdn列表为空,请先加载cdn")
|
||||
else:
|
||||
pass
|
||||
|
||||
def main(self):
|
||||
self.cdn_certification()
|
||||
self.set_cdn()
|
||||
l = liftTicketInit(session=self)
|
||||
l.reqLiftTicketInit()
|
||||
self.call_login()
|
||||
checkUser(self).sendCheckUser()
|
||||
from_station, to_station = self.station_table(self.from_station, self.to_station)
|
||||
self.check_user()
|
||||
time.sleep(0.1)
|
||||
num = 1
|
||||
while 1:
|
||||
try:
|
||||
num += 1
|
||||
if "user_time" in self.is_check_user and (datetime.datetime.now() - self.is_check_user["user_time"]).seconds/60 > 5:
|
||||
# 5分钟检查一次用户是否登录
|
||||
self.check_user()
|
||||
checkUser(self).sendCheckUser()
|
||||
time.sleep(self.select_refresh_interval)
|
||||
if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00" or time.strftime('%H:%M:%S', time.localtime(time.time())) < "06:00:00":
|
||||
print(u"12306休息时间,本程序自动停止,明天早上6点将自动运行")
|
||||
if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00" or time.strftime('%H:%M:%S',
|
||||
time.localtime(
|
||||
time.time())) < "06:00:00":
|
||||
print(ticket.REST_TIME)
|
||||
while 1:
|
||||
time.sleep(1)
|
||||
if time.strftime('%H:%M:%S', time.localtime(time.time())) > "06:00:00":
|
||||
print(u"休息时间已过,重新开启检票功能")
|
||||
if "06:00:00" < time.strftime('%H:%M:%S', time.localtime(time.time())) < "23:00:00":
|
||||
print(ticket.REST_TIME_PAST)
|
||||
self.call_login()
|
||||
break
|
||||
start_time = datetime.datetime.now()
|
||||
self.submitOrderRequestImplement(from_station, to_station)
|
||||
print u"正在第{0}次查询 乘车日期: {1} 车次{2} 查询无票 cdn轮询IP {4} 当前cdn总数{5} 总耗时{3}ms".format(num,
|
||||
",".join(self.station_dates),
|
||||
",".join(self.station_trains),
|
||||
(datetime.datetime.now()-start_time).microseconds/1000,
|
||||
self.httpClint.cdn,
|
||||
len(self.cdn_list))
|
||||
self.set_cdn()
|
||||
|
||||
q = query(session=self,
|
||||
from_station=from_station,
|
||||
to_station=to_station,
|
||||
from_station_h=self.from_station,
|
||||
to_station_h=self.to_station,
|
||||
_station_seat=self._station_seat,
|
||||
station_trains=self.station_trains,
|
||||
station_dates=self.station_dates, )
|
||||
queryResult = q.sendQuery()
|
||||
# 查询接口
|
||||
if queryResult.get("status", False):
|
||||
train_no = queryResult.get("train_no", "")
|
||||
train_date = queryResult.get("train_date", "")
|
||||
stationTrainCode = queryResult.get("stationTrainCode", "")
|
||||
set_type = queryResult.get("set_type", "")
|
||||
secretStr = queryResult.get("secretStr", "")
|
||||
leftTicket = queryResult.get("leftTicket", "")
|
||||
query_from_station_name = queryResult.get("query_from_station_name", "")
|
||||
query_to_station_name = queryResult.get("query_to_station_name", "")
|
||||
if wrapcache.get(train_no):
|
||||
print(ticket.QUEUE_WARNING_MSG.format(train_no))
|
||||
else:
|
||||
# 获取联系人
|
||||
if not self.passengerTicketStrList and not self.oldPassengerStr:
|
||||
s = getPassengerDTOs(session=self, ticket_peoples=self.ticke_peoples, set_type=set_type)
|
||||
getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr()
|
||||
if getPassengerDTOsResult.get("status", False):
|
||||
self.passengerTicketStrList = getPassengerDTOsResult.get("passengerTicketStrList", "")
|
||||
self.oldPassengerStr = getPassengerDTOsResult.get("oldPassengerStr", "")
|
||||
set_type = getPassengerDTOsResult.get("set_type", "")
|
||||
# 提交订单
|
||||
if self.order_type == 1: # 快读下单
|
||||
a = autoSubmitOrderRequest(session=self,
|
||||
secretStr=secretStr,
|
||||
train_date=train_date,
|
||||
passengerTicketStr=self.passengerTicketStrList,
|
||||
oldPassengerStr=self.oldPassengerStr,
|
||||
train_no=train_no,
|
||||
stationTrainCode=stationTrainCode,
|
||||
leftTicket=leftTicket,
|
||||
set_type=set_type,
|
||||
query_from_station_name=query_from_station_name,
|
||||
query_to_station_name=query_to_station_name,
|
||||
)
|
||||
a.sendAutoSubmitOrderRequest()
|
||||
elif self.order_type == 2: # 普通下单
|
||||
sor = submitOrderRequest(self, secretStr, from_station, to_station, train_no, set_type,
|
||||
self.passengerTicketStrList, self.oldPassengerStr, train_date,
|
||||
self.ticke_peoples)
|
||||
sor.sendSubmitOrderRequest()
|
||||
|
||||
|
||||
else:
|
||||
s_time = random.randint(0, 4)
|
||||
time.sleep(s_time)
|
||||
print u"正在第{0}次查询 随机停留时长:{6} 乘车日期: {1} 车次:{2} 查询无票 cdn轮询IP:{4}当前cdn总数:{5} 总耗时:{3}ms".format(num,
|
||||
",".join(
|
||||
self.station_dates),
|
||||
",".join(
|
||||
self.station_trains),
|
||||
(
|
||||
datetime.datetime.now() - start_time).microseconds / 1000,
|
||||
self.httpClint.cdn,
|
||||
len(
|
||||
self.cdn_list),
|
||||
s_time)
|
||||
except PassengerUserException as e:
|
||||
print e.message
|
||||
break
|
||||
|
@ -766,6 +229,4 @@ class select:
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
login()
|
||||
# a = select('上海', '北京')
|
||||
# a.main()
|
||||
pass
|
|
@ -3,6 +3,10 @@ import urllib
|
|||
from collections import OrderedDict
|
||||
|
||||
from config.TicketEnmu import ticket
|
||||
from config.ticketConf import _get_yaml
|
||||
from inter.CheckRandCodeAnsyn import checkRandCodeAnsyn
|
||||
from inter.GetQueueCountAsync import getQueueCountAsync
|
||||
from inter.GetRandCode import getRandCode
|
||||
|
||||
|
||||
class autoSubmitOrderRequest:
|
||||
|
@ -15,7 +19,11 @@ class autoSubmitOrderRequest:
|
|||
query_from_station_name,
|
||||
query_to_station_name,
|
||||
passengerTicketStr,
|
||||
oldPassengerStr):
|
||||
oldPassengerStr,
|
||||
train_no,
|
||||
stationTrainCode,
|
||||
leftTicket,
|
||||
set_type,):
|
||||
self.secretStr = urllib.unquote(secretStr)
|
||||
self.train_date = train_date
|
||||
self.query_from_station_name = query_from_station_name
|
||||
|
@ -23,6 +31,10 @@ class autoSubmitOrderRequest:
|
|||
self.passengerTicketStr = passengerTicketStr
|
||||
self.oldPassengerStr = oldPassengerStr
|
||||
self.session = session
|
||||
self.train_no = train_no
|
||||
self.stationTrainCode = stationTrainCode
|
||||
self.leftTicket = leftTicket
|
||||
self.set_type = set_type
|
||||
|
||||
def data_par(self):
|
||||
"""
|
||||
|
@ -46,8 +58,8 @@ class autoSubmitOrderRequest:
|
|||
data["train_date"] = self.train_date
|
||||
data["tour_flag"] = "dc"
|
||||
data["purpose_codes"] = "ADULT"
|
||||
data["query_from_station_name"] = self.query_from_station_name
|
||||
data["query_to_station_name"] = self.query_to_station_name
|
||||
data["query_from_station_name"] = self.session.from_station
|
||||
data["query_to_station_name"] = self.session.to_station
|
||||
data["cancel_flag"] = 2
|
||||
data["bed_level_order_num"] = "000000000000000000000000000000"
|
||||
data["passengerTicketStr"] = self.passengerTicketStr
|
||||
|
@ -69,40 +81,42 @@ class autoSubmitOrderRequest:
|
|||
if requestResultData:
|
||||
result = requestResultData.get("result", "")
|
||||
ifShowPassCode = requestResultData.get("ifShowPassCode", "N")
|
||||
ifShowPassCodeTime = int(requestResultData.get("ifShowPassCodeTime", "1000")) / float(1000)
|
||||
print(ticket.AUTO_SUBMIT_ORDER_REQUEST_C)
|
||||
g = getQueueCountAsync(session=self.session,
|
||||
train_no=self.train_no,
|
||||
stationTrainCode=self.stationTrainCode,
|
||||
fromStationTelecode=self.query_from_station_name,
|
||||
toStationTelecode=self.query_to_station_name,
|
||||
leftTicket=self.leftTicket,
|
||||
set_type=self.set_type,
|
||||
users=len(self.session.ticke_peoples),
|
||||
station_dates=self.train_date,
|
||||
passengerTicketStr=self.passengerTicketStr,
|
||||
oldPassengerStr=self.oldPassengerStr,
|
||||
result=result,
|
||||
ifShowPassCodeTime=ifShowPassCodeTime,
|
||||
)
|
||||
g.sendGetQueueCountAsync()
|
||||
if ifShowPassCode == "Y": # 如果需要验证码
|
||||
print(ticket.AUTO_SUBMIT_NEED_CODE)
|
||||
return {
|
||||
"result": result,
|
||||
"ifShowPassCode": ifShowPassCode,
|
||||
"code": ticket.SUCCESS_CODE,
|
||||
"ifShowPassCodeTime": requestResultData.get("requestResultData", 2000) / float(1000),
|
||||
"status": True,
|
||||
}
|
||||
else:
|
||||
print(ticket.AUTO_SUBMIT_NOT_NEED_CODE)
|
||||
return {
|
||||
"result": result,
|
||||
"ifShowPassCode": ifShowPassCode,
|
||||
"code": ticket.SUCCESS_CODE,
|
||||
"ifShowPassCodeTime": requestResultData.get("requestResultData", 2000) / float(1000),
|
||||
"status": True,
|
||||
}
|
||||
print(u"需要验证码")
|
||||
print(u"正在使用自动识别验证码功能")
|
||||
for i in range(3):
|
||||
randCode = getRandCode(is_auto_code=True, auto_code_type=_get_yaml()["auto_code_type"])
|
||||
checkcode = checkRandCodeAnsyn(self.session, randCode, "")
|
||||
if checkcode == 'TRUE':
|
||||
print(u"验证码通过,正在提交订单")
|
||||
data['randCode'] = randCode
|
||||
break
|
||||
else:
|
||||
print (u"验证码有误, {0}次尝试重试".format(i + 1))
|
||||
print(u"验证码超过限定次数3次,放弃此次订票机会!")
|
||||
g.sendGetQueueCountAsync()
|
||||
else:
|
||||
print(ticket.AUTO_SUBMIT_ORDER_REQUEST_F)
|
||||
if autoSubmitOrderRequestResult.get("messages", ""):
|
||||
print(autoSubmitOrderRequestResult.get("messages", ""))
|
||||
return {
|
||||
"code": ticket.FAIL_CODE,
|
||||
"status": False,
|
||||
}
|
||||
elif autoSubmitOrderRequestResult.get("validateMessages", ""):
|
||||
print(autoSubmitOrderRequestResult.get("validateMessages", ""))
|
||||
return {
|
||||
"code": ticket.FAIL_CODE,
|
||||
"status": False,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
# coding=utf-8
|
||||
from collections import OrderedDict
|
||||
from inter.GetQueueCount import getQueueCount
|
||||
from inter.GetRepeatSubmitToken import getRepeatSubmitToken
|
||||
|
||||
|
||||
class checkOrderInfo:
|
||||
|
||||
def __init__(self, session, train_no, set_type, passengerTicketStrList, oldPassengerStr, station_dates, ticket_peoples):
|
||||
self.train_no = train_no
|
||||
self.set_type = set_type
|
||||
self.passengerTicketStrList = passengerTicketStrList
|
||||
self.oldPassengerStr = oldPassengerStr
|
||||
self.station_dates = station_dates
|
||||
self.ticket_peoples = ticket_peoples
|
||||
self.RepeatSubmitToken = getRepeatSubmitToken(session)
|
||||
self.getTicketInfoForPassengerForm = self.RepeatSubmitToken.sendGetRepeatSubmitToken()
|
||||
self.ticketInfoForPassengerForm = self.getTicketInfoForPassengerForm.get("ticketInfoForPassengerForm", "")
|
||||
self.token = self.getTicketInfoForPassengerForm.get("token", "")
|
||||
self.session = self.getTicketInfoForPassengerForm.get("session", "")
|
||||
|
||||
def data_par(self):
|
||||
"""
|
||||
参数结构
|
||||
:return:
|
||||
"""
|
||||
data = OrderedDict()
|
||||
data['passengerTicketStr'] = self.passengerTicketStrList.rstrip("_{0}".format(self.set_type))
|
||||
data['oldPassengerStr'] = self.oldPassengerStr
|
||||
data['REPEAT_SUBMIT_TOKEN'] = self.token
|
||||
data['randCode'] = ""
|
||||
data['cancel_flag'] = 2
|
||||
data['bed_level_order_num'] = "000000000000000000000000000000"
|
||||
data['tour_flag'] = 'dc'
|
||||
data['_json_att'] = ""
|
||||
return data
|
||||
|
||||
def sendCheckOrderInfo(self):
|
||||
"""
|
||||
检查支付订单,需要提交REPEAT_SUBMIT_TOKEN
|
||||
passengerTicketStr : 座位编号,0,票类型,乘客名,证件类型,证件号,手机号码,保存常用联系人(Y或N)
|
||||
oldPassengersStr: 乘客名,证件类型,证件号,乘客类型
|
||||
:return:
|
||||
"""
|
||||
CheckOrderInfoUrls = self.session.urls["checkOrderInfoUrl"]
|
||||
data = self.data_par()
|
||||
checkOrderInfoRep = self.session.httpClint.send(CheckOrderInfoUrls, data)
|
||||
if 'data' in checkOrderInfoRep:
|
||||
print (u'车票提交通过,正在尝试排队')
|
||||
ifShowPassCodeTime = int(checkOrderInfoRep["data"]["ifShowPassCodeTime"]) / float(1000)
|
||||
if "ifShowPassCode" in checkOrderInfoRep["data"] and checkOrderInfoRep["data"]["ifShowPassCode"] == "Y":
|
||||
is_need_code = True
|
||||
elif "ifShowPassCode" in checkOrderInfoRep["data"] and checkOrderInfoRep['data']['submitStatus'] is True:
|
||||
is_need_code = False
|
||||
else:
|
||||
is_need_code = False
|
||||
QueueCount = getQueueCount(self.session,
|
||||
is_need_code,
|
||||
ifShowPassCodeTime,
|
||||
self.set_type,
|
||||
self.station_dates,
|
||||
self.train_no,
|
||||
self.ticket_peoples,
|
||||
self.ticketInfoForPassengerForm,
|
||||
self.token,
|
||||
self.oldPassengerStr,
|
||||
self.passengerTicketStrList,
|
||||
)
|
||||
QueueCount.sendGetQueueCount()
|
||||
elif "errMsg" in checkOrderInfoRep['data'] and checkOrderInfoRep['data']["errMsg"]:
|
||||
print checkOrderInfoRep['data']["errMsg"]
|
||||
elif 'messages' in checkOrderInfoRep and checkOrderInfoRep['messages']:
|
||||
print (checkOrderInfoRep['messages'][0])
|
|
@ -0,0 +1,27 @@
|
|||
# coding=utf-8
|
||||
class checkRandCodeAnsyn:
|
||||
def __init__(self, session, randCode, token):
|
||||
self.session = session
|
||||
self.randCode = randCode
|
||||
self.token = token
|
||||
|
||||
def data_par(self):
|
||||
"""
|
||||
:return:
|
||||
"""
|
||||
data = {
|
||||
"randCode": self.randCode,
|
||||
"rand": "randp",
|
||||
"_json_att": "",
|
||||
"REPEAT_SUBMIT_TOKEN": self.token
|
||||
}
|
||||
return data
|
||||
|
||||
def sendCheckRandCodeAnsyn(self):
|
||||
"""
|
||||
下单验证码识别
|
||||
:return:
|
||||
"""
|
||||
checkRandCodeAnsynUrl = self.session.urls["checkRandCodeAnsyn"]
|
||||
fresult = self.session.httpClint.send(checkRandCodeAnsynUrl, self.data_par()) # 校验验证码是否正确
|
||||
return fresult['data']['msg']
|
|
@ -0,0 +1,33 @@
|
|||
# coding=utf-8
|
||||
import datetime
|
||||
import wrapcache
|
||||
|
||||
from config.TicketEnmu import ticket
|
||||
|
||||
|
||||
class checkUser:
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
def sendCheckUser(self):
|
||||
"""
|
||||
检查用户登录, 检查间隔为五分钟
|
||||
:return:
|
||||
"""
|
||||
if wrapcache.get("user_time") is None:
|
||||
check_user_url = self.session.urls["check_user_url"]
|
||||
data = {"_json_att": ""}
|
||||
check_user = self.session.httpClint.send(check_user_url, data)
|
||||
if check_user.get("data", False):
|
||||
check_user_flag = check_user["data"]["flag"]
|
||||
if check_user_flag is True:
|
||||
wrapcache.set("user_time", datetime.datetime.now(), timeout=60 * 5)
|
||||
else:
|
||||
if check_user['messages']:
|
||||
print (ticket.LOGIN_SESSION_FAIL.format(check_user['messages']))
|
||||
self.session.call_login()
|
||||
wrapcache.set("user_time", datetime.datetime.now(), timeout=60 * 5)
|
||||
else:
|
||||
print (ticket.LOGIN_SESSION_FAIL.format(check_user['messages']))
|
||||
self.session.call_login()
|
||||
wrapcache.set("user_time", datetime.datetime.now(), timeout=60 * 5)
|
|
@ -0,0 +1,96 @@
|
|||
# coding=utf-8
|
||||
import datetime
|
||||
import time
|
||||
|
||||
from config.ticketConf import _get_yaml
|
||||
from inter.CheckRandCodeAnsyn import checkRandCodeAnsyn
|
||||
from inter.GetPassengerDTOs import getPassengerDTOs
|
||||
from inter.GetRandCode import getRandCode
|
||||
from inter.QueryOrderWaitTime import queryOrderWaitTime
|
||||
|
||||
|
||||
class confirmSingleForQueue:
|
||||
def __init__(self, session, ifShowPassCodeTime, is_node_code, token, set_type, ticket_peoples, ticketInfoForPassengerForm,
|
||||
oldPassengerStr, passengerTicketStrList):
|
||||
self.session = session
|
||||
self.ifShowPassCodeTime = ifShowPassCodeTime
|
||||
self.is_node_code = is_node_code
|
||||
self.token = token
|
||||
self.set_type = set_type
|
||||
self.ticket_peoples = ticket_peoples
|
||||
self.ticketInfoForPassengerForm = ticketInfoForPassengerForm
|
||||
self.passengerTicketStrList = passengerTicketStrList
|
||||
self.oldPassengerStr = oldPassengerStr
|
||||
|
||||
def data_par(self):
|
||||
"""
|
||||
模拟提交订单是确认按钮,参数获取方法还是get_ticketInfoForPassengerForm 中获取
|
||||
:return:
|
||||
"""
|
||||
if not self.passengerTicketStrList and not self.oldPassengerStr:
|
||||
s = getPassengerDTOs(session=self.session, ticket_peoples=self.ticket_peoples, set_type=self.set_type)
|
||||
getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr()
|
||||
if getPassengerDTOsResult.get("status", False):
|
||||
self.passengerTicketStrList = getPassengerDTOsResult.get("passengerTicketStrList", "")
|
||||
self.oldPassengerStr = getPassengerDTOsResult.get("oldPassengerStr", "")
|
||||
data = {
|
||||
"passengerTicketStr": self.passengerTicketStrList.rstrip("_{0}".format(self.set_type)),
|
||||
"oldPassengerStr": "".join(self.oldPassengerStr),
|
||||
"purpose_codes": self.ticketInfoForPassengerForm["purpose_codes"],
|
||||
"key_check_isChange": self.ticketInfoForPassengerForm["key_check_isChange"],
|
||||
"leftTicketStr": self.ticketInfoForPassengerForm["leftTicketStr"],
|
||||
"train_location": self.ticketInfoForPassengerForm["train_location"],
|
||||
"seatDetailType": "", # 开始需要选择座位,但是目前12306不支持自动选择作为,那这个参数为默认
|
||||
"roomType": "00", # 好像是根据一个id来判断选中的,两种 第一种是00,第二种是10,但是我在12306的页面没找到该id,目前写死是00,不知道会出什么错
|
||||
"dwAll": "N",
|
||||
"whatsSelect": 1,
|
||||
"_json_at": "",
|
||||
"randCode": "",
|
||||
"choose_seats": "",
|
||||
"REPEAT_SUBMIT_TOKEN": self.token,
|
||||
}
|
||||
return data
|
||||
|
||||
def sendConfirmSingleForQueue(self):
|
||||
"""
|
||||
# 模拟查询当前的列车排队人数的方法
|
||||
# 返回信息组成的提示字符串
|
||||
:return:
|
||||
"""
|
||||
data = self.data_par()
|
||||
checkQueueOrderUrl = self.session.urls["checkQueueOrderUrl"]
|
||||
try:
|
||||
if self.is_node_code:
|
||||
print(u"正在使用自动识别验证码功能")
|
||||
for i in range(3):
|
||||
randCode = getRandCode(is_auto_code=True, auto_code_type=_get_yaml()["auto_code_type"])
|
||||
checkcode = checkRandCodeAnsyn(self.session, randCode, self.token)
|
||||
if checkcode == 'TRUE':
|
||||
print(u"验证码通过,正在提交订单")
|
||||
data['randCode'] = randCode
|
||||
break
|
||||
else:
|
||||
print (u"验证码有误, {0}次尝试重试".format(i + 1))
|
||||
print(u"验证码超过限定次数3次,放弃此次订票机会!")
|
||||
else:
|
||||
print(u"不需要验证码")
|
||||
time.sleep(self.ifShowPassCodeTime)
|
||||
checkQueueOrderResult = self.session.httpClint.send(checkQueueOrderUrl, data)
|
||||
if "status" in checkQueueOrderResult and checkQueueOrderResult["status"]:
|
||||
c_data = checkQueueOrderResult["data"] if "data" in checkQueueOrderResult else {}
|
||||
if 'submitStatus' in c_data and c_data['submitStatus'] is True:
|
||||
print(u"提交订单成功!")
|
||||
qow = queryOrderWaitTime(self.session)
|
||||
qow.sendQueryOrderWaitTime()
|
||||
else:
|
||||
if 'errMsg' in c_data and c_data['errMsg']:
|
||||
print(u"提交订单失败,{0}".format(c_data['errMsg']))
|
||||
else:
|
||||
print(c_data)
|
||||
print(u'订票失败!很抱歉,请重试提交预订功能!')
|
||||
elif "messages" in checkQueueOrderResult and checkQueueOrderResult["messages"]:
|
||||
print(u"提交订单失败,错误信息: " + checkQueueOrderResult["messages"])
|
||||
else:
|
||||
print(u"提交订单中,请耐心等待:" + checkQueueOrderResult["message"])
|
||||
except ValueError:
|
||||
print(u"接口 {} 无响应".format(checkQueueOrderUrl))
|
|
@ -3,6 +3,8 @@ import json
|
|||
import urllib
|
||||
from collections import OrderedDict
|
||||
|
||||
from inter.QueryOrderWaitTime import queryOrderWaitTime
|
||||
|
||||
|
||||
class confirmSingleForQueueAsys:
|
||||
"""
|
||||
|
@ -64,15 +66,7 @@ class confirmSingleForQueueAsys:
|
|||
if confirmSingleForQueueAsysResult.get("status", False) and confirmSingleForQueueAsysResult.get("data", False):
|
||||
queueData = confirmSingleForQueueAsysResult.get("data", {})
|
||||
if queueData.get("submitStatus", False):
|
||||
return {
|
||||
"status": True
|
||||
}
|
||||
qwt = queryOrderWaitTime(session=self.session)
|
||||
qwt.sendQueryOrderWaitTime()
|
||||
else:
|
||||
print(queueData.get("errMsg", ""))
|
||||
return {
|
||||
"status": False
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"status": False
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
# coding=utf-8
|
||||
|
||||
|
||||
def getPassCodeNewOrderAndLogin(session, imgType):
|
||||
"""
|
||||
下载验证码
|
||||
:param session:
|
||||
:param imgType: 下载验证码类型,login=登录验证码,其余为订单验证码
|
||||
:return:
|
||||
"""
|
||||
if imgType == "login":
|
||||
codeImgUrl = session.urls["getCodeImg"]
|
||||
else:
|
||||
codeImgUrl = session.urls["codeImgByOrder"]
|
||||
print (u"下载验证码...")
|
||||
img_path = './tkcode'
|
||||
result = session.httpClint.send(codeImgUrl)
|
||||
try:
|
||||
print(u"下载验证码成功")
|
||||
open(img_path, 'wb').write(result)
|
||||
except OSError as e:
|
||||
print (e)
|
|
@ -56,7 +56,7 @@ class getPassengerDTOs:
|
|||
"""
|
||||
获取提交车次人内容格式
|
||||
passengerTicketStr O,0,1,文贤平,1,43052419950223XXXX,15618715583,N_O,0,1,梁敏,1,43052719920118XXXX,,N
|
||||
oldPassengerStr 文贤平,1,43052719920118XXXX,1_梁敏,1,43052719920118XXXX,1_
|
||||
oldPassengerStr 文贤平,1,43052719920118XXXX,1_梁敏,1,43052719920118XXXX,1
|
||||
:return:
|
||||
"""
|
||||
passengerTicketStrList = []
|
||||
|
@ -89,4 +89,5 @@ class getPassengerDTOs:
|
|||
"code": ticket.SUCCESS_CODE,
|
||||
"set_type": set_type,
|
||||
"status": True,
|
||||
"user_info": user_info,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
# coding=utf-8
|
||||
import datetime
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
import wrapcache
|
||||
|
||||
from config.ticketConf import _get_yaml
|
||||
from inter.ConfirmSingleForQueue import confirmSingleForQueue
|
||||
|
||||
|
||||
def conversion_int(str):
|
||||
return int(str)
|
||||
|
||||
|
||||
class getQueueCount:
|
||||
def __init__(self, session, is_need_code, ifShowPassCodeTime, set_type, station_dates, train_no, ticket_peoples,
|
||||
ticketInfoForPassengerForm, token, oldPassengerStr, passengerTicketStrList):
|
||||
self.station_dates = station_dates
|
||||
self.session = session
|
||||
self.is_need_code = is_need_code
|
||||
self.ifShowPassCodeTime = ifShowPassCodeTime
|
||||
self.set_type = set_type
|
||||
self.train_no = train_no
|
||||
self.ticket_peoples = ticket_peoples
|
||||
self.ticket_black_list = {}
|
||||
self.ticketInfoForPassengerForm = ticketInfoForPassengerForm
|
||||
self.token = token
|
||||
self.oldPassengerStr = oldPassengerStr
|
||||
self.passengerTicketStrList = passengerTicketStrList
|
||||
|
||||
def data_par(self):
|
||||
"""
|
||||
参数结构
|
||||
自动提交代码接口-autoSubmitOrderRequest
|
||||
- 字段说明
|
||||
- secretStr 车票代码
|
||||
- train_date 乘车日期
|
||||
- tour_flag 乘车类型
|
||||
- purpose_codes 学生还是成人
|
||||
- query_from_station_name 起始车站
|
||||
- query_to_station_name 结束车站
|
||||
- cancel_flag 默认2,我也不知道干嘛的
|
||||
- bed_level_order_num 000000000000000000000000000000
|
||||
- passengerTicketStr 乘客乘车代码
|
||||
- oldPassengerStr 乘客编号代码
|
||||
:return:
|
||||
"""
|
||||
|
||||
new_train_date = filter(None, str(time.asctime(time.strptime(self.station_dates, "%Y-%m-%d"))).split(" "))
|
||||
data = OrderedDict()
|
||||
data['train_date'] = "{0} {1} 0{2} {3} 00:00:00 GMT+0800 (中国标准时间)".format(
|
||||
new_train_date[0],
|
||||
new_train_date[1],
|
||||
new_train_date[2],
|
||||
new_train_date[4],
|
||||
),
|
||||
data['train_no'] = self.ticketInfoForPassengerForm['queryLeftTicketRequestDTO']['train_no'],
|
||||
data['stationTrainCode'] = self.ticketInfoForPassengerForm['queryLeftTicketRequestDTO'][
|
||||
'station_train_code'],
|
||||
data['seatType'] = self.set_type,
|
||||
data['fromStationTelecode'] = self.ticketInfoForPassengerForm['queryLeftTicketRequestDTO'][
|
||||
'from_station'],
|
||||
data['toStationTelecode'] = self.ticketInfoForPassengerForm['queryLeftTicketRequestDTO']['to_station'],
|
||||
data['leftTicket'] = self.ticketInfoForPassengerForm['leftTicketStr'],
|
||||
data['purpose_codes'] = self.ticketInfoForPassengerForm['purpose_codes'],
|
||||
data['train_location'] = self.ticketInfoForPassengerForm['train_location'],
|
||||
data['REPEAT_SUBMIT_TOKEN'] = self.token,
|
||||
return data
|
||||
|
||||
def sendGetQueueCount(self):
|
||||
"""
|
||||
# 模拟查询当前的列车排队人数的方法
|
||||
# 返回信息组成的提示字符串
|
||||
:return:
|
||||
"""
|
||||
getQueueCountResult = self.session.httpClint.send(self.session.urls["getQueueCountUrl"], self.data_par())
|
||||
if "status" in getQueueCountResult and getQueueCountResult["status"] is True:
|
||||
if "countT" in getQueueCountResult["data"]:
|
||||
ticket = getQueueCountResult["data"]["ticket"]
|
||||
ticket_split = sum(map(conversion_int, ticket.split(","))) if ticket.find(",") != -1 else ticket
|
||||
countT = getQueueCountResult["data"]["countT"]
|
||||
if int(countT) is 0:
|
||||
if int(ticket_split) < len(self.ticket_peoples):
|
||||
print(u"当前余票数小于乘车人数,放弃订票")
|
||||
else:
|
||||
print(u"排队成功, 当前余票还剩余: {0} 张".format(ticket_split))
|
||||
csf = confirmSingleForQueue(self.session, self.ifShowPassCodeTime, self.is_need_code, self.token,
|
||||
self.set_type, self.ticket_peoples, self.ticketInfoForPassengerForm,
|
||||
self.oldPassengerStr, self.passengerTicketStrList)
|
||||
csf.sendConfirmSingleForQueue()
|
||||
else:
|
||||
print(u"当前排队人数: {1} 当前余票还剩余:{0} 张,继续排队中".format(ticket_split, countT))
|
||||
else:
|
||||
print(u"排队发现未知错误{0},将此列车 {1}加入小黑屋".format(getQueueCountResult, self.train_no))
|
||||
wrapcache.set(key=self.train_no, value=datetime.datetime.now(),
|
||||
timeout=int(_get_yaml()["ticket_black_list_time"]) * 60)
|
||||
elif "messages" in getQueueCountResult and getQueueCountResult["messages"]:
|
||||
print(u"排队异常,错误信息:{0}, 将此列车 {1}加入小黑屋".format(getQueueCountResult["messages"][0], self.train_no))
|
||||
wrapcache.set(key=self.train_no, value=datetime.datetime.now(), timeout=int(_get_yaml()["ticket_black_list_time"]) * 60)
|
||||
else:
|
||||
if "validateMessages" in getQueueCountResult and getQueueCountResult["validateMessages"]:
|
||||
print(str(getQueueCountResult["validateMessages"]))
|
||||
wrapcache.set(key=self.train_no, value=datetime.datetime.now(),
|
||||
timeout=int(_get_yaml()["ticket_black_list_time"]) * 60)
|
||||
else:
|
||||
print(u"未知错误 {0}".format("".join(getQueueCountResult)))
|
||||
|
||||
|
||||
|
|
@ -1,8 +1,13 @@
|
|||
# coding=utf-8
|
||||
import datetime
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
|
||||
import wrapcache
|
||||
|
||||
from config.TicketEnmu import ticket
|
||||
from config.ticketConf import _get_yaml
|
||||
from inter.ConfirmSingleForQueueAsys import confirmSingleForQueueAsys
|
||||
|
||||
|
||||
class getQueueCountAsync:
|
||||
|
@ -17,7 +22,12 @@ class getQueueCountAsync:
|
|||
toStationTelecode,
|
||||
leftTicket,
|
||||
set_type,
|
||||
users,):
|
||||
users,
|
||||
station_dates,
|
||||
passengerTicketStr,
|
||||
oldPassengerStr,
|
||||
result,
|
||||
ifShowPassCodeTime):
|
||||
self.train_no = train_no
|
||||
self.session = session
|
||||
self.stationTrainCode = stationTrainCode
|
||||
|
@ -26,6 +36,11 @@ class getQueueCountAsync:
|
|||
self.set_type = set_type
|
||||
self.leftTicket = leftTicket
|
||||
self.users = users
|
||||
self.station_dates = station_dates
|
||||
self.passengerTicketStr = passengerTicketStr
|
||||
self.oldPassengerStr = oldPassengerStr
|
||||
self.result = result
|
||||
self.ifShowPassCodeTime=ifShowPassCodeTime
|
||||
|
||||
def data_par(self):
|
||||
"""
|
||||
|
@ -41,11 +56,15 @@ class getQueueCountAsync:
|
|||
- _json_att 没啥卵用,还是带上吧
|
||||
:return:
|
||||
"""
|
||||
l_time = time.localtime(time.time())
|
||||
new_train_date = time.strftime("%b %d %Y %H:%M:%S", l_time)
|
||||
new_train_date = filter(None, str(time.asctime(time.strptime(self.station_dates, "%Y-%m-%d"))).split(" "))
|
||||
data = OrderedDict()
|
||||
# data["train_date"] = "Fri " + str(new_train_date) + " GMT+0800 (CST)"
|
||||
data["train_date"] = "Fri Jun 21 2018 18:23:54 GMT+0800 (CST)"
|
||||
data['train_date'] = "{0} {1} {2} {3} 00:00:00 GMT+0800 (中国标准时间)".format(
|
||||
new_train_date[0],
|
||||
new_train_date[1],
|
||||
new_train_date[2],
|
||||
new_train_date[4],
|
||||
time.strftime("%H:%M:%S", time.localtime(time.time()))
|
||||
),
|
||||
data["train_no"] = self.train_no
|
||||
data["stationTrainCode"] = self.stationTrainCode
|
||||
data["seatType"] = self.set_type
|
||||
|
@ -76,27 +95,27 @@ class getQueueCountAsync:
|
|||
countT = getQueueCountAsyncResult["data"]["countT"]
|
||||
if int(countT) is 0:
|
||||
if int(ticket_split) < self.users:
|
||||
print(ticket.QUEUE_TICKET_SHORT)
|
||||
return {"status": False, "is_black": False}
|
||||
print(u"当前余票数小于乘车人数,放弃订票")
|
||||
else:
|
||||
print(ticket.QUEUE_TICKET_SUCCESS.format(ticket_split))
|
||||
return {"status": True, "is_black": False}
|
||||
else:
|
||||
return {"status": False, "is_black": True}
|
||||
print(u"排队成功, 当前余票还剩余: {0} 张".format(ticket_split))
|
||||
c = confirmSingleForQueueAsys(session=self.session,
|
||||
passengerTicketStr=self.passengerTicketStr,
|
||||
oldPassengerStr=self.oldPassengerStr,
|
||||
result=self.result,)
|
||||
print(u"验证码提交安全期,等待{}MS".format(self.ifShowPassCodeTime))
|
||||
time.sleep(self.ifShowPassCodeTime)
|
||||
c.sendConfirmSingleForQueueAsys()
|
||||
else:
|
||||
print(ticket.QUEUE_JOIN_BLACK.format(getQueueCountAsyncResult, self.train_no))
|
||||
return {"status": False, "is_black": True, "train_no": self.train_no}
|
||||
print(u"排队发现未知错误{0},将此列车 {1}加入小黑屋".format(getQueueCountAsyncResult, self.train_no))
|
||||
wrapcache.set(key=self.train_no, value=datetime.datetime.now(),
|
||||
timeout=int(_get_yaml()["ticket_black_list_time"]) * 60)
|
||||
elif "messages" in getQueueCountAsyncResult and getQueueCountAsyncResult["messages"]:
|
||||
print(ticket.QUEUE_WARNING_MSG.format(getQueueCountAsyncResult["messages"][0], self.train_no))
|
||||
return {"status": False, "is_black": True, "train_no": self.train_no}
|
||||
print(u"排队异常,错误信息:{0}, 将此列车 {1}加入小黑屋".format(getQueueCountAsyncResult["messages"][0], self.train_no))
|
||||
wrapcache.set(key=self.train_no, value=datetime.datetime.now(),
|
||||
timeout=int(_get_yaml()["ticket_black_list_time"]) * 60)
|
||||
else:
|
||||
if "validateMessages" in getQueueCountAsyncResult and getQueueCountAsyncResult["validateMessages"]:
|
||||
print(str(getQueueCountAsyncResult["validateMessages"]))
|
||||
return {"status": False, "is_black": False}
|
||||
else:
|
||||
return {"status": False, "is_black": False}
|
||||
else:
|
||||
return {"status": False, "is_black": False}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
# coding=utf-8
|
||||
from PIL import Image
|
||||
|
||||
from config.ticketConf import _get_yaml
|
||||
from damatuCode.ruokuai import RClient
|
||||
|
||||
|
||||
def getRandCode(is_auto_code, auto_code_type):
|
||||
"""
|
||||
识别验证码
|
||||
:return: 坐标
|
||||
"""
|
||||
try:
|
||||
if is_auto_code:
|
||||
if auto_code_type == 1:
|
||||
print(u"打码兔已关闭, 如需使用自动识别,请使用如果平台 auto_code_type == 2")
|
||||
return
|
||||
if auto_code_type == 2:
|
||||
rc = RClient(_get_yaml()["auto_code_account"]["uesr"], _get_yaml()["auto_code_account"]["pwd"])
|
||||
im = open('./tkcode', 'rb').read()
|
||||
Result = rc.rk_create(im, 6113)
|
||||
if "Result" in Result:
|
||||
return codexy(Ofset=",".join(list(Result["Result"])), is_raw_input=False)
|
||||
else:
|
||||
if "Error" in Result and Result["Error"]:
|
||||
print Result["Error"]
|
||||
return ""
|
||||
else:
|
||||
img = Image.open('./tkcode')
|
||||
img.show()
|
||||
return codexy()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def codexy(Ofset=None, is_raw_input=True):
|
||||
"""
|
||||
获取验证码
|
||||
:return: str
|
||||
"""
|
||||
if is_raw_input:
|
||||
Ofset = raw_input(u"请输入验证码: ")
|
||||
Ofset = Ofset.replace(",", ",")
|
||||
select = Ofset.split(',')
|
||||
post = []
|
||||
offsetsX = 0 # 选择的答案的left值,通过浏览器点击8个小图的中点得到的,这样基本没问题
|
||||
offsetsY = 0 # 选择的答案的top值
|
||||
for ofset in select:
|
||||
if ofset == '1':
|
||||
offsetsY = 46
|
||||
offsetsX = 42
|
||||
elif ofset == '2':
|
||||
offsetsY = 46
|
||||
offsetsX = 105
|
||||
elif ofset == '3':
|
||||
offsetsY = 45
|
||||
offsetsX = 184
|
||||
elif ofset == '4':
|
||||
offsetsY = 48
|
||||
offsetsX = 256
|
||||
elif ofset == '5':
|
||||
offsetsY = 36
|
||||
offsetsX = 117
|
||||
elif ofset == '6':
|
||||
offsetsY = 112
|
||||
offsetsX = 115
|
||||
elif ofset == '7':
|
||||
offsetsY = 114
|
||||
offsetsX = 181
|
||||
elif ofset == '8':
|
||||
offsetsY = 111
|
||||
offsetsX = 252
|
||||
else:
|
||||
pass
|
||||
post.append(offsetsX)
|
||||
post.append(offsetsY)
|
||||
randCode = str(post).replace(']', '').replace('[', '').replace("'", '').replace(' ', '')
|
||||
print(u"验证码识别坐标为{0}".format(randCode))
|
||||
return randCode
|
|
@ -0,0 +1,36 @@
|
|||
# coding=utf-8
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
class getRepeatSubmitToken:
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
def sendGetRepeatSubmitToken(self):
|
||||
"""
|
||||
获取提交车票请求token
|
||||
:return: token
|
||||
"""
|
||||
initdc_url = self.session.urls["initdc_url"]
|
||||
initdc_result = self.session.httpClint.send(initdc_url, )
|
||||
token_name = re.compile(r"var globalRepeatSubmitToken = '(\S+)'")
|
||||
ticketInfoForPassengerForm_name = re.compile(r'var ticketInfoForPassengerForm=(\{.+\})?')
|
||||
order_request_params_name = re.compile(r'var orderRequestDTO=(\{.+\})?')
|
||||
token = re.search(token_name, initdc_result).group(1)
|
||||
re_tfpf = re.findall(ticketInfoForPassengerForm_name, initdc_result)
|
||||
re_orp = re.findall(order_request_params_name, initdc_result)
|
||||
if re_tfpf:
|
||||
ticketInfoForPassengerForm = json.loads(re_tfpf[0].replace("'", '"'))
|
||||
else:
|
||||
ticketInfoForPassengerForm = ""
|
||||
if re_orp:
|
||||
order_request_params = json.loads(re_orp[0].replace("'", '"'))
|
||||
else:
|
||||
order_request_params = ""
|
||||
return {
|
||||
"token": token,
|
||||
"ticketInfoForPassengerForm": ticketInfoForPassengerForm,
|
||||
"order_request_params": order_request_params,
|
||||
"session": self.session
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
# coding=utf-8
|
||||
import copy
|
||||
import datetime
|
||||
import random
|
||||
import time
|
||||
|
||||
import wrapcache
|
||||
from config.TicketEnmu import ticket
|
||||
|
||||
|
||||
|
@ -45,11 +43,9 @@ class query:
|
|||
查询
|
||||
:return:
|
||||
"""
|
||||
|
||||
for station_date in self.station_dates:
|
||||
select_url = copy.copy(self.session.urls["select_url"])
|
||||
select_url["req_url"] = select_url["req_url"].format(
|
||||
station_date, self.from_station, self.to_station)
|
||||
select_url["req_url"] = select_url["req_url"].format(station_date, self.from_station, self.to_station)
|
||||
station_ticket = self.session.httpClint.send(select_url)
|
||||
value = station_ticket.get("data", "")
|
||||
if not value:
|
||||
|
@ -62,52 +58,42 @@ class query:
|
|||
if ticket_info[11] == "Y" and ticket_info[1].encode("utf8") == "预订": # 筛选未在开始时间内的车次
|
||||
for j in xrange(len(self._station_seat)):
|
||||
is_ticket_pass = ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))]
|
||||
if is_ticket_pass != '' and is_ticket_pass != '无' and ticket_info[
|
||||
3] in self.station_trains and is_ticket_pass != '*': # 过滤有效目标车次
|
||||
if is_ticket_pass != '' and is_ticket_pass != '无' and ticket_info[3] in self.station_trains and is_ticket_pass != '*': # 过滤有效目标车次
|
||||
secretStr = ticket_info[0]
|
||||
train_no = ticket_info[2]
|
||||
query_from_station_name = ticket_info[6]
|
||||
query_to_station_name = ticket_info[7]
|
||||
train_location = ticket_info[15]
|
||||
stationTrainCode = ticket_info[3]
|
||||
train_date = station_date
|
||||
leftTicket = ticket_info[12]
|
||||
set_type = self._station_seat[j]
|
||||
print (u'车次: {0} 始发车站: {1} 终点站: {2} {3}: {4}'.format(train_no,
|
||||
self.from_station_h,
|
||||
self.to_station_h,
|
||||
self._station_seat[j].encode(
|
||||
"utf8"),
|
||||
ticket_info[self.station_seat(
|
||||
self._station_seat[
|
||||
j].encode("utf8"))]
|
||||
))
|
||||
if "train_no" in self.ticket_black_list and (
|
||||
datetime.datetime.now() - self.ticket_black_list[
|
||||
train_no]).seconds / 60 < int(ticket.TICKET_BLACK_LIST_TIME):
|
||||
self.from_station_h,
|
||||
self.to_station_h,
|
||||
self._station_seat[j].encode(
|
||||
"utf8"),
|
||||
ticket_info[self.station_seat(
|
||||
self._station_seat[
|
||||
j].encode("utf8"))]
|
||||
))
|
||||
if wrapcache.get(train_no):
|
||||
print(ticket.QUERY_IN_BLACK_LIST.format(train_no))
|
||||
break
|
||||
else:
|
||||
print (ticket.QUERY_C)
|
||||
# self.buy_ticket_time = datetime.datetime.now()
|
||||
return {
|
||||
"secretStr": secretStr,
|
||||
"train_no": train_no,
|
||||
"stationTrainCode": stationTrainCode,
|
||||
"train_date": train_date,
|
||||
"train_date": station_date,
|
||||
"query_from_station_name": query_from_station_name,
|
||||
"query_to_station_name": query_to_station_name,
|
||||
# "buy_ticket_time": self.buy_ticket_time,
|
||||
"set_type": set_type,
|
||||
"leftTicket": leftTicket,
|
||||
"train_location": train_location,
|
||||
"code": ticket.SUCCESS_CODE,
|
||||
"status": True,
|
||||
}
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
print u"车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket)
|
||||
return {"code": ticket.FAIL_CODE, "status": False}
|
||||
|
|
|
@ -89,7 +89,7 @@ class queryOrderWaitTime:
|
|||
else:
|
||||
return False
|
||||
else:
|
||||
print(u"接口 {} 无响应".format(queryMyOrderNoCompleteUrl))
|
||||
return False
|
||||
|
||||
def initNoComplete(self):
|
||||
"""
|
||||
|
@ -121,3 +121,4 @@ class queryOrderWaitTime:
|
|||
return True
|
||||
else:
|
||||
print(ticket.CANCEL_ORDER_FAIL.format(sequence_no))
|
||||
return False
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# coding=utf-8
|
||||
import datetime
|
||||
import urllib
|
||||
|
||||
from inter.CheckOrderInfo import checkOrderInfo
|
||||
from myException.ticketIsExitsException import ticketIsExitsException
|
||||
|
||||
|
||||
def time():
|
||||
"""
|
||||
获取日期
|
||||
:return:
|
||||
"""
|
||||
today = datetime.date.today()
|
||||
return today.strftime('%Y-%m-%d')
|
||||
|
||||
|
||||
class submitOrderRequest:
|
||||
def __init__(self, session, secretStr, from_station, to_station, train_no, set_type,
|
||||
passengerTicketStrList, oldPassengerStr, train_date, ticke_peoples):
|
||||
self.session = session
|
||||
self.secretStr = secretStr
|
||||
self.from_station = from_station
|
||||
self.to_station = to_station
|
||||
self.to_station = to_station
|
||||
self.train_no = train_no
|
||||
self.set_type = set_type
|
||||
self.passengerTicketStrList = passengerTicketStrList
|
||||
self.oldPassengerStr = oldPassengerStr
|
||||
self.train_date = train_date
|
||||
self.ticke_peoples = ticke_peoples
|
||||
|
||||
def data_apr(self):
|
||||
"""
|
||||
:return:
|
||||
"""
|
||||
data = [('secretStr', urllib.unquote(self.secretStr)), # 字符串加密
|
||||
('train_date', self.train_date), # 出发时间
|
||||
('back_train_date', time()), # 返程时间
|
||||
('tour_flag', 'dc'), # 旅途类型
|
||||
('purpose_codes', 'ADULT'), # 成人票还是学生票
|
||||
('query_from_station_name', self.from_station), # 起始车站
|
||||
('query_to_station_name', self.to_station), # 终点车站
|
||||
]
|
||||
return data
|
||||
|
||||
def sendSubmitOrderRequest(self):
|
||||
"""
|
||||
提交车次
|
||||
预定的请求参数,注意参数顺序
|
||||
注意这里为了防止secretStr被urllib.parse过度编码,在这里进行一次解码
|
||||
否则调用HttpTester类的post方法将会将secretStr编码成为无效码,造成提交预定请求失败
|
||||
:param self:
|
||||
:param secretStr: 提交车次加密
|
||||
:return:
|
||||
"""
|
||||
submit_station_url = self.session.urls["submit_station_url"]
|
||||
submitResult = self.session.httpClint.send(submit_station_url, self.data_apr())
|
||||
if 'data' in submitResult and submitResult['data']:
|
||||
if submitResult['data'] == 'N':
|
||||
print (u'出票成功')
|
||||
coi = checkOrderInfo(self.session, self.train_no, self.set_type, self.passengerTicketStrList,
|
||||
self.oldPassengerStr,
|
||||
self.train_date, self.ticke_peoples)
|
||||
coi.sendCheckOrderInfo()
|
||||
else:
|
||||
print (u'出票失败')
|
||||
elif 'messages' in submitResult and submitResult['messages']:
|
||||
raise ticketIsExitsException(submitResult['messages'][0])
|
|
@ -0,0 +1,202 @@
|
|||
# coding=utf-8
|
||||
import json
|
||||
import socket
|
||||
import re
|
||||
# s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# s.connect(('183.232.189.31', 80))
|
||||
# get_str = 'GET {0} HTTP/1.1\r\nConnection: close\r\n' \
|
||||
# 'Host: %s\r\n' \
|
||||
# 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36' \
|
||||
# '\r\nAccept: */*\r\n' \
|
||||
# '\r\n'
|
||||
# post_str = "POST {0} HTTP/1.1\r\n" \
|
||||
# "Host: kyfw.12306.cn\r\n" \
|
||||
# "Connection: close\r\n"\
|
||||
# "Origin: https://kyfw.12306.cn\r\n" \
|
||||
# "X-Requested-With: XMLHttpRequest\r\n" \
|
||||
# "Referer: https://kyfw.12306.cn/otn/leftTicket/init\r\n" \
|
||||
# "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n" \
|
||||
# "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n" \
|
||||
# "Accept: application/json, text/javascript, */*; q=0.01\r\n" \
|
||||
# "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5\r\n" \
|
||||
# "Content-Length: 9\r\n"\
|
||||
# "Cookie: _passport_session=a459aba69761497eb31de76c27795e999613; _passport_ct=9116b2cb0bf443e1a01d22ac8c1ae449t5007; route=9036359bb8a8a461c164a04f8f50b252; BIGipServerpool_passport=200081930.50215.0000; BIGipServerotn=484704778.64545.0000\r\n\n"\
|
||||
# "appid=otn\r\n"
|
||||
# # s.sendall(get_str.format("https://kyfw.12306.cn/otn/login/init"))
|
||||
# s.sendall(post_str.format("https://kyfw.12306.cn/passport/web/auth/uamtk"))
|
||||
from config.urlConf import urls
|
||||
|
||||
|
||||
def default_get_data():
|
||||
"""
|
||||
get请求默认组装字符串
|
||||
需要拼接的字符串
|
||||
-- url 发送请求的全连接
|
||||
:return:
|
||||
"""
|
||||
return 'GET {0} HTTP/1.1\r\nConnection: close\r\n' \
|
||||
'Host: kyfw.12306.cn\r\n' \
|
||||
"Referer: {1}\r\n" \
|
||||
'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36' \
|
||||
'\r\nAccept: */*\r\n' \
|
||||
"Cookie: {2}\r\n\n"\
|
||||
'\r\n'
|
||||
# return 'GET {0} HTTP/1.1\r\nConnection: close\r\n' \
|
||||
# 'Host: kyfw.12306.cn\r\n' \
|
||||
# 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36' \
|
||||
# '\r\nAccept: */*\r\n' \
|
||||
# '\r\n'
|
||||
|
||||
|
||||
def default_post_data():
|
||||
"""
|
||||
post请求默认组装字符串
|
||||
需要拼接的字符串
|
||||
-- url 发送请求的全连接
|
||||
-- Referer 请求页面来源
|
||||
-- Content-Length: body 长度
|
||||
-- Cookie 页面请求的身份认证
|
||||
-- appid 接口请求报文
|
||||
:return:
|
||||
"""
|
||||
return "POST https://kyfw.12306.cn{0} HTTP/1.1\r\n" \
|
||||
"Host: kyfw.12306.cn\r\n" \
|
||||
"Connection: close\r\n"\
|
||||
"Origin: https://kyfw.12306.cn\r\n" \
|
||||
"X-Requested-With: XMLHttpRequest\r\n" \
|
||||
"Referer: {3}\r\n" \
|
||||
"Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n" \
|
||||
"Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n" \
|
||||
"Accept: application/json, text/javascript, */*; q=0.01\r\n" \
|
||||
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5\r\n" \
|
||||
"Content-Length: {2}\r\n"\
|
||||
"Cookie: {4}\r\n\n"\
|
||||
"{1}\r\n"\
|
||||
# "\r\n"
|
||||
|
||||
|
||||
class socketUtils:
|
||||
def __init__(self, host, port=80):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.s = self.connect_socket(self.host, self.port)
|
||||
|
||||
def connect_socket(self, host, port):
|
||||
"""
|
||||
连接socket
|
||||
:param host:
|
||||
:param port:
|
||||
:return:
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((host if isinstance(host, str) else str(host),
|
||||
port if isinstance(port, int) else int(port)))
|
||||
return s
|
||||
|
||||
def close_s(self):
|
||||
self.s.close()
|
||||
|
||||
# def send(self, urls, Cookie=None, data=None):
|
||||
# """
|
||||
# 发送请求
|
||||
# :param urls:
|
||||
# :param data:
|
||||
# :param cookie:
|
||||
# :return:
|
||||
# """
|
||||
# url = urls.get("req_url", "")
|
||||
# Referer = urls.get("Referer", "")
|
||||
# if urls.get("req_type", "get") == "post":
|
||||
# Content_Length = len(data)
|
||||
# Cookie = "tk=pnidlCoFy2B7wxO_X_pESbrkZFSq3OtVA_xzXwuba2a0; JSESSIONID=C6144324BFCE36AC5082E543E934E8B3; current_captcha_type=Z; _jc_save_fromDate=2018-08-03; _jc_save_fromStation=%u6DF1%u5733%2CSZQ; _jc_save_toDate=2018-08-03; _jc_save_toStation=%u957F%u6C99%2CCSQ; _jc_save_wfdc_flag=dc; ten_key=b5L6aMWfnzBm8CgQe8pcAKQsmVBS2PYH; BIGipServerpool_passport=166527498.50215.0000; BIGipServerotn=165937674.50210.0000; route=c5c62a339e7744272a54643b3be5bf64; RAIL_DEVICEID=fC-yepiUqNjsBiRvtLBXW4JqQmabCfB9QxI3FifJZK9YDRsImhJLSz4sAQ4HiGF7uQAFdFyISg6jA7KAhtpEldJV9ZMNsn6Dzm_psA5CBDwSNfiORf42w-LIRvkeGvdKFtegZwWGlkA2fVuEWKu-1xAYdCXRnsMD; RAIL_EXPIRATION=1533420302032; _jc_save_detail=true"
|
||||
# if data:
|
||||
# send_value = default_post_data().format(url,
|
||||
# data,
|
||||
# Content_Length,
|
||||
# Referer,
|
||||
# Cookie
|
||||
# )
|
||||
# print("send_value: " + send_value)
|
||||
# self.s.sendall(send_value)
|
||||
# else:
|
||||
# self.s.sendall(default_get_data().format(url,
|
||||
# Referer,
|
||||
# Cookie))
|
||||
# total_data = ""
|
||||
# while 1:
|
||||
# data = self.s.recv(1024)
|
||||
# total_data += data
|
||||
# if not data:
|
||||
# break
|
||||
# self.close_s()
|
||||
# print(total_data)
|
||||
# return self.recv_data(total_data)
|
||||
|
||||
def recv_data(self, r_data):
|
||||
cookie = self.get_cookie(r_data)
|
||||
status_code = self.get_status_code(r_data)
|
||||
r_body = self.get_rep_body(r_data)
|
||||
return {
|
||||
"cookie": cookie,
|
||||
"status_code": status_code,
|
||||
"r_body": r_body
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_cookie(recv_data):
|
||||
"""
|
||||
提取cookie
|
||||
:param recv_data:
|
||||
:return:
|
||||
"""
|
||||
if not isinstance(recv_data, str):
|
||||
recv_data = str(recv_data)
|
||||
cookies_re = re.compile(r"Set-Cookie: (\S+);")
|
||||
cookies = re.findall(cookies_re, recv_data)
|
||||
return "; ".join(cookies)
|
||||
|
||||
@staticmethod
|
||||
def get_status_code(recv_data):
|
||||
"""
|
||||
获取状态码
|
||||
:return:
|
||||
"""
|
||||
if not isinstance(recv_data, str):
|
||||
recv_data = str(recv_data)
|
||||
http_code_re = re.compile(r"HTTP/1.1 (\S+) ")
|
||||
status_code = re.search(http_code_re, recv_data).group(1)
|
||||
return status_code
|
||||
|
||||
@staticmethod
|
||||
def get_rep_body(recv_data):
|
||||
"""
|
||||
获取返回值
|
||||
:param recv_data:
|
||||
:return:
|
||||
"""
|
||||
if not isinstance(recv_data, str):
|
||||
recv_data = str(recv_data)
|
||||
if recv_data.find("{") != -1 and recv_data.find("}") != -1:
|
||||
data = json.loads(recv_data.split("\n")[-1])
|
||||
return data
|
||||
else:
|
||||
print(recv_data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
so = socketUtils('183.232.189.31', 80)
|
||||
train_date = "2018-08-03"
|
||||
from_station = "SZQ"
|
||||
to_station = "CSQ"
|
||||
urls["select_url"]["req_url"] = "https://kyfw.12306.cn" + urls["select_url"]["req_url"].format(train_date, from_station, to_station)
|
||||
result = so.send(urls=urls["select_url"])
|
||||
print(result)
|
||||
|
||||
so = socketUtils('183.232.189.31', 80)
|
||||
|
||||
data = "secretStr=Vgo534nDZiCH8NCvyEPcGepzJoRCjvYr34gKFv5CW1K1XtM6mtKHoiFPjUYvaVKoe06SMhUUpT%2FK%0AxIEIsBD4zHgJPpVyKiTPx80y6OCWhNgcKjib2LLMXMJfgTgh0RKPISjkDjVFmO9p905O%2FegDeKjp%0A1fhIeqCuYraHjNhI0PjQY39BAY4AHLzW0iGgDq8b%2FtpyOY8Td2XfIWNZJCWzgyPkNXOk0HUguB2G%0AKh2T8nlko6zb5ra%2B%2BA%3D%3D&train_date=2018-08-03&back_train_date=2018-08-03&tour_flag=dc&purpose_codes=ADULT&query_from_station_name=深圳&query_to_station_name=长沙&undefined"
|
||||
result1 = so.send(urls=urls["submit_station_url"], data=data)
|
||||
print(result1)
|
||||
# so = socketUtils('183.232.189.31', 80)
|
||||
# result = so.send(url="https://kyfw.12306.cn/passport/web/login", s_data="")
|
||||
# print(result)
|
|
@ -12,49 +12,14 @@ from config import logger
|
|||
|
||||
def _set_header_default():
|
||||
header_dict = OrderedDict()
|
||||
header_dict["Host"] = "kyfw.12306.cn"
|
||||
header_dict["Connection"] = "keep-alive"
|
||||
header_dict["Accept"] = "application/json, text/javascript, */*; q=0.01"
|
||||
header_dict["Origin"] = "https://kyfw.12306.cn"
|
||||
header_dict["X-Requested-With"] = "XMLHttpRequest"
|
||||
header_dict["Accept"] = "application/json, text/plain, */*"
|
||||
header_dict["Accept-Encoding"] = "gzip, deflate"
|
||||
header_dict[
|
||||
"User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
|
||||
"User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) 12306-electron/1.0.1 Chrome/59.0.3071.115 Electron/1.8.4 Safari/537.36"
|
||||
header_dict["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"
|
||||
header_dict["Referer"] = "https://kyfw.12306.cn/otn/leftTicket/init"
|
||||
header_dict["Accept-Encoding"] = "gzip, deflate, br"
|
||||
header_dict["Accept-Language"] = "zh-CN,zh;q=0.9,en;q=0.8"
|
||||
return header_dict
|
||||
|
||||
|
||||
def _set_header_j():
|
||||
"""设置header"""
|
||||
return {
|
||||
"Content-Type": "application/json; charset=UTF-8",
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5",
|
||||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||
"Referer": "https://kyfw.12306.cn/otn/leftTicket/init",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
||||
"Origin": "https://kyfw.12306.cn",
|
||||
"Connection": "keep-alive",
|
||||
}
|
||||
|
||||
|
||||
def _set_header_x():
|
||||
"""设置header"""
|
||||
return {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5",
|
||||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||
"Referer": "https://kyfw.12306.cn/otn/leftTicket/init",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
||||
"Origin": "https://kyfw.12306.cn",
|
||||
"Connection": "keep-alive",
|
||||
}
|
||||
|
||||
|
||||
class HTTPClient(object):
|
||||
|
||||
def __init__(self):
|
||||
|
@ -67,7 +32,7 @@ class HTTPClient(object):
|
|||
|
||||
def initS(self):
|
||||
self._s = requests.Session()
|
||||
self._s.headers.update(_set_header_j())
|
||||
self._s.headers.update(_set_header_default())
|
||||
return self
|
||||
|
||||
def set_cookies(self, **kwargs):
|
||||
|
@ -79,6 +44,13 @@ class HTTPClient(object):
|
|||
for k, v in kwargs.items():
|
||||
self._s.cookies.set(k, v)
|
||||
|
||||
def get_cookies(self):
|
||||
"""
|
||||
获取cookies
|
||||
:return:
|
||||
"""
|
||||
return self._s.cookies.values()
|
||||
|
||||
def del_cookies(self):
|
||||
"""
|
||||
删除所有的key
|
||||
|
@ -97,12 +69,9 @@ class HTTPClient(object):
|
|||
self._s.headers.update(headers)
|
||||
return self
|
||||
|
||||
def resetHeaders(self, header_type):
|
||||
def resetHeaders(self):
|
||||
self._s.headers.clear()
|
||||
if header_type == 1:
|
||||
self._s.headers.update(_set_header_x())
|
||||
else:
|
||||
self._s.headers.update(_set_header_j())
|
||||
self._s.headers.update(_set_header_default())
|
||||
|
||||
def getHeadersHost(self):
|
||||
return self._s.headers["Host"]
|
||||
|
@ -126,14 +95,6 @@ class HTTPClient(object):
|
|||
def cdn(self, cdn):
|
||||
self._cdn = cdn
|
||||
|
||||
# def send_socket(self, urls, data=None, **kwargs):
|
||||
# data = """
|
||||
# POST {0} HTTP/1.1
|
||||
# {0}
|
||||
# """.format(urls["req_url"], self._set_header())
|
||||
# fack = socket.create_connection(urls["Host"], 443)
|
||||
# fack.send()
|
||||
|
||||
def send(self, urls, data=None, **kwargs):
|
||||
"""send request to url.If response 200,return response, else return None."""
|
||||
allow_redirects = False
|
||||
|
@ -141,31 +102,22 @@ class HTTPClient(object):
|
|||
req_url = urls.get("req_url", "")
|
||||
re_try = urls.get("re_try", 0)
|
||||
s_time = urls.get("s_time", 0)
|
||||
contentType = urls.get("Content-Type", 0)
|
||||
error_data = {"code": 99999, "message": u"重试次数达到上限"}
|
||||
if data:
|
||||
method = "post"
|
||||
self.setHeaders({"Content-Length": "{0}".format(len(data))})
|
||||
else:
|
||||
method = "get"
|
||||
self.resetHeaders(contentType)
|
||||
self.resetHeaders()
|
||||
self.setHeadersReferer(urls["Referer"])
|
||||
if is_logger:
|
||||
logger.log(
|
||||
u"url: {0}\n入参: {1}\n请求方式: {2}\n".format(req_url, data, method, ))
|
||||
self.setHeadersHost(urls["Host"])
|
||||
# self.setHeadersHost(urls["Host"])
|
||||
if self.cdn:
|
||||
url_host = self.cdn
|
||||
else:
|
||||
url_host = urls["Host"]
|
||||
if contentType == 1:
|
||||
# 普通from表单
|
||||
self.resetHeaders(contentType)
|
||||
if method == "post":
|
||||
pass
|
||||
data = urllib.urlencode(data)
|
||||
elif contentType == 0:
|
||||
self.resetHeaders(contentType)
|
||||
for i in range(re_try):
|
||||
try:
|
||||
# sleep(urls["s_time"]) if "s_time" in urls else sleep(0.001)
|
||||
|
|
|
@ -3,4 +3,5 @@ bs4==0.0.1
|
|||
PyYAML==3.12
|
||||
six==1.10.0
|
||||
requests==2.18.4
|
||||
Pillow==5.0.0
|
||||
Pillow==5.0.0
|
||||
wrapcache==1.0.8
|
14
run.py
14
run.py
|
@ -1,12 +1,16 @@
|
|||
# -*- coding=utf-8 -*-
|
||||
from init import login, select_ticket_info, SelectTicketInfoFast
|
||||
from config.emailConf import sendEmail
|
||||
from init import select_ticket_info
|
||||
|
||||
|
||||
def run():
|
||||
# login.main()
|
||||
SelectTicketInfoFast.selectFast().main()
|
||||
# select_ticket_info.select().main()
|
||||
select_ticket_info.select().main()
|
||||
|
||||
|
||||
def testEmail():
|
||||
sendEmail(u"订票小助手测试一下")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
run()
|
||||
# testEmail()
|
Loading…
Reference in New Issue