diff --git a/.gitignore b/.gitignore index 3ff2ada..467b159 100755 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *.log .idea/ *.h5 +tkcode.png \ No newline at end of file diff --git a/README.md b/README.md index e97c88e..4ec24c9 100755 --- a/README.md +++ b/README.md @@ -18,13 +18,13 @@ - 非root用户(避免安装和运行时使用了不同环境): `pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt` #### 项目使用说明 - - 可以配置邮箱,可以配置可以不配置,配置邮箱的格式在[yaml](config/ticket_config.yaml)里面可以看到ex + - 可以配置邮箱,可以配置可以不配置,配置邮箱的格式在[配置](TickerConfig.py)里面可以看到ex - 可以配置server酱提醒(推荐), [配置教程](https://www.jianshu.com/p/8d10b5b9c4e3) - - 配置[yaml](config/ticket_config.yaml)文件的时候,需注意空格和遵循yaml语法格式 + - 配置[配置](TickerConfig.py)文件的时候,需注意空格和遵循yaml语法格式 #### 项目开始 - 服务器启动: - - 修改[config/ticket_config.yaml](config/ticket_config.yaml)文件,按照提示更改自己想要的信息 + - 修改[配置](TickerConfig.py)文件,按照提示更改自己想要的信息 - 运行根目录`sudo python run.py`,即可开始 - 由于新增对时功能,请务必用**sudo,sudo,sudo** 执行,否则会报权限错误,windows打开ide或者cmd请用管理员身份执行`python run.py`,不需要加`sudo` - 如果你的服务器安装了docker与docker-compose, 那么就可以通过`docker-compose`进行启动,`docker.sh`脚本对此进行了封装,可以通过如下命令进行启动 diff --git a/TickerConfig.py b/TickerConfig.py new file mode 100644 index 0000000..2603a34 --- /dev/null +++ b/TickerConfig.py @@ -0,0 +1,119 @@ +# 刷票模式:1=刷票 2=候补 +TICKET_TYPE = 2 + +# 候补最晚兑现日期,如果是候补订单,这个值一定要填 +# 格式为日期+小时+分 +# t("#fromDate").val() + "#" + t("#dafaultTime").html().replace("时", "") + "#" + t("#dafaultMinutes").html().replace("分", ""), +J_Z_PARAM = "2019-09-10#22#59" + +# 出发日期(list) "2018-01-06", "2018-01-07" +STATION_DATES = [ + "2019-09-30" +] + +# 填入需要购买的车次(list),"G1353" +STATION_TRAINS = [ + "G1377" +] + +# 出发城市,比如深圳北,就填深圳就搜得到 +FROM_STATION = "上海" + +# 到达城市 比如深圳北,就填深圳就搜得到 +TO_STATION = "长沙" + +# 座位(list) 多个座位ex: +# - "商务座" +# - "一等座" +# - "二等座" +# - "特等座" +# - "软卧" +# - "硬卧" +# - "硬座" +# - "无座" +# - "动卧" +SET_TYPE = [ + "二等座" +] + +# 当余票小于乘车人,如果选择优先提交,则删减联系人和余票数一致在提交 +# bool +IS_MORE_TICKET = False + +# 乘车人(list) 多个乘车人ex: +# - "张三" +# - "李四" +TICKET_PEOPLES = [ + "" +] + +# 12306登录账号 +USER = "" +PWD = "" + +# 加入小黑屋时间默认为5分钟,此功能为了防止僵尸票导致一直下单不成功错过正常的票 +TICKET_BLACK_LIST_TIME = 5 + +# 自动打码 +IS_AUTO_CODE = True + +# 邮箱配置,如果抢票成功,将通过邮件配置通知给您 +# 列举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" +EMAIL_CONF = { + "IS_MAIL": True, + "email": "", + "notice_email_list": "", + "username": "", + "password": "", + "host": "", +} + +# 是否开启 pushbear 微信提醒, 使用前需要前往 http://pushbear.ftqq.com 扫码绑定获取 send_key 并关注获得抢票结果通知的公众号 +PUSHBEAR_CONF = { + "is_pushbear": False, + "send_key": "" +} + +# 是否开启cdn查询,可以更快的检测票票 1为开启,2为关闭 +IS_CDN = 1 + +# 下单接口分为两种,1 模拟网页自动捡漏下单(不稳定),2 模拟车次后面的购票按钮下单(稳如老狗) +ORDER_TYPE = 2 + +# 下单模式 1 为预售,整点刷新,刷新间隔0.1-0.5S, 然后会校验时间,比如12点的预售,那脚本就会在12.00整检票,刷新订单 +# 2 是捡漏,捡漏的刷新间隔时间为0.5-3秒,时间间隔长,不容易封ip +ORDER_MODEL = 2 + +# 是否开启代理, 0代表关闭, 1表示开始 +# 开启此功能的时候请确保代理ip是否可用,在测试放里面经过充分的测试,再开启此功能,不然可能会耽误你购票的宝贵时间 +# 使用方法: +# 1、在agency/proxy_list列表下填入代理ip +# 2、测试UnitTest/TestAll/testProxy 测试代理是否可以用 +# 3、开启代理ip +IS_PROXY = 0 + +# 预售放票时间, 如果是捡漏模式,可以忽略此操作 +OPEN_TIME = "13:00:00" + +PASSENGER_TICKER_STR = { + '一等座': 'M', + '特等座': 'P', + '二等座': 'O', + '商务座': 9, + '硬座': 1, + '无座': 1, + '软座': 2, + '软卧': 4, + '硬卧': 3, +} diff --git a/UnitTest/TestAll.py b/UnitTest/TestAll.py index 103cf27..74ff210 100644 --- a/UnitTest/TestAll.py +++ b/UnitTest/TestAll.py @@ -53,6 +53,5 @@ class testAll(unittest.TestCase): # :return: # """ - if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/Update.md b/Update.md index 41b4cc3..7448950 100644 --- a/Update.md +++ b/Update.md @@ -157,3 +157,9 @@ - 删除若快打码 - 修复不能下单问题 - 放弃支持python2.7,只支持3.6以上版本 + +- 2019.09.01更新 + - 去除yaml配置文件,改为py文件配置 + - 增加候补订单功能 + - 新增TICKET_TYPE字段,1=刷票 2=候补 + - 目前候补只支持单车次,多乘车人候补,由于目前不是很懂候补的需求,所以暂时这样做 diff --git a/config/TicketEnmu.py b/config/TicketEnmu.py index d960282..9e9f294 100644 --- a/config/TicketEnmu.py +++ b/config/TicketEnmu.py @@ -1,4 +1,5 @@ # coding=utf-8 +from enum import Enum class ticket(object): @@ -25,6 +26,7 @@ class ticket(object): OUT_NUM = 120 # 排队请求12306的次数 WAIT_OUT_NUM = u"超出排队时间,自动放弃,正在重新刷票" WAIT_ORDER_SUCCESS = u"恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!" + WAIT_AFTER_NATE_SUCCESS = u"候补订单已完成,请立即打开浏览器登录12306,访问‘候补订单’,在30分钟内完成支付!" WAIT_ORDER_CONTINUE = u"排队等待时间预计还剩 {0} ms" WAIT_ORDER_FAIL = u"排队等待失败,错误消息:{0}" WAIT_ORDER_NUM = u"第{0}次排队中,请耐心等待" @@ -37,4 +39,3 @@ class ticket(object): REST_TIME_PAST = u"休息时间已过,重新开启检票功能" LOGIN_SESSION_FAIL = u"用户检查失败:{0},可能未登录,可能session已经失效, 正在重新登录中" - diff --git a/config/emailConf.py b/config/emailConf.py index 514f1c8..efc132e 100755 --- a/config/emailConf.py +++ b/config/emailConf.py @@ -1,10 +1,9 @@ # -*- coding: utf8 -*- import socket - __author__ = 'MR.wen' +import TickerConfig from email.header import Header from email.mime.text import MIMEText -from config.ticketConf import _get_yaml import smtplib @@ -14,38 +13,33 @@ def sendEmail(msg): :param str: email content :return: """ - email_conf = _get_yaml() - is_email = email_conf["email_conf"]["is_email"] - if is_email: + try: + sender = TickerConfig.EMAIL_CONF["email"] + receiver = TickerConfig.EMAIL_CONF["notice_email_list"] + subject = '恭喜,您已订票成功' + username = TickerConfig.EMAIL_CONF["username"] + password = TickerConfig.EMAIL_CONF["password"] + host = TickerConfig.EMAIL_CONF["host"] + s = "{0}".format(msg) + + msg = MIMEText(s, 'plain', 'utf-8') # 中文需参数‘utf-8’,单字节字符不需要 + msg['Subject'] = Header(subject, 'utf-8') + msg['From'] = sender + msg['To'] = receiver + try: - sender = email_conf["email_conf"]["email"] - receiver = email_conf["email_conf"]["notice_email_list"] - subject = '恭喜,您已订票成功' - username = email_conf["email_conf"]["username"] - password = email_conf["email_conf"]["password"] - host = email_conf["email_conf"]["host"] - s = "{0}".format(msg) - - msg = MIMEText(s, 'plain', 'utf-8') # 中文需参数‘utf-8’,单字节字符不需要 - msg['Subject'] = Header(subject, 'utf-8') - msg['From'] = sender - msg['To'] = receiver - - try: - smtp = smtplib.SMTP_SSL() - smtp.connect(host) - except socket.error: - smtp = smtplib.SMTP() - smtp.connect(host) + smtp = smtplib.SMTP_SSL() smtp.connect(host) - smtp.login(username, password) - smtp.sendmail(sender, receiver.split(","), msg.as_string()) - smtp.quit() - print(u"邮件已通知, 请查收") - except Exception as e: - print(u"邮件配置有误{}".format(e)) - else: - pass + except socket.error: + smtp = smtplib.SMTP() + smtp.connect(host) + smtp.connect(host) + smtp.login(username, password) + smtp.sendmail(sender, receiver.split(","), msg.as_string()) + smtp.quit() + print(u"邮件已通知, 请查收") + except Exception as e: + print(u"邮件配置有误{}".format(e)) if __name__ == '__main__': diff --git a/config/pushbearConf.py b/config/pushbearConf.py index bc8576c..115fdfc 100644 --- a/config/pushbearConf.py +++ b/config/pushbearConf.py @@ -1,8 +1,5 @@ # -*- coding: utf8 -*- -import time - -import requests -from config.ticketConf import _get_yaml +import TickerConfig from config.urlConf import urls from myUrllib.httpUtils import HTTPClient @@ -15,12 +12,11 @@ def sendPushBear(msg): :param str: 通知内容 content :return: """ - conf = _get_yaml() - if conf["pushbear_conf"]["is_pushbear"] and conf["pushbear_conf"]["send_key"].strip() != "": + if TickerConfig.PUSHBEAR_CONF["is_pushbear"] and TickerConfig.PUSHBEAR_CONF["pushbear_conf"]["send_key"].strip() != "": try: sendPushBearUrls = urls.get("Pushbear") data = { - "sendkey": conf["pushbear_conf"]["send_key"].strip(), + "sendkey": TickerConfig.PUSHBEAR_CONF["pushbear_conf"]["send_key"].strip(), "text": "易行购票成功通知", "desp": msg } diff --git a/config/ticketConf.py b/config/ticketConf.py deleted file mode 100755 index b84c89b..0000000 --- a/config/ticketConf.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf8 -*- -__author__ = 'MR.wen' -import os -import yaml - - -def _get_yaml(): - """ - 解析yaml - :return: s 字典 - """ - path = os.path.join(os.path.dirname(__file__) + '/ticket_config.yaml') - try: # 兼容2和3版本 - with open(path, encoding="utf-8") as f: - s = yaml.load(f) - except Exception: - with open(path) as f: - s = yaml.load(f) - return s.decode() if isinstance(s, bytes) else s - - -if __name__ == '__main__': - print(_get_yaml()) \ No newline at end of file diff --git a/config/ticket_config.yaml b/config/ticket_config.yaml deleted file mode 100755 index b47ff40..0000000 --- a/config/ticket_config.yaml +++ /dev/null @@ -1,142 +0,0 @@ ---- -# 配置文件请严格遵循yaml语法格式,yaml学习地址 https://ansible-tran.readthedocs.io/en/latest/docs/YAMLSyntax.html -set: - # 出发日期(list),格式ex: - # - 2018-01-06 - # - 2018-01-07 - station_dates: - - "2019-01-18" - - # 是否根据时间范围 和 乘车类型 购票 - # 否则将需要手动填写车次 - is_by_time: False - - # 列车类型: 高铁 G 动车 D 其它火车 O - train_types: [G,D,O] - - # 可接受最早出发时间 格式ex: - # departure_time: "8:00" - departure_time: "00:00" - - # 可接受最晚抵达时间 格式ex: - # arrival_time: "16:00" - arrival_time: "24:00" - - # 可接受最长旅途时间 格式ex: - # take_time: "24:00" - take_time: "24:00" - - # 填入需要购买的车次(list),格式ex: - # - "G1353" - # - "G1329" - station_trains: - - "G6153" - - "G6184" - - "G6173" - - # 出发城市,比如深圳北,就填深圳就搜得到 - from_station: "邵阳" - - # 到达城市 比如深圳北,就填深圳就搜得到 - to_station: "深圳北" - - # 座位(list) 多个座位ex: - # - "商务座" - # - "一等座" - # - "二等座" - # - "特等座" - # - "软卧" - # - "硬卧" - # - "硬座" - # - "无座" - # - "动卧" - set_type: - - "二等座" - - # 当余票小于乘车人,如果选择优先提交,则删减联系人和余票数一致在提交 - is_more_ticket: False - - # 乘车人(list) 多个乘车人ex: - # - "张三" - # - "李四" - ticke_peoples: - - "" - - # 12306登录账号(list) - 12306account: - - user: "qqxin1011" - - pwd: "" - -# 加入小黑屋时间默认为5分钟,此功能为了防止僵尸票导致一直下单不成功错过正常的票, -ticket_black_list_time: 5 - -# 自动打码 -is_auto_code: True - -# 打码平台, 2 为AI识别,需将两个模型文件放到项目根目录下 -auto_code_type: 2 - -# 邮箱配置,如果抢票成功,将通过邮件配置通知给您 -# 列举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" -email_conf: - is_email: True - email: "" - notice_email_list: "" - username: "" - password: "" - host: "smtp.qq.com" - -# 是否开启 pushbear 微信提醒, 使用前需要前往 http://pushbear.ftqq.com 扫码绑定获取 send_key 并关注获得抢票结果通知的公众号 -pushbear_conf: - is_pushbear: False - send_key: "" - -# 是否开启cdn查询,可以更快的检测票票 1为开启,2为关闭 -is_cdn: 1 - -# 下单接口分为两种,1 模拟网页自动捡漏下单(不稳定),2 模拟车次后面的购票按钮下单(稳如老狗) -order_type: 2 - -# 下单模式 1 为预售,整点刷新,刷新间隔0.1-0.5S, 然后会校验时间,比如12点的预售,那脚本就会在12.00整检票,刷新订单 -# 2 是捡漏,捡漏的刷新间隔时间为0.5-3秒,时间间隔长,不容易封ip -order_model: 2 - -# 预售放票时间, 如果是捡漏模式,可以忽略此操作 -open_time: '13:00:00' - -# 是否开启代理, 0代表关闭, 1表示开始 -# 开启此功能的时候请确保代理ip是否可用,在测试放里面经过充分的测试,再开启此功能,不然可能会耽误你购票的宝贵时间 -# 使用方法: -# 1、在agency/proxy_list列表下填入代理ip -# 2、测试UnitTest/TestAll/testProxy 测试代理是否可以用 -# 3、开启代理ip -is_proxy: 0 - -# 路由器自动切换ip, 目前只支持tplink, -# is_router: 0表示打开,1表示开启 -# router_time: 以/分钟为单位 -#router_pwd: 路由器登录的密码 -#broadband_user_name: 宽带账号 -#broadband_pwd: 宽带密码 - -#is_router: 1 -#router_time: -#router_pwd: -#broadband_user_name: "" -#broadband_pwd: - -# query线程 -#query_thread: 3 - - diff --git a/config/urlConf.py b/config/urlConf.py index 5e60134..236bc65 100755 --- a/config/urlConf.py +++ b/config/urlConf.py @@ -139,7 +139,7 @@ urls = { "is_json": False, }, "getDevicesId": { # 获取用户信息 - "req_url": "/otn/HttpZF/logdevice?algID=3yxNoRW8BM&hashCode=8EFUGZrjK3cO8VdDugvPxyyiUqMNmKhl6pbW1ftnEVI&FMQw=0&q4f3=zh-CN&VPIf=1&custID=133&VEek=unknown&dzuS=0&yD16=0&EOQP=c227b88b01f5c513710d4b9f16a5ce52&lEnu=2887005765&jp76=52d67b2a5aa5e031084733d5006cc664&hAqN=MacIntel&platform=WEB&ks0Q=d22ca0b81584fbea62237b14bd04c866&TeRS=1013x1920&tOHY=24xx1080x1920&Fvje=i1l1o1s1&q5aJ=-8&wNLf=99115dfb07133750ba677d055874de87&0aew=Mozilla/5.0%20(Macintosh;%20Intel%20Mac%20OS%20X%2010_14_4)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/74.0.3729.131%20Safari/537.36&E3gR=d4c1ccb1725a4a45cc350f16ac26f32b×tamp={0}", + "req_url": "/otn/HttpZF/logdevice?algID=YD9Iw7QM4u&hashCode=d7vhohETY2f2TpCef2MPZFvngSXyZU71bSRYvkHTkbc&FMQw=0&q4f3=zh-CN&VySQ=FGFC5l5w_W3LWESYu2oI4qV2jIzzka61&VPIf=1&custID=133&VEek=unknown&dzuS=0&yD16=0&EOQP=c227b88b01f5c513710d4b9f16a5ce52&lEnu=3232235624&jp76=52d67b2a5aa5e031084733d5006cc664&hAqN=MacIntel&platform=WEB&ks0Q=d22ca0b81584fbea62237b14bd04c866&TeRS=831x1440&tOHY=24xx900x1440&Fvje=i1l1o1s1&q5aJ=-8&wNLf=99115dfb07133750ba677d055874de87&0aew=Mozilla/5.0%20(Macintosh;%20Intel%20Mac%20OS%20X%2010_13_4)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/76.0.3809.132%20Safari/537.36&E3gR=ab86d46d16b9293beca4799ff15c5db1×tamp={0}", "req_type": "get", "Referer": "https://kyfw.12306.cn/otn/passport?redirect=/otn/", "Host": "kyfw.12306.cn", @@ -504,4 +504,65 @@ urls = { }, + + # 候补订单接口 + + "chechFace": { # 人脸识别 + "req_url": "/otn/afterNate/chechFace", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_logger": True, + "is_json": True, + }, + "getSuccessRate": { # 成功信息 + "req_url": "/otn/afterNate/getSuccessRate", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_logger": True, + "is_json": True, + }, + "SubmitOrderRequestRsp": { # 提交候补订单准备 + "req_url": "/otn/afterNate/submitOrderRequest", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_logger": True, + "is_json": True, + }, + "confirmHB": { # 设置订单信息 + "req_url": "/otn/afterNate/confirmHB", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_logger": True, + "is_json": True, + }, + "queryQueue": { # 排队 + "req_url": "/otn/afterNate/queryQueue", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_logger": True, + "is_json": True, + }, + + + } \ No newline at end of file diff --git a/init/login.py b/init/login.py index f55179c..ef2f77e 100755 --- a/init/login.py +++ b/init/login.py @@ -3,8 +3,7 @@ import copy import time from collections import OrderedDict from time import sleep - -from config.ticketConf import _get_yaml +import TickerConfig from inter.GetPassCodeNewOrderAndLogin import getPassCodeNewOrderAndLogin1 from inter.GetRandCode import getRandCode from inter.LoginAysnSuggest import loginAysnSuggest @@ -126,7 +125,7 @@ class GoLogin: :param passwd: 密码 :return: """ - user, passwd = _get_yaml()["set"]["12306account"][0]["user"], _get_yaml()["set"]["12306account"][1]["pwd"] + user, passwd = TickerConfig.USER, TickerConfig.PWD if not user or not passwd: raise UserPasswordException(u"温馨提示: 用户名或者密码为空,请仔细检查") login_num = 0 @@ -138,7 +137,7 @@ class GoLogin: devicesIdUrl["req_url"] = devicesIdUrl["req_url"].format(int(time.time() * 1000)) # devicesIdRsp = self.session.httpClint.send(devicesIdUrl) # devicesId = eval(devicesIdRsp.split("(")[1].split(")")[0].replace("'", ""))["dfp"] - devicesId = "UysLb2cYwsVjyInSzZ0pGOmYplvokmhBjoGNjrinquaUD0id7gkifgF6FvM2TRCL7Df89GZL1lVV763tGhiPhxlNdlE7iQkk496KUGCFZyyWxE4d0XjyHYv9DlsXfKTlrd8RBUdYIYjmWBXWMN65ElDQiO_Rnrul" + devicesId = "K1OnaaicUR1DrGl2vRS1HrLLna8UBoXkESCnuPMBzVtrO6fG4URi2RWJHpM7urYlYx-fpp0AeM4Ca8rNN4WyYv1X493VsH5yejsLNol7XZ74gRp8yE7eEDHYU87t1urn3Oeaifrjrd5FRTmk3WCNylKeE2UQhPRH" if devicesId: self.session.httpClint.set_cookies(RAIL_DEVICEID=devicesId) diff --git a/init/select_ticket_info.py b/init/select_ticket_info.py index 6b08c86..7e8f33c 100755 --- a/init/select_ticket_info.py +++ b/init/select_ticket_info.py @@ -6,16 +6,15 @@ import socket import sys import threading import time - +import TickerConfig import wrapcache - from agency.cdn_utils import CDNProxy from config import urlConf, configCommon from config.TicketEnmu import ticket -from config.configCommon import seat_conf, checkDate, seat_conf_2 -from config.ticketConf import _get_yaml +from config.configCommon import seat_conf_2, seat_conf from init.login import GoLogin from inter.AutoSubmitOrderRequest import autoSubmitOrderRequest +from inter.ChechFace import chechFace from inter.CheckUser import checkUser from inter.GetPassengerDTOs import getPassengerDTOs from inter.LiftTicketInit import liftTicketInit @@ -27,13 +26,6 @@ from myException.ticketConfigException import ticketConfigException from myException.ticketIsExitsException import ticketIsExitsException from myException.ticketNumOutException import ticketNumOutException from myUrllib.httpUtils import HTTPClient -from utils.timeUtil import time_to_minutes, minutes_to_time - -try: - reload(sys) - sys.setdefaultencoding('utf-8') -except NameError: - pass class select: @@ -42,57 +34,25 @@ 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.station_trains, self.ticket_black_list_time, \ - self.order_type, self.is_by_time, self.train_types, self.departure_time, \ - self.arrival_time, self.take_time, self.order_model, self.open_time, self.is_proxy = 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.httpClint = HTTPClient(self.is_proxy) + self.get_ticket_info() + self._station_seat = [seat_conf[x] for x in TickerConfig.SET_TYPE] + self.auto_code_type = 2 + self.httpClint = HTTPClient(TickerConfig.IS_PROXY) self.urls = urlConf.urls - self.login = GoLogin(self, self.is_auto_code, self.auto_code_type) + self.login = GoLogin(self, TickerConfig.IS_AUTO_CODE, self.auto_code_type) self.cdn_list = [] - self.queryUrl = "leftTicket/query" + self.queryUrl = "leftTicket/queryT" self.passengerTicketStrList = "" + self.passengerTicketStrByAfterLate = "" self.oldPassengerStr = "" self.set_type = "" - def get_ticket_info(self): + @staticmethod + def get_ticket_info(): """ 获取配置信息 :return: """ - ticket_info_config = _get_yaml() - from_station = ticket_info_config["set"]["from_station"] - to_station = ticket_info_config["set"]["to_station"] - station_dates = checkDate(ticket_info_config["set"]["station_dates"]) - - set_names = ticket_info_config["set"]["set_type"] - try: - set_type = [seat_conf[x.encode("utf-8")] for x in ticket_info_config["set"]["set_type"]] - except KeyError: - set_type = [seat_conf[x] for x in ticket_info_config["set"]["set_type"]] - is_more_ticket = ticket_info_config["set"]["is_more_ticket"] - ticke_peoples = ticket_info_config["set"]["ticke_peoples"] - station_trains = ticket_info_config["set"]["station_trains"] - ticket_black_list_time = ticket_info_config["ticket_black_list_time"] - order_type = ticket_info_config["order_type"] - - # by time - is_by_time = ticket_info_config["set"]["is_by_time"] - train_types = ticket_info_config["set"]["train_types"] - departure_time = time_to_minutes(ticket_info_config["set"]["departure_time"]) - arrival_time = time_to_minutes(ticket_info_config["set"]["arrival_time"]) - take_time = time_to_minutes(ticket_info_config["set"]["take_time"]) - - # 下单模式 - order_model = ticket_info_config["order_model"] - open_time = ticket_info_config["open_time"] - - # 代理模式 - is_proxy = ticket_info_config["is_proxy"] - print(u"*" * 50) print(u"检查当前python版本为:{},目前版本只支持3.6以上".format(sys.version.split(" ")[0])) print(u"12306刷票小助手,最后更新于2019.01.08,请勿作为商业用途,交流群号:286271084(已满)," @@ -103,31 +63,10 @@ class select: u" 6群: 444101020(未满)\n" u" 7群: 660689659(未满)\n" ) - if is_by_time: - method_notie = u"购票方式:根据时间区间购票\n可接受最早出发时间:{0}\n可接受最晚抵达时间:{1}\n可接受最长旅途时间:{2}\n可接受列车类型:{3}\n" \ - .format(minutes_to_time(departure_time), minutes_to_time(arrival_time), minutes_to_time(take_time), - " , ".join(train_types)) - else: - method_notie = u"购票方式:根据候选车次购买\n候选购买车次:{0}".format(",".join(station_trains)) - print (u"当前配置:\n出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票优先提交:{4}\n乘车人:{5}\n" \ - u"刷新间隔: 随机(1-3S)\n{6}\n僵尸票关小黑屋时长: {7}\n下单接口: {8}\n下单模式: {9}\n预售踩点时间:{10} ".format \ - ( - from_station, - to_station, - station_dates, - ",".join(set_names), - is_more_ticket, - ",".join(ticke_peoples), - method_notie, - ticket_black_list_time, - order_type, - order_model, - open_time, - )) - print (u"*" * 50) - return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, station_trains, \ - ticket_black_list_time, order_type, is_by_time, train_types, departure_time, arrival_time, take_time, \ - order_model, open_time, is_proxy + print( + f"当前配置:\n出发站:{TickerConfig.FROM_STATION}\n到达站:{TickerConfig.TO_STATION}\n乘车日期:{','.join(TickerConfig.STATION_DATES)}\n坐席:{','.join(TickerConfig.SET_TYPE)}\n是否有票优先提交:{TickerConfig.IS_MORE_TICKET}\n乘车人:{TickerConfig.TICKET_PEOPLES}\n" \ + f"刷新间隔: 随机(1-3S)\n僵尸票关小黑屋时长: {TickerConfig.TICKET_BLACK_LIST_TIME}\n下单接口: {TickerConfig.ORDER_TYPE}\n下单模式: {TickerConfig.ORDER_MODEL}\n预售踩点时间:{TickerConfig.OPEN_TIME}") + print(u"*" * 50) def station_table(self, from_station, to_station): """ @@ -184,7 +123,7 @@ class select: cdn 认证 :return: """ - if self.is_cdn == 1: + if TickerConfig.IS_CDN == 1: CDN = CDNProxy() all_cdn = CDN.open_cdn_file() if all_cdn: @@ -200,7 +139,6 @@ class select: raise ticketConfigException(u"cdn列表为空,请先加载cdn") def main(self): - # autoSynchroTime() # 同步时间 self.cdn_certification() l = liftTicketInit(self) l.reqLiftTicketInit() @@ -209,23 +147,23 @@ class select: t = threading.Thread(target=check_user.sendCheckUser) t.setDaemon(True) t.start() - from_station, to_station = self.station_table(self.from_station, self.to_station) + from_station, to_station = self.station_table(TickerConfig.FROM_STATION, TickerConfig.TO_STATION) num = 0 - s = getPassengerDTOs(session=self, ticket_peoples=self.ticke_peoples) + s = getPassengerDTOs(session=self, ticket_peoples=TickerConfig.TICKET_PEOPLES) passenger = s.sendGetPassengerDTOs() wrapcache.set("user_info", passenger, timeout=9999999) while 1: try: num += 1 now = datetime.datetime.now() # 感谢群里大佬提供整点代码 - configCommon.checkSleepTime(self) # 晚上到点休眠 - if self.order_model is 1: + configCommon.checkSleepTime(self) # 晚上到点休眠 + if TickerConfig.ORDER_MODEL is 1: sleep_time_s = 0.5 sleep_time_t = 0.6 # 测试了一下有微妙级的误差,应该不影响,测试结果:2019-01-02 22:30:00.004555,预售还是会受到前一次刷新的时间影响,暂时没想到好的解决方案 - while not now.strftime("%H:%M:%S") == self.open_time: + while not now.strftime("%H:%M:%S") == TickerConfig.OPEN_TIME: now = datetime.datetime.now() - if now.strftime("%H:%M:%S") > self.open_time: + if now.strftime("%H:%M:%S") > TickerConfig.OPEN_TIME: break time.sleep(0.0001) else: @@ -234,12 +172,12 @@ class select: q = query(session=self, from_station=from_station, to_station=to_station, - from_station_h=self.from_station, - to_station_h=self.to_station, + from_station_h=TickerConfig.FROM_STATION, + to_station_h=TickerConfig.FROM_STATION, _station_seat=self._station_seat, - station_trains=self.station_trains, - station_dates=self.station_dates, - ticke_peoples_num=len(self.ticke_peoples), + station_trains=TickerConfig.STATION_TRAINS, + station_dates=TickerConfig.STATION_DATES, + ticke_peoples_num=len(TickerConfig.TICKET_PEOPLES), ) queryResult = q.sendQuery() # 查询接口 @@ -252,46 +190,55 @@ class select: leftTicket = queryResult.get("leftTicket", "") query_from_station_name = queryResult.get("query_from_station_name", "") query_to_station_name = queryResult.get("query_to_station_name", "") - is_more_ticket_num = queryResult.get("is_more_ticket_num", len(self.ticke_peoples)) + is_more_ticket_num = queryResult.get("is_more_ticket_num", len(TickerConfig.TICKET_PEOPLES)) if wrapcache.get(train_no): print(ticket.QUEUE_WARNING_MSG.format(train_no)) else: # 获取联系人 - s = getPassengerDTOs(session=self, ticket_peoples=self.ticke_peoples, - set_type=seat_conf_2[seat], + s = getPassengerDTOs(session=self, ticket_peoples=TickerConfig.TICKET_PEOPLES, + set_type="" if isinstance(seat, list) else seat_conf_2[seat], + # 候补订单需要设置多个坐席 is_more_ticket_num=is_more_ticket_num) getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr() if getPassengerDTOsResult.get("status", False): self.passengerTicketStrList = getPassengerDTOsResult.get("passengerTicketStrList", "") + self.passengerTicketStrByAfterLate = getPassengerDTOsResult.get( + "passengerTicketStrByAfterLate", "") self.oldPassengerStr = getPassengerDTOsResult.get("oldPassengerStr", "") self.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=self.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, self.set_type, - self.passengerTicketStrList, self.oldPassengerStr, train_date, - self.ticke_peoples) - sor.sendSubmitOrderRequest() + # 订单分为两种,一种为抢单,一种为候补订单 + if TickerConfig.TICKET_TYPE == 1: + if TickerConfig.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=self.set_type, + query_from_station_name=query_from_station_name, + query_to_station_name=query_to_station_name, + ) + a.sendAutoSubmitOrderRequest() + elif TickerConfig.ORDER_TYPE == 2: # 普通下单 + sor = submitOrderRequest(self, secretStr, from_station, to_station, train_no, + self.set_type, + self.passengerTicketStrList, self.oldPassengerStr, train_date, + TickerConfig.TICKET_PEOPLES) + sor.sendSubmitOrderRequest() + elif TickerConfig.TICKET_TYPE == 2: + c = chechFace(self, secretStr) + c.sendChechFace() else: random_time = round(random.uniform(sleep_time_s, sleep_time_t), 2) print(u"正在第{0}次查询 随机停留时长:{6} 乘车日期: {1} 车次:{2} 查询无票 cdn轮询IP:{4}当前cdn总数:{5} 总耗时:{3}ms".format(num, ",".join( - self.station_dates), + TickerConfig.STATION_DATES), ",".join( - self.station_trains), + TickerConfig.STATION_TRAINS), ( datetime.datetime.now() - now).microseconds / 1000, queryResult.get( diff --git a/inter/AutoSubmitOrderRequest.py b/inter/AutoSubmitOrderRequest.py index 92bdacf..8788e6a 100644 --- a/inter/AutoSubmitOrderRequest.py +++ b/inter/AutoSubmitOrderRequest.py @@ -3,7 +3,6 @@ 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 @@ -104,7 +103,7 @@ class autoSubmitOrderRequest: print(u"需要验证码") print(u"正在使用自动识别验证码功能") for i in range(3): - randCode = getRandCode(is_auto_code=True, auto_code_type=_get_yaml()["auto_code_type"]) + randCode = getRandCode(is_auto_code=True, auto_code_type=2) checkcode = checkRandCodeAnsyn(self.session, randCode, "") if checkcode == 'TRUE': print(u"验证码通过,正在提交订单") diff --git a/inter/ChechFace.py b/inter/ChechFace.py new file mode 100644 index 0000000..da49f7b --- /dev/null +++ b/inter/ChechFace.py @@ -0,0 +1,37 @@ +import urllib +from collections import OrderedDict +from config.urlConf import urls +import TickerConfig +from inter.GetSuccessRate import getSuccessRate + + +class chechFace: + def __init__(self, session, secretList): + """ + 人脸识别 + """ + self.secretList = secretList + self.session = session + + def data_apr(self): + """ + secretList 9vqa9%2B%2F%2Fsdozmm22hpSeDTGqRUwSuA2D0r%2BmU%2BLZj7MK7CDuf5Ep1xpxl4Dyxfmoah%2BaB9TZSesU%0AkxBbo5oNgR1vqMfvq66VP0T7tpQtH%2BbVGBz1FolZG8jDD%2FHqnz%2FnvdBP416Og6WGS14O%2F3iBSwT8%0AkRPsNF0Vq0U082g0tlJtP%2BPn7TzW3z7TDCceMJIjFcfEOA%2BW%2BuK%2Bpy6jCQMv0TmlkXf5aKcGnE02%0APuv4I8nF%2BOWjWzv9CrJyiCZiWaXd%2Bi7p69V3a9dhF787UgS660%2BqKRFB4RLwAfic3MkAlfpGWhMY%0ACfARVQ%3D%3D#O| + _json_att + 候补一次只能补一个座位,默认取TICKET_TYPE第一个 + :return: + """ + ticker = TickerConfig.PASSENGER_TICKER_STR.get(TickerConfig.SET_TYPE[0]) + data = OrderedDict() + data["secretList"] = f"{self.secretList}#{ticker}|" + data["_json_att"] = "" + return data + + def sendChechFace(self): + chechFaceRsp = self.session.httpClint.send(urls.get("chechFace"), self.data_apr()) + if not chechFaceRsp.get("status"): + print("".join(chechFaceRsp.get("messages")) or chechFaceRsp.get("validateMessages")) + return + g = getSuccessRate(self.session, self.secretList) + g.sendSuccessRate() + + diff --git a/inter/ConfirmHB.py b/inter/ConfirmHB.py new file mode 100644 index 0000000..bc72540 --- /dev/null +++ b/inter/ConfirmHB.py @@ -0,0 +1,43 @@ +from collections import OrderedDict +from config.urlConf import urls +import TickerConfig +from inter.GetQueueCount import queryQueueByAfterNate + + +class confirmHB: + def __init__(self, secretList, session, tickerNo): + """ + 人脸识别 + """ + self.secretList = secretList + self.session = session + self.passengerTicketStrByAfterLate = session.passengerTicketStrByAfterLate + self.tickerNo = tickerNo + + def data_apr(self): + """ + passengerInfo 1#XXXX#1#***************77X#bf6ae40d3655ae7eff005ee21d95876b38ab97a8031b464bc2f74a067e3ec957; + jzParam 2019-08-31#19#00 + hbTrain 5l000G177230,O# + lkParam + :return: + """ + ticker = TickerConfig.PASSENGER_TICKER_STR.get(TickerConfig.SET_TYPE[0]) + data = OrderedDict() + data["passengerInfo"] = self.passengerTicketStrByAfterLate + data["jzParam"] = TickerConfig.J_Z_PARAM + data["hbTrain"] = f"{self.tickerNo},{ticker}#" + data["lkParam"] = "" + return data + + def sendChechFace(self): + ChechFaceRsp = self.session.httpClint.send(urls.get("confirmHB"), self.data_apr()) + if not ChechFaceRsp.get("status"): + print("".join(ChechFaceRsp.get("messages")) or ChechFaceRsp.get("validateMessages")) + return + queue = queryQueueByAfterNate(self.session) + queue.sendQueryQueueByAfterNate() + + + + diff --git a/inter/ConfirmSingleForQueue.py b/inter/ConfirmSingleForQueue.py index d213006..9c6ecf0 100644 --- a/inter/ConfirmSingleForQueue.py +++ b/inter/ConfirmSingleForQueue.py @@ -2,7 +2,6 @@ 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 @@ -63,7 +62,7 @@ class confirmSingleForQueue: 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"]) + randCode = getRandCode(is_auto_code=True, auto_code_type=2) checkcode = checkRandCodeAnsyn(self.session, randCode, self.token) if checkcode == 'TRUE': print(u"验证码通过,正在提交订单") diff --git a/inter/GetPassengerDTOs.py b/inter/GetPassengerDTOs.py index 5d90f87..4055375 100644 --- a/inter/GetPassengerDTOs.py +++ b/inter/GetPassengerDTOs.py @@ -4,11 +4,7 @@ import json from config.TicketEnmu import ticket from myException.PassengerUserException import PassengerUserException import wrapcache - -try: - xrange # Python 2 -except NameError: - xrange = range # Python 3 +import TickerConfig class getPassengerDTOs: @@ -76,37 +72,49 @@ class getPassengerDTOs: """ passengerTicketStrList = [] oldPassengerStr = [] + tickers = [] + set_type = "" if wrapcache.get("user_info"): # 如果缓存中有联系人方式,则读取缓存中的联系人 user_info = wrapcache.get("user_info") print(u"使用缓存中查找的联系人信息") else: user_info = self.sendGetPassengerDTOs() wrapcache.set("user_info", user_info, timeout=9999999) - set_type = self.getPassengerTicketStr(self.set_type) if not user_info: raise PassengerUserException(ticket.DTO_NOT_IN_LIST) if len(user_info) < self.is_more_ticket_num: # 如果乘车人填错了导致没有这个乘车人的话,可能乘车人数会小于自动乘车人 self.is_more_ticket_num = len(user_info) - if self.is_more_ticket_num is 1: - passengerTicketStrList.append( - '0,' + user_info[0]['passenger_type'] + "," + user_info[0][ - "passenger_name"] + "," + - user_info[0]['passenger_id_type_code'] + "," + user_info[0]['passenger_id_no'] + "," + - user_info[0]['mobile_no'] + ',N,' + user_info[0]["allEncStr"]) - oldPassengerStr.append( - user_info[0]['passenger_name'] + "," + user_info[0]['passenger_id_type_code'] + "," + - user_info[0]['passenger_id_no'] + "," + user_info[0]['passenger_type'] + '_') - else: - for i in xrange(self.is_more_ticket_num): + if TickerConfig.TICKET_TYPE is 1: + set_type = self.getPassengerTicketStr(self.set_type) + if self.is_more_ticket_num is 1: passengerTicketStrList.append( - '0,' + user_info[i]['passenger_type'] + "," + user_info[i][ - "passenger_name"] + "," + user_info[i]['passenger_id_type_code'] + "," + user_info[i][ - 'passenger_id_no'] + "," + user_info[i]['mobile_no'] + ',N,' + user_info[i]["allEncStr"] + '_' + set_type) + '0,' + user_info[0]['passenger_type'] + "," + user_info[0][ + "passenger_name"] + "," + + user_info[0]['passenger_id_type_code'] + "," + user_info[0]['passenger_id_no'] + "," + + user_info[0]['mobile_no'] + ',N,' + user_info[0]["allEncStr"]) oldPassengerStr.append( - user_info[i]['passenger_name'] + "," + user_info[i]['passenger_id_type_code'] + "," + - user_info[i]['passenger_id_no'] + "," + user_info[i]['passenger_type'] + '_') + user_info[0]['passenger_name'] + "," + user_info[0]['passenger_id_type_code'] + "," + + user_info[0]['passenger_id_no'] + "," + user_info[0]['passenger_type'] + '_') + else: + for i in range(self.is_more_ticket_num): + passengerTicketStrList.append( + '0,' + user_info[i]['passenger_type'] + "," + user_info[i][ + "passenger_name"] + "," + user_info[i]['passenger_id_type_code'] + "," + user_info[i][ + 'passenger_id_no'] + "," + user_info[i]['mobile_no'] + ',N,' + user_info[i]["allEncStr"] + '_' + set_type) + oldPassengerStr.append( + user_info[i]['passenger_name'] + "," + user_info[i]['passenger_id_type_code'] + "," + + user_info[i]['passenger_id_no'] + "," + user_info[i]['passenger_type'] + '_') + elif TickerConfig.TICKET_TYPE is 2: + """ + 候补订单有多少个联系人,就候补多少个联系人了,没有优先提交之说 + 1#XXXX#1#***************77X#bf6ae40d3655ae7eff005ee21d95876b38ab97a8031b464bc2f74a067e3ec957; + """ + for user in user_info: + tickers.append(f"1#{user['passenger_name']}#1#{user['passenger_id_no']}#{user['allEncStr']};") + return { "passengerTicketStrList": set_type + "," + ",".join(passengerTicketStrList), + "passengerTicketStrByAfterLate": "".join(tickers), "oldPassengerStr": "".join(oldPassengerStr), "code": ticket.SUCCESS_CODE, "set_type": set_type, diff --git a/inter/GetQueueCount.py b/inter/GetQueueCount.py index 86d5ed3..e2c98b5 100644 --- a/inter/GetQueueCount.py +++ b/inter/GetQueueCount.py @@ -5,8 +5,13 @@ import time from collections import OrderedDict import wrapcache -from config.ticketConf import _get_yaml +import TickerConfig +from config.TicketEnmu import ticket +from config.emailConf import sendEmail +from config.pushbearConf import sendPushBear +from config.urlConf import urls from inter.ConfirmSingleForQueue import confirmSingleForQueue +from myException.ticketIsExitsException import ticketIsExitsException def conversion_int(str): @@ -94,15 +99,37 @@ class getQueueCount: 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) + timeout=TickerConfig.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) + timeout=TickerConfig.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) + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) else: print(u"未知错误 {0}".format("".join(getQueueCountResult))) + + +class queryQueueByAfterNate: + def __init__(self, session): + """ + 候补排队 + :param session: + """ + self.session = session + + def sendQueryQueueByAfterNate(self): + for i in range(10): + queryQueueByAfterNateRsp = self.session.httpClint.send(urls.get("queryQueue")) + if not queryQueueByAfterNateRsp.get("status"): + print("".join(queryQueueByAfterNateRsp.get("messages")) or queryQueueByAfterNateRsp.get("validateMessages")) + time.sleep(1) + else: + sendEmail(ticket.WAIT_ORDER_SUCCESS) + sendPushBear(sendEmail(ticket.WAIT_ORDER_SUCCESS)) + raise ticketIsExitsException(ticket.WAIT_AFTER_NATE_SUCCESS) + + diff --git a/inter/GetQueueCountAsync.py b/inter/GetQueueCountAsync.py index 50c7682..4df24b7 100644 --- a/inter/GetQueueCountAsync.py +++ b/inter/GetQueueCountAsync.py @@ -1,3 +1,5 @@ +import TickerConfig + []# coding=utf-8 import datetime import sys @@ -6,8 +8,6 @@ from collections import OrderedDict import wrapcache -from config.TicketEnmu import ticket -from config.ticketConf import _get_yaml from inter.ConfirmSingleForQueueAsys import confirmSingleForQueueAsys @@ -107,11 +107,11 @@ class getQueueCountAsync: else: 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) + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) elif "messages" in getQueueCountAsyncResult and getQueueCountAsyncResult["messages"]: 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) + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) else: if "validateMessages" in getQueueCountAsyncResult and getQueueCountAsyncResult["validateMessages"]: print(str(getQueueCountAsyncResult["validateMessages"])) diff --git a/inter/GetRandCode.py b/inter/GetRandCode.py index b51d4d0..b953d55 100644 --- a/inter/GetRandCode.py +++ b/inter/GetRandCode.py @@ -1,14 +1,7 @@ # coding=utf-8 from PIL import Image -from config.ticketConf import _get_yaml from verify.localVerifyCode import verify -from verify.ruokuai import RClient - -try: - raw_input # Python 2 -except NameError: # Python 3 - raw_input = input def getRandCode(is_auto_code, auto_code_type, result): @@ -48,7 +41,7 @@ def codexy(Ofset=None, is_raw_input=True): print(u"验证码分为8个,对应上面数字,例如第一和第二张,输入1, 2 如果开启cdn查询的话,会冲掉提示,直接鼠标点击命令行获取焦点,输入即可,不要输入空格") print(u"如果是linux无图形界面,请使用自动打码,is_auto_code: True") print(u"如果没有弹出验证码,请手动双击根目录下的tkcode.png文件") - Ofset = raw_input(u"输入对应的验证码: ") + Ofset = input(u"输入对应的验证码: ") if isinstance(Ofset, list): select = Ofset else: diff --git a/inter/GetSuccessRate.py b/inter/GetSuccessRate.py new file mode 100644 index 0000000..e5500f4 --- /dev/null +++ b/inter/GetSuccessRate.py @@ -0,0 +1,41 @@ +from collections import OrderedDict + + +from config.urlConf import urls +import TickerConfig +from inter.SubmitOrderRequest import submitOrderRequestByAfterNate + + +class getSuccessRate: + def __init__(self, session, secretList): + """ + 获取成功信息 + """ + self.secretList = secretList + self.session = session + + def data_apr(self): + """ + secretList 9vqa9%2B%2F%2Fsdozmm22hpSeDTGqRUwSuA2D0r%2BmU%2BLZj7MK7CDuf5Ep1xpxl4Dyxfmoah%2BaB9TZSesU%0AkxBbo5oNgR1vqMfvq66VP0T7tpQtH%2BbVGBz1FolZG8jDD%2FHqnz%2FnvdBP416Og6WGS14O%2F3iBSwT8%0AkRPsNF0Vq0U082g0tlJtP%2BPn7TzW3z7TDCceMJIjFcfEOA%2BW%2BuK%2Bpy6jCQMv0TmlkXf5aKcGnE02%0APuv4I8nF%2BOWjWzv9CrJyiCZiWaXd%2Bi7p69V3a9dhF787UgS660%2BqKRFB4RLwAfic3MkAlfpGWhMY%0ACfARVQ%3D%3D#O + _json_att + 候补一次只能补一个座位,默认取TICKET_TYPE第一个 + :return: + """ + + ticker = TickerConfig.PASSENGER_TICKER_STR.get(TickerConfig.SET_TYPE[0]) + data = OrderedDict() + data["successSecret"] = f"{self.secretList}#{ticker}" + data["_json_att"] = "" + return data + + def sendSuccessRate(self): + successRateRsp = self.session.httpClint.send(urls.get("getSuccessRate"), self.data_apr()) + if not successRateRsp.get("status"): + print("".join(successRateRsp.get("messages")) or successRateRsp.get("validateMessages")) + return + flag = successRateRsp.get("data", {}).get("flag")[0] + train_no = flag.get("train_no") + print(f"准备提交候补订单,{flag.get('info')}") + submit = submitOrderRequestByAfterNate(self.session, self.secretList, train_no) + submit.sendSubmitOrderRequest() + diff --git a/inter/Query.py b/inter/Query.py index 061e7de..15b9b58 100644 --- a/inter/Query.py +++ b/inter/Query.py @@ -1,16 +1,12 @@ # coding=utf-8 import copy -import threading -import time - import random - import wrapcache from config import urlConf from config.TicketEnmu import ticket from myUrllib.httpUtils import HTTPClient from config.configCommon import seat_conf_2 -from utils.timeUtil import time_to_minutes +import TickerConfig class query: @@ -21,7 +17,7 @@ class query: def __init__(self, session, from_station, to_station, from_station_h, to_station_h, _station_seat, station_trains, ticke_peoples_num, station_dates=None, ): self.session = session - self.httpClint = HTTPClient(session.is_proxy) + self.httpClint = HTTPClient(TickerConfig.IS_PROXY) self.urls = urlConf.urls self.from_station = from_station self.to_station = to_station @@ -32,14 +28,7 @@ class query: self.station_dates = station_dates if isinstance(station_dates, list) else list(station_dates) self.ticket_black_list = dict() self.ticke_peoples_num = ticke_peoples_num - # by time - self.is_by_time = session.is_by_time - self.train_types = session.train_types - self.departure_time = session.departure_time - self.arrival_time = session.arrival_time - self.take_time = session.take_time - @classmethod def station_seat(self, index): """ 获取车票对应坐席 @@ -57,37 +46,15 @@ class query: } return seat[index] - def check_time_interval(self, ticket_info): - """ - 判断日期是否符合当前设置时间 - fix: https://github.com/testerSunshine/12306/issues/256 - :param ticket_info: - :return: - """ - return self.departure_time <= time_to_minutes(ticket_info[8]) <= self.arrival_time and \ - time_to_minutes(ticket_info[9]) <= self.arrival_time and \ - time_to_minutes(ticket_info[10]) <= self.take_time - - def check_train_types(self, train): - train_type = train[0] - if train_type != "G" and train_type != "D": train_type = "O" - if train_type in self.train_types: - return True - else: - return False - def check_is_need_train(self, ticket_info): - if self.is_by_time: - return self.check_train_types(ticket_info[3]) and self.check_time_interval(ticket_info) - else: - return ticket_info[3] in self.station_trains + return ticket_info[3] in self.station_trains def sendQuery(self): """ 查询 :return: """ - if self.session.is_cdn == 1: + if TickerConfig.IS_CDN == 1: if self.session.cdn_list: self.httpClint.cdn = self.session.cdn_list[random.randint(0, len(self.session.cdn_list) - 1)] for station_date in self.station_dates: @@ -101,7 +68,7 @@ class query: continue value = station_ticket.get("data", "") if not value: - print(u'{0}-{1} 车次坐席查询为空,ip网络异常,可能是时间配置未正确,查询url: https://kyfw.12306.cn{2}, 可以手动查询是否有票'.format( + print(u'{0}-{1} 车次坐席查询为空,查询url: https://kyfw.12306.cn{2}, 可以手动查询是否有票'.format( self.from_station_h, self.to_station_h, select_url["req_url"])) @@ -110,63 +77,73 @@ class query: if result: for i in value['result']: ticket_info = i.split('|') - if ticket_info[11] == "Y" and ticket_info[1] == "预订": # 筛选未在开始时间内的车次 - for j in self._station_seat: - is_ticket_pass = ticket_info[j] - if is_ticket_pass != '' and is_ticket_pass != '无' and is_ticket_pass != '*' and self.check_is_need_train( - ticket_info): # 过滤有效目标车次 - 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] - leftTicket = ticket_info[12] - start_time = ticket_info[8] - arrival_time = ticket_info[9] - distance_time = ticket_info[10] - print(start_time, arrival_time, distance_time) - seat = j - try: - ticket_num = int(ticket_info[j]) - except ValueError: - ticket_num = "有" - print(u'车次: {0} 始发车站: {1} 终点站: {2} {3}: {4}'.format(ticket_info[3], - self.from_station_h, - self.to_station_h, - seat_conf_2[j], - ticket_num)) - if wrapcache.get(train_no): - print(ticket.QUERY_IN_BLACK_LIST.format(train_no)) - continue - else: - if ticket_num != "有" and self.ticke_peoples_num > ticket_num: - if self.session.is_more_ticket: - print( - u"余票数小于乘车人数,当前余票数: {}, 删减人车人数到: {}".format(ticket_num, ticket_num)) - is_more_ticket_num = ticket_num - else: - print(u"余票数小于乘车人数,当前设置不提交,放弃此次提交机会") - continue + if TickerConfig.TICKET_TYPE is 2 and self.check_is_need_train(ticket_info): + # 如果最后一位为1,则是可以候补的,不知道这些正确嘛? + if ticket_info[-2] == "1": + print("当前订单可以候补,尝试提交候补订单") + return { + "secretStr": ticket_info[0], + "seat": TickerConfig.SET_TYPE, + "status": True, + } + elif TickerConfig.TICKET_TYPE is 1: + if ticket_info[11] == "Y" and ticket_info[1] == "预订": # 筛选未在开始时间内的车次 + for j in self._station_seat: + is_ticket_pass = ticket_info[j] + if is_ticket_pass != '' and is_ticket_pass != '无' and is_ticket_pass != '*' and self.check_is_need_train( + ticket_info): # 过滤有效目标车次 + 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] + leftTicket = ticket_info[12] + start_time = ticket_info[8] + arrival_time = ticket_info[9] + distance_time = ticket_info[10] + print(start_time, arrival_time, distance_time) + seat = j + try: + ticket_num = int(ticket_info[j]) + except ValueError: + ticket_num = "有" + print(u'车次: {0} 始发车站: {1} 终点站: {2} {3}: {4}'.format(ticket_info[3], + self.from_station_h, + self.to_station_h, + seat_conf_2[j], + ticket_num)) + if wrapcache.get(train_no): + print(ticket.QUERY_IN_BLACK_LIST.format(train_no)) + continue else: - print(u"设置乘车人数为: {}".format(self.ticke_peoples_num)) - is_more_ticket_num = self.ticke_peoples_num - print(ticket.QUERY_C) - return { - "secretStr": secretStr, - "train_no": train_no, - "stationTrainCode": stationTrainCode, - "train_date": station_date, - "query_from_station_name": query_from_station_name, - "query_to_station_name": query_to_station_name, - "seat": seat, - "leftTicket": leftTicket, - "train_location": train_location, - "code": ticket.SUCCESS_CODE, - "is_more_ticket_num": is_more_ticket_num, - "cdn": self.httpClint.cdn, - "status": True, - } + if ticket_num != "有" and self.ticke_peoples_num > ticket_num: + if self.session.is_more_ticket: + print( + u"余票数小于乘车人数,当前余票数: {}, 删减人车人数到: {}".format(ticket_num, ticket_num)) + is_more_ticket_num = ticket_num + else: + print(u"余票数小于乘车人数,当前设置不提交,放弃此次提交机会") + continue + else: + print(u"设置乘车人数为: {}".format(self.ticke_peoples_num)) + is_more_ticket_num = self.ticke_peoples_num + print(ticket.QUERY_C) + return { + "secretStr": secretStr, + "train_no": train_no, + "stationTrainCode": stationTrainCode, + "train_date": station_date, + "query_from_station_name": query_from_station_name, + "query_to_station_name": query_to_station_name, + "seat": seat, + "leftTicket": leftTicket, + "train_location": train_location, + "code": ticket.SUCCESS_CODE, + "is_more_ticket_num": is_more_ticket_num, + "cdn": self.httpClint.cdn, + "status": True, + } else: print(u"车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket)) return {"code": ticket.FAIL_CODE, "status": False, "cdn": self.httpClint.cdn, } diff --git a/inter/SubmitOrderRequest.py b/inter/SubmitOrderRequest.py index cb422dc..7cac605 100644 --- a/inter/SubmitOrderRequest.py +++ b/inter/SubmitOrderRequest.py @@ -1,8 +1,11 @@ # coding=utf-8 import datetime import urllib - +from collections import OrderedDict +import TickerConfig +from config.urlConf import urls from inter.CheckOrderInfo import checkOrderInfo +from inter.ConfirmHB import confirmHB from myException.ticketIsExitsException import ticketIsExitsException @@ -19,6 +22,7 @@ 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 try: self.secretStr = urllib.unquote(secretStr) except AttributeError: @@ -42,8 +46,9 @@ class submitOrderRequest: ('back_train_date', time()), # 返程时间 ('tour_flag', 'dc'), # 旅途类型 ('purpose_codes', 'ADULT'), # 成人票还是学生票 - ('query_from_station_name', self.from_station), # 起始车站 - ('query_to_station_name', self.to_station), # 终点车站 + ('query_from_station_name', TickerConfig.FROM_STATION), # 起始车站 + ('query_to_station_name', TickerConfig.TO_STATION), # 终点车站 + ('undefined', ''), ] return data @@ -68,3 +73,37 @@ class submitOrderRequest: print (u'出票失败') elif 'messages' in submitResult and submitResult['messages']: raise ticketIsExitsException(submitResult['messages'][0]) + + +class submitOrderRequestByAfterNate: + def __init__(self, session, secretList, tickerNo): + """ + 提交候补订单 + :param secretList: + :param session: + """ + self.secretList = secretList + self.session = session + self.tickerNo = tickerNo + + def data_apr(self): + """ + secretList 9vqa9%2B%2F%2Fsdozmm22hpSeDTGqRUwSuA2D0r%2BmU%2BLZj7MK7CDuf5Ep1xpxl4Dyxfmoah%2BaB9TZSesU%0AkxBbo5oNgR1vqMfvq66VP0T7tpQtH%2BbVGBz1FolZG8jDD%2FHqnz%2FnvdBP416Og6WGS14O%2F3iBSwT8%0AkRPsNF0Vq0U082g0tlJtP%2BPn7TzW3z7TDCceMJIjFcfEOA%2BW%2BuK%2Bpy6jCQMv0TmlkXf5aKcGnE02%0APuv4I8nF%2BOWjWzv9CrJyiCZiWaXd%2Bi7p69V3a9dhF787UgS660%2BqKRFB4RLwAfic3MkAlfpGWhMY%0ACfARVQ%3D%3D#O| + _json_att + 候补一次只能补一个座位,默认取TICKET_TYPE第一个 + :return: + """ + + ticker = TickerConfig.PASSENGER_TICKER_STR.get(TickerConfig.SET_TYPE[0]) + data = OrderedDict() + data["secretList"] = f"{self.secretList}#{ticker}|" + data["_json_att"] = "" + return data + + def sendSubmitOrderRequest(self, ): + submitOrderRequestRsp = self.session.httpClint.send(urls.get("SubmitOrderRequestRsp"), self.data_apr()) + if not submitOrderRequestRsp.get("status"): + print("".join(submitOrderRequestRsp.get("messages")) or submitOrderRequestRsp.get("validateMessages")) + return + confirm = confirmHB(self.secretList, self.session, self.tickerNo) + confirm.sendChechFace() diff --git a/tkcode.png b/tkcode.png index b8faea4..8416dca 100644 Binary files a/tkcode.png and b/tkcode.png differ