Compare commits
126 Commits
revert-325
...
1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c87724d170 | ||
|
|
cdedfa859d | ||
|
|
484c5f2aa3 | ||
|
|
996fc245cc | ||
|
|
66ad9c9e5c | ||
|
|
e81a239609 | ||
|
|
8ed02ea625 | ||
|
|
9462e0d72c | ||
|
|
696f888ad1 | ||
|
|
68445e1913 | ||
|
|
547300b609 | ||
|
|
4398e60305 | ||
|
|
15f6932f50 | ||
|
|
35c45bbeac | ||
|
|
f781c353c3 | ||
|
|
79929da88d | ||
|
|
25ba185c27 | ||
|
|
33e38da2b2 | ||
|
|
91e68f68c6 | ||
|
|
5c8a1327dc | ||
|
|
8b90194f65 | ||
|
|
5eb412d45a | ||
|
|
864c239a24 | ||
|
|
3a7700c2d4 | ||
|
|
c613b54dec | ||
|
|
0c8174592d | ||
|
|
05ffcffe68 | ||
|
|
c2cf3ef79c | ||
|
|
69f1a84c04 | ||
|
|
21b092245b | ||
|
|
6d47181513 | ||
|
|
89c7e2b0f9 | ||
|
|
1ff1676f46 | ||
|
|
493411ecbf | ||
|
|
b72f7ec5dc | ||
|
|
ecd809dc16 | ||
|
|
26063f5be6 | ||
|
|
532e165688 | ||
|
|
901ba7f15a | ||
|
|
2e89bd1d89 | ||
|
|
8139eef48f | ||
|
|
deab8142a1 | ||
|
|
e4831d6df9 | ||
|
|
9b7f16d60a | ||
|
|
e6b30b8427 | ||
|
|
d4e1ef1049 | ||
|
|
033c34e035 | ||
|
|
ab84b92665 | ||
|
|
5ef5df52a5 | ||
|
|
b93807155e | ||
|
|
b3683cbbd2 | ||
|
|
25b6bd536a | ||
|
|
d4339e2e38 | ||
|
|
e7f293edaf | ||
|
|
9346546dd9 | ||
|
|
45ce85afde | ||
|
|
7437564e64 | ||
|
|
d98c98069a | ||
|
|
76a2b0f98a | ||
|
|
e4f20350fe | ||
|
|
71f2972e3f | ||
|
|
957c768a43 | ||
|
|
6685c1570e | ||
|
|
6a5d58605d | ||
|
|
ebca190c26 | ||
|
|
e788bb03cc | ||
|
|
02b6169b35 | ||
|
|
1719bc718a | ||
|
|
21fa98c9d0 | ||
|
|
08ff445604 | ||
|
|
e0b10870dd | ||
|
|
2b5e0cf8be | ||
|
|
8a0309dd7c | ||
|
|
18df704c08 | ||
|
|
d7c9a1cbd4 | ||
|
|
b78f1c6af7 | ||
|
|
ae418ec3dd | ||
|
|
9f8187a58f | ||
|
|
b333b09f83 | ||
|
|
82b1f2c3c6 | ||
|
|
c8988cd214 | ||
|
|
01cf6cca33 | ||
|
|
f724139d8c | ||
|
|
454d5b2fbf | ||
|
|
70e2c0e736 | ||
|
|
25049389ff | ||
|
|
7c62c1ebad | ||
|
|
5838026b25 | ||
|
|
a0bdc4ca82 | ||
|
|
3b15f260ae | ||
|
|
fc595d4590 | ||
|
|
b1e826b27a | ||
|
|
c49ac26f0e | ||
|
|
5d492c8e9e | ||
|
|
ee677c56ee | ||
|
|
a337f972a8 | ||
|
|
d5097d2374 | ||
|
|
0c14ebd0ab | ||
|
|
845f303293 | ||
|
|
dba893e705 | ||
|
|
8e9468406a | ||
|
|
ed04957863 | ||
|
|
ba489fd9bc | ||
|
|
a87f10c884 | ||
|
|
da469f3ea1 | ||
|
|
247c46db2a | ||
|
|
ebdd2b6645 | ||
|
|
bbba2caab6 | ||
|
|
f93fdcfd88 | ||
|
|
b323e3d953 | ||
|
|
e25dda3a03 | ||
|
|
2ee8dc5da1 | ||
|
|
c804de2e07 | ||
|
|
5de41150d9 | ||
|
|
6dc09572c1 | ||
|
|
b0888dd8c6 | ||
|
|
0b054997c5 | ||
|
|
da5f4e93c6 | ||
|
|
bc29d8a8aa | ||
|
|
a0f26435b7 | ||
|
|
054c476c4e | ||
|
|
bb136d17ba | ||
|
|
33be8c9237 | ||
|
|
98bafed66c | ||
|
|
bcf1f623d6 | ||
|
|
44d9a91da6 |
14
README.md
14
README.md
@@ -1,6 +1,10 @@
|
||||
# 🚂 py12306 购票助手
|
||||
分布式,多账号,多任务购票
|
||||
|
||||
## 前言
|
||||
今年回家的票明显要难买很多,早早就答应了父母今年的票没问题,到现在一张票没买到,虽然家里已经订了汽车票,让我不用操心,但是想想他们一行还有小孩,心还是很伤的。
|
||||
这段时间从 12306Bypass 到 testerSunshine 大佬写的 [12306](https://github.com/testerSunshine/12306),还是没买到票,索性就自己写了一个,希望也能帮助到更多人
|
||||
|
||||
## Features
|
||||
- [x] 多日期查询余票
|
||||
- [x] 自动打码下单
|
||||
@@ -14,7 +18,7 @@
|
||||
- [x] 邮件通知
|
||||
- [x] Web 管理页面
|
||||
- [x] 微信消息通知
|
||||
- [ ] 代理池支持 ([pyproxy-async](https://github.com/pjialin/pyproxy-async))
|
||||
- [ ] 代理池支持
|
||||
|
||||
## 使用
|
||||
py12306 需要运行在 python 3.6 以上版本(其它版本暂未测试)
|
||||
@@ -32,8 +36,9 @@ cp env.py.example env.py
|
||||
```
|
||||
自动打码
|
||||
|
||||
(若快已停止服务,目前只能设置**free**打码模式)
|
||||
free 已对接到打码共享平台,[https://py12306-helper.pjialin.com](https://py12306-helper.pjialin.com/),欢迎参与分享
|
||||
目前支持免费打码,和若快打码
|
||||
|
||||
注:免费打码无法保证持续可用,如失效请手动切换到若快平台,需要先到 [http://www.ruokuai.com](http://www.ruokuai.com/login) 注册一个账号后填写到配置中
|
||||
|
||||
语音通知
|
||||
|
||||
@@ -143,7 +148,7 @@ docker-compose up -d
|
||||
### 关于防封
|
||||
目前查询和登录操作是分开的,查询是不依赖用户是否登录,放在 A 云 T 云容易被限制 ip,建议在其它网络环境下运行
|
||||
|
||||
QQ 交流群 [780289875](https://jq.qq.com/?_wv=1027&k=5PgzDwV),TG 群 [Py12306 交流](https://t.me/joinchat/F3sSegrF3x8KAmsd1mTu7w)
|
||||
交流群 [274781597](http://shang.qq.com/wpa/qunwpa?idkey=8eab0b6402096266a62263c1cd452149926adb5cba7a2b7a98a5adc65869addf)
|
||||
|
||||
### Online IDE
|
||||
[](https://gitpod.io#https://github.com/pjialin/py12306)
|
||||
@@ -151,7 +156,6 @@ QQ 交流群 [780289875](https://jq.qq.com/?_wv=1027&k=5PgzDwV),TG 群 [Py1230
|
||||
## Thanks
|
||||
- 感谢大佬 [testerSunshine](https://github.com/testerSunshine/12306),借鉴了部分实现
|
||||
- 感谢所有提供 pr 的大佬
|
||||
- 感谢大佬 [zhaipro](https://github.com/zhaipro/easy12306) 的验证码本地识别模型与算法
|
||||
|
||||
## License
|
||||
|
||||
|
||||
48
data/cdn.txt
48
data/cdn.txt
@@ -2218,51 +2218,3 @@
|
||||
117.27.241.218
|
||||
112.65.92.116
|
||||
52.114.128.43
|
||||
183.66.109.254
|
||||
60.28.100.248
|
||||
111.161.122.240
|
||||
121.31.28.101
|
||||
222.218.87.252
|
||||
113.16.212.251
|
||||
58.18.254.253
|
||||
124.225.107.254
|
||||
14.204.186.174
|
||||
14.204.185.254
|
||||
14.204.185.123
|
||||
220.165.142.253
|
||||
42.123.108.8
|
||||
42.123.107.43
|
||||
120.241.66.115
|
||||
112.90.135.229
|
||||
183.56.172.113
|
||||
27.155.108.102
|
||||
27.155.108.93
|
||||
61.132.238.115
|
||||
113.194.59.199
|
||||
218.64.94.181
|
||||
122.191.168.109
|
||||
42.49.185.169
|
||||
42.49.185.170
|
||||
175.154.187.252
|
||||
118.123.233.254
|
||||
118.123.237.245
|
||||
123.138.157.122
|
||||
113.142.80.223
|
||||
117.23.2.252
|
||||
218.26.75.236
|
||||
218.26.75.206
|
||||
183.131.124.249
|
||||
36.25.241.251
|
||||
153.99.235.91
|
||||
221.230.143.254
|
||||
120.221.24.14
|
||||
218.58.205.182
|
||||
182.34.127.253
|
||||
150.138.214.124
|
||||
61.54.7.192
|
||||
115.54.16.245
|
||||
218.12.228.246
|
||||
121.22.247.254
|
||||
124.236.28.230
|
||||
218.60.185.251
|
||||
42.101.72.9
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -115,8 +115,8 @@ QUERY_JOBS = [
|
||||
# 'job_name': 'bj -> sz', # 任务名称,不填默认会以车站名命名,不可重复
|
||||
'account_key': 0, # 将会使用指定账号下单
|
||||
'left_dates': [ # 出发日期 :Array
|
||||
"2020-01-25",
|
||||
"2020-01-26",
|
||||
"2019-01-25",
|
||||
"2019-01-26",
|
||||
],
|
||||
'stations': { # 车站 支持多个车站同时查询 :Dict or :List
|
||||
'left': '北京',
|
||||
@@ -132,7 +132,7 @@ QUERY_JOBS = [
|
||||
# }],
|
||||
'members': [ # 乘客姓名,会根据当前账号自动识别乘客类型 购买儿童票 设置两个相同的姓名即可,程序会自动识别 如 ['张三', '张三']
|
||||
"张三",
|
||||
#"*王五", #在姓名前加*表示学生购买成人票
|
||||
"王五",
|
||||
# 7, # 支持通过序号确定唯一乘客,序号查看可通过 python main.py -t 登录成功之后在 runtime/user/ 下找到对应的 用户名_passengers.json 文件,找到对应的 code 填入
|
||||
],
|
||||
'allow_less_member': 0, # 是否允许余票不足时提交部分乘客
|
||||
|
||||
@@ -15,7 +15,7 @@ def app_available_check():
|
||||
if Config().IS_DEBUG:
|
||||
return True
|
||||
now = time_now()
|
||||
if (now.hour >= 23 and now.minute >= 30) or now.hour < 6:
|
||||
if now.hour >= 23 or now.hour < 6:
|
||||
CommonLog.add_quick_log(CommonLog.MESSAGE_12306_IS_CLOSED.format(time_now())).flush()
|
||||
open_time = datetime.datetime(now.year, now.month, now.day, 6)
|
||||
if open_time < now:
|
||||
|
||||
@@ -2,7 +2,7 @@ import math
|
||||
import random
|
||||
|
||||
from py12306.config import Config
|
||||
from py12306.helpers.api import API_FREE_CODE_QCR_API
|
||||
from py12306.helpers.api import *
|
||||
from py12306.helpers.request import Request
|
||||
from py12306.log.common_log import CommonLog
|
||||
from py12306.vender.ruokuai.main import RKClient
|
||||
@@ -56,13 +56,22 @@ class OCR:
|
||||
|
||||
def get_image_by_free_site(self, img):
|
||||
data = {
|
||||
'img': img
|
||||
'base64': img
|
||||
}
|
||||
response = self.session.post(API_FREE_CODE_QCR_API, data=data, timeout=30)
|
||||
response = self.session.post(API_FREE_CODE_QCR_API, json=data)
|
||||
result = response.json()
|
||||
if result.get('msg') == 'success':
|
||||
pos = result.get('result')
|
||||
return self.get_image_position_by_offset(pos)
|
||||
if result.get('success') and result.get('data.check'):
|
||||
check_data = {
|
||||
'check': result.get('data.check'),
|
||||
'img_buf': img,
|
||||
'logon': 1,
|
||||
'type': 'D'
|
||||
}
|
||||
check_response = self.session.post(API_FREE_CODE_QCR_API_CHECK, json=check_data)
|
||||
check_result = check_response.json()
|
||||
if check_result.get('res'):
|
||||
position = check_result.get('res')
|
||||
return position.replace('(', '').replace(')', '').split(',')
|
||||
|
||||
CommonLog.print_auto_code_fail(CommonLog.MESSAGE_GET_RESPONSE_FROM_FREE_AUTO_CODE)
|
||||
return None
|
||||
|
||||
@@ -40,11 +40,12 @@ API_GET_QUEUE_COUNT = BASE_URL_OF_12306 + '/otn/confirmPassenger/getQueueCount'
|
||||
API_CONFIRM_SINGLE_FOR_QUEUE = BASE_URL_OF_12306 + '/otn/confirmPassenger/confirmSingleForQueue'
|
||||
API_QUERY_ORDER_WAIT_TIME = BASE_URL_OF_12306 + '/otn/confirmPassenger/queryOrderWaitTime?{}' # 排队查询
|
||||
API_QUERY_INIT_PAGE = BASE_URL_OF_12306 + '/otn/leftTicket/init'
|
||||
# API_GET_BROWSER_DEVICE_ID = BASE_URL_OF_12306 + '/otn/HttpZF/logdevice'
|
||||
API_GET_BROWSER_DEVICE_ID = 'https://12306-rail-id-v2.pjialin.com/'
|
||||
API_FREE_CODE_QCR_API = 'https://12306-ocr.pjialin.com/check/'
|
||||
|
||||
API_NOTIFICATION_BY_VOICE_CODE = 'http://ali-voice.showapi.com/sendVoice?'
|
||||
API_NOTIFICATION_BY_VOICE_CODE_DINGXIN = 'http://yuyin2.market.alicloudapi.com/dx/voice_notice'
|
||||
|
||||
# API_FREE_CODE_QCR_API = 'http://60.205.200.159/api' # 19-03-07 接口已失效
|
||||
API_FREE_CODE_QCR_API = 'https://12306.jiedanba.cn/api/v2/getCheck'
|
||||
API_FREE_CODE_QCR_API_CHECK = 'http://check.huochepiao.360.cn/img_vcode'
|
||||
|
||||
API_CHECK_CDN_AVAILABLE = 'https://{}/otn/dynamicJs/omseuuq'
|
||||
|
||||
@@ -33,7 +33,6 @@ class AuthCode:
|
||||
return self.retry_get_auth_code()
|
||||
|
||||
answer = ','.join(map(str, position))
|
||||
|
||||
if not self.check_code(answer):
|
||||
return self.retry_get_auth_code()
|
||||
return position
|
||||
@@ -47,7 +46,6 @@ class AuthCode:
|
||||
url = API_AUTH_CODE_BASE64_DOWNLOAD.format(random=random.random())
|
||||
# code_path = self.data_path + 'code.png'
|
||||
try:
|
||||
self.session.cookies.clear_session_cookies()
|
||||
UserLog.add_quick_log(UserLog.MESSAGE_DOWNLAODING_THE_CODE).flush()
|
||||
# response = self.session.save_to_file(url, code_path) # TODO 返回错误情况
|
||||
response = self.session.get(url)
|
||||
|
||||
@@ -125,9 +125,9 @@ class Notification():
|
||||
message.set_content(content)
|
||||
try:
|
||||
server = smtplib.SMTP(Config().EMAIL_SERVER_HOST)
|
||||
server.login(Config().EMAIL_SERVER_USER, Config().EMAIL_SERVER_PASSWORD)
|
||||
server.ehlo()
|
||||
server.starttls()
|
||||
server.login(Config().EMAIL_SERVER_USER, Config().EMAIL_SERVER_PASSWORD)
|
||||
server.send_message(message)
|
||||
server.quit()
|
||||
CommonLog.add_quick_log(CommonLog.MESSAGE_SEND_EMAIL_SUCCESS).flush()
|
||||
|
||||
@@ -33,9 +33,8 @@ class Request(HTMLSession):
|
||||
return response
|
||||
|
||||
def add_response_hook(self, hook):
|
||||
hooks = self.hooks['response']
|
||||
if not isinstance(hooks, list):
|
||||
hooks = [hooks]
|
||||
exist_hooks = self.hooks['response']
|
||||
if not isinstance(exist_hooks, list): hooks = [exist_hooks]
|
||||
hooks.append(hook)
|
||||
self.hooks['response'] = hooks
|
||||
return self
|
||||
|
||||
@@ -94,24 +94,15 @@ class CommonLog(BaseLog):
|
||||
self.add_quick_log('多线程查询: {}'.format(get_true_false_text(Config().QUERY_JOB_THREAD_ENABLED, enable, disable)))
|
||||
self.add_quick_log('CDN 状态: {}'.format(get_true_false_text(Config().CDN_ENABLED, enable, disable))).flush()
|
||||
self.add_quick_log('通知状态:')
|
||||
if Config().NOTIFICATION_BY_VOICE_CODE:
|
||||
self.add_quick_log(
|
||||
'语音验证码: {}'.format(get_true_false_text(Config().NOTIFICATION_BY_VOICE_CODE, enable, disable)))
|
||||
if Config().EMAIL_ENABLED:
|
||||
self.add_quick_log('邮件通知: {}'.format(get_true_false_text(Config().EMAIL_ENABLED, enable, disable)))
|
||||
if Config().DINGTALK_ENABLED:
|
||||
self.add_quick_log('钉钉通知: {}'.format(get_true_false_text(Config().DINGTALK_ENABLED, enable, disable)))
|
||||
if Config().TELEGRAM_ENABLED:
|
||||
self.add_quick_log('Telegram通知: {}'.format(get_true_false_text(Config().TELEGRAM_ENABLED, enable, disable)))
|
||||
if Config().SERVERCHAN_ENABLED:
|
||||
self.add_quick_log(
|
||||
'ServerChan通知: {}'.format(get_true_false_text(Config().SERVERCHAN_ENABLED, enable, disable)))
|
||||
if Config().BARK_ENABLED:
|
||||
self.add_quick_log('Bark通知: {}'.format(get_true_false_text(Config().BARK_ENABLED, enable, disable)))
|
||||
if Config().PUSHBEAR_ENABLED:
|
||||
self.add_quick_log(
|
||||
'PushBear通知: {}'.format(get_true_false_text(Config().PUSHBEAR_ENABLED, enable, disable)))
|
||||
self.add_quick_log().flush(sep='\t\t')
|
||||
self.add_quick_log(
|
||||
'语音验证码: {}'.format(get_true_false_text(Config().NOTIFICATION_BY_VOICE_CODE, enable, disable)))
|
||||
self.add_quick_log('邮件通知: {}'.format(get_true_false_text(Config().EMAIL_ENABLED, enable, disable)))
|
||||
self.add_quick_log('钉钉通知: {}'.format(get_true_false_text(Config().DINGTALK_ENABLED, enable, disable)))
|
||||
self.add_quick_log('Telegram通知: {}'.format(get_true_false_text(Config().TELEGRAM_ENABLED, enable, disable)))
|
||||
self.add_quick_log('ServerChan通知: {}'.format(get_true_false_text(Config().SERVERCHAN_ENABLED, enable, disable)))
|
||||
self.add_quick_log('Bark通知: {}'.format(get_true_false_text(Config().BARK_ENABLED, enable, disable)))
|
||||
self.add_quick_log(
|
||||
'PushBear通知: {}'.format(get_true_false_text(Config().PUSHBEAR_ENABLED, enable, disable))).flush(sep='\t\t')
|
||||
self.add_quick_log('查询间隔: {} 秒'.format(Config().QUERY_INTERVAL))
|
||||
self.add_quick_log('用户心跳检测间隔: {} 秒'.format(Config().USER_HEARTBEAT_INTERVAL))
|
||||
self.add_quick_log('WEB 管理页面: {}'.format(get_true_false_text(Config().WEB_ENABLE, enable, disable)))
|
||||
@@ -139,10 +130,3 @@ class CommonLog(BaseLog):
|
||||
self.add_quick_log('打码失败: 错误原因 {reason}'.format(reason=reason))
|
||||
self.flush()
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def print_auth_code_info(cls, reason):
|
||||
self = cls()
|
||||
self.add_quick_log('打码信息: {reason}'.format(reason=reason))
|
||||
self.flush()
|
||||
return self
|
||||
|
||||
@@ -63,14 +63,10 @@ class Order:
|
||||
return self.order_did_success()
|
||||
elif not order_request_res:
|
||||
return
|
||||
if not self.user_ins.request_init_dc_page():
|
||||
return
|
||||
if not self.check_order_info():
|
||||
return
|
||||
if not self.get_queue_count():
|
||||
return
|
||||
if not self.confirm_single_for_queue():
|
||||
return
|
||||
if not self.user_ins.request_init_dc_page(): return
|
||||
if not self.check_order_info(): return
|
||||
if not self.get_queue_count(): return
|
||||
if not self.confirm_single_for_queue(): return
|
||||
order_id = self.query_order_wait_time()
|
||||
if order_id: # 发送通知
|
||||
self.order_id = order_id
|
||||
@@ -378,12 +374,10 @@ class Order:
|
||||
elif 'waitTime' in result_data:
|
||||
# 计算等待时间
|
||||
wait_time = int(result_data.get('waitTime'))
|
||||
if wait_time == -1: # 成功
|
||||
if wait_time == -1 or wait_time == -100: # 成功
|
||||
# /otn/confirmPassenger/resultOrderForDcQueue 请求订单状态 目前不需要
|
||||
# 不应该走到这
|
||||
return order_id
|
||||
elif wait_time == -100: # 重新获取订单号
|
||||
pass
|
||||
elif wait_time >= 0: # 等待
|
||||
OrderLog.add_quick_log(
|
||||
OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING.format(result_data.get('waitCount', 0),
|
||||
@@ -435,12 +429,11 @@ class Order:
|
||||
OrderLog.print_passenger_did_deleted(available_passengers)
|
||||
|
||||
for passenger in available_passengers:
|
||||
tmp_str = '{seat_type},0,{passenger_type},{passenger_name},{passenger_id_card_type},{passenger_id_card},{passenger_mobile},N,{enc_str}_'.format(
|
||||
tmp_str = '{seat_type},0,{passenger_type},{passenger_name},{passenger_id_card_type},{passenger_id_card},{passenger_mobile},N_'.format(
|
||||
seat_type=self.query_ins.current_order_seat, passenger_type=passenger['type'],
|
||||
passenger_name=passenger['name'],
|
||||
passenger_id_card_type=passenger['id_card_type'], passenger_id_card=passenger['id_card'],
|
||||
passenger_mobile=passenger['mobile'],
|
||||
enc_str=passenger['enc_str'],
|
||||
passenger_mobile=passenger['mobile']
|
||||
)
|
||||
passenger_tickets.append(tmp_str)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import sys
|
||||
from datetime import timedelta
|
||||
from datetime import datetime
|
||||
|
||||
from py12306.app import app_available_check
|
||||
from py12306.cluster.cluster import Cluster
|
||||
@@ -67,8 +66,6 @@ class Job:
|
||||
INDEX_LEFT_TIME = 8
|
||||
INDEX_ARRIVE_TIME = 9
|
||||
|
||||
max_buy_time = 32
|
||||
|
||||
def __init__(self, info, query):
|
||||
self.cluster = Cluster()
|
||||
self.query = query
|
||||
@@ -139,29 +136,11 @@ class Job:
|
||||
QueryLog.add_log('\n').flush(sep='\t\t', publish=False)
|
||||
if Const.IS_TEST: return
|
||||
|
||||
def judge_date_legal(self, date):
|
||||
date_now = datetime.datetime.now()
|
||||
date_query = datetime.datetime.strptime(str(date), "%Y-%m-%d")
|
||||
diff = (date_query - date_now).days
|
||||
if date_now.day == date_query.day:
|
||||
diff = 0
|
||||
if diff < 0:
|
||||
msg = '乘车日期错误,比当前时间还早!!'
|
||||
QueryLog.add_quick_log(msg).flush(publish=False)
|
||||
raise RuntimeError(msg)
|
||||
elif diff > self.max_buy_time:
|
||||
msg = '乘车日期错误,超出一个月预售期!!'
|
||||
QueryLog.add_quick_log(msg).flush(publish=False)
|
||||
raise RuntimeError(msg)
|
||||
else:
|
||||
pass
|
||||
|
||||
def query_by_date(self, date):
|
||||
"""
|
||||
通过日期进行查询
|
||||
:return:
|
||||
"""
|
||||
self.judge_date_legal(date)
|
||||
from py12306.helpers.cdn import Cdn
|
||||
QueryLog.add_log(('\n' if not is_main_thread() else '') + QueryLog.MESSAGE_QUERY_START_BY_DATE.format(date,
|
||||
self.left_station,
|
||||
|
||||
@@ -149,7 +149,7 @@ class Query:
|
||||
return self.api_type
|
||||
response = self.session.get(API_QUERY_INIT_PAGE)
|
||||
if response.status_code == 200:
|
||||
res = re.search(r'var CLeftTicketUrl = \'(.*)\';', response.text)
|
||||
res = re.search(r'var CLeftTicketUrl = \'(leftTicket/queryX)\';', response.text)
|
||||
try:
|
||||
self.api_type = res.group(1)
|
||||
except IndexError:
|
||||
|
||||
@@ -125,7 +125,6 @@ class UserJob:
|
||||
}
|
||||
answer = AuthCode.get_auth_code(self.session)
|
||||
data['answer'] = answer
|
||||
self.request_device_id()
|
||||
response = self.session.post(API_BASE_LOGIN.get('url'), data)
|
||||
result = response.json()
|
||||
if result.get('result_code') == 0: # 登录成功
|
||||
@@ -161,10 +160,7 @@ class UserJob:
|
||||
return is_login
|
||||
|
||||
def auth_uamtk(self):
|
||||
response = self.session.post(API_AUTH_UAMTK.get('url'), {'appid': 'otn'}, headers={
|
||||
'Referer': 'https://kyfw.12306.cn/otn/passport?redirect=/otn/login/userLogin',
|
||||
'Origin': 'https://kyfw.12306.cn'
|
||||
})
|
||||
response = self.session.post(API_AUTH_UAMTK.get('url'), {'appid': 'otn'})
|
||||
result = response.json()
|
||||
if result.get('newapptk'):
|
||||
return result.get('newapptk')
|
||||
@@ -179,31 +175,6 @@ class UserJob:
|
||||
# TODO 处理获取失败情况
|
||||
return False
|
||||
|
||||
def request_device_id(self):
|
||||
"""
|
||||
获取加密后的浏览器特征 ID
|
||||
:return:
|
||||
"""
|
||||
response = self.session.get(API_GET_BROWSER_DEVICE_ID)
|
||||
if response.status_code == 200:
|
||||
try:
|
||||
result = json.loads(response.text)
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
|
||||
}
|
||||
from base64 import b64decode
|
||||
self.session.headers.update(headers)
|
||||
response = self.session.get(b64decode(result['id']).decode())
|
||||
if response.text.find('callbackFunction') >= 0:
|
||||
result = response.text[18:-2]
|
||||
result = json.loads(result)
|
||||
self.session.cookies.update({
|
||||
'RAIL_EXPIRATION': result.get('exp'),
|
||||
'RAIL_DEVICEID': result.get('dfp'),
|
||||
})
|
||||
except:
|
||||
return False
|
||||
|
||||
def login_did_success(self):
|
||||
"""
|
||||
用户登录成功
|
||||
@@ -341,7 +312,7 @@ class UserJob:
|
||||
UserLog.MESSAGE_GET_USER_PASSENGERS_FAIL.format(
|
||||
result.get('messages', CommonLog.MESSAGE_RESPONSE_EMPTY_ERROR), self.retry_time)).flush()
|
||||
if Config().is_slave():
|
||||
self.load_user_from_remote() # 加载最新 cookie
|
||||
self.load_user_from_remote() # 加载最新 cookie
|
||||
stay_second(self.retry_time)
|
||||
return self.get_user_passengers()
|
||||
|
||||
@@ -354,8 +325,7 @@ class UserJob:
|
||||
name: '项羽',
|
||||
type: 1,
|
||||
id_card: 0000000000000000000,
|
||||
type_text: '成人',
|
||||
enc_str: 'aaaaaa'
|
||||
type_text: '成人'
|
||||
}]
|
||||
"""
|
||||
self.get_user_passengers()
|
||||
@@ -363,11 +333,6 @@ class UserJob:
|
||||
for member in members:
|
||||
is_member_code = is_number(member)
|
||||
if not is_member_code:
|
||||
if member[0] == "*":
|
||||
audlt = 1
|
||||
member = member[1:]
|
||||
else:
|
||||
audlt = 0
|
||||
child_check = array_dict_find_by_key_value(results, 'name', member)
|
||||
if not is_member_code and child_check:
|
||||
new_member = child_check.copy()
|
||||
@@ -378,8 +343,6 @@ class UserJob:
|
||||
passenger = array_dict_find_by_key_value(self.passengers, 'code', member)
|
||||
else:
|
||||
passenger = array_dict_find_by_key_value(self.passengers, 'passenger_name', member)
|
||||
if audlt:
|
||||
passenger['passenger_type'] = UserType.ADULT
|
||||
if not passenger:
|
||||
UserLog.add_quick_log(
|
||||
UserLog.MESSAGE_USER_PASSENGERS_IS_INVALID.format(self.user_name, member)).flush()
|
||||
@@ -390,8 +353,7 @@ class UserJob:
|
||||
'id_card_type': passenger.get('passenger_id_type_code'),
|
||||
'mobile': passenger.get('mobile_no'),
|
||||
'type': passenger.get('passenger_type'),
|
||||
'type_text': dict_find_key_by_value(UserType.dicts, int(passenger.get('passenger_type'))),
|
||||
'enc_str': passenger.get('allEncStr')
|
||||
'type_text': dict_find_key_by_value(UserType.dicts, int(passenger.get('passenger_type')))
|
||||
}
|
||||
results.append(new_member)
|
||||
|
||||
@@ -417,6 +379,6 @@ class UserJob:
|
||||
self.ticket_info_for_passenger_form = json.loads(form.groups()[0].replace("'", '"'))
|
||||
self.order_request_dto = json.loads(order.groups()[0].replace("'", '"'))
|
||||
except:
|
||||
return False # TODO Error
|
||||
pass # TODO Error
|
||||
|
||||
return True
|
||||
|
||||
@@ -25,9 +25,9 @@ requests-html==0.9.0
|
||||
six==1.12.0
|
||||
soupsieve==1.6.2
|
||||
tqdm==4.28.1
|
||||
urllib3==1.24.2
|
||||
urllib3==1.24.1
|
||||
w3lib==1.19.0
|
||||
websockets==7.0
|
||||
Werkzeug==0.15.3
|
||||
Werkzeug==0.14.1
|
||||
DingtalkChatbot==1.3.0
|
||||
lightpush==0.1.3
|
||||
lightpush==0.1.3
|
||||
Reference in New Issue
Block a user