Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
py12306
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
python
py12306
Commits
27a5a13c
Commit
27a5a13c
authored
Jan 07, 2019
by
Jalin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完成自动下单
parent
0e287096
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
472 additions
and
37 deletions
+472
-37
config.py
py12306/config.py
+12
-1
api.py
py12306/helpers/api.py
+6
-0
func.py
py12306/helpers/func.py
+3
-1
order_log.py
py12306/log/order_log.py
+42
-0
query_log.py
py12306/log/query_log.py
+1
-1
user_log.py
py12306/log/user_log.py
+2
-0
order.py
py12306/order/order.py
+316
-21
job.py
py12306/query/job.py
+38
-8
query.py
py12306/query/query.py
+1
-1
job.py
py12306/user/job.py
+34
-0
user.py
py12306/user/user.py
+17
-4
No files found.
py12306/config.py
View file @
27a5a13c
...
...
@@ -24,16 +24,27 @@ AUTO_CODE_ACCOUNT = {
}
SEAT_TYPES
=
{
'特等座'
:
25
,
'商务座'
:
32
,
'一等座'
:
31
,
'二等座'
:
30
,
'特等座'
:
25
,
'软卧'
:
23
,
'硬卧'
:
28
,
'硬座'
:
29
,
'无座'
:
26
,
}
ORDER_SEAT_TYPES
=
{
'特等座'
:
'P'
,
'商务座'
:
9
,
'一等座'
:
'M'
,
'二等座'
:
'O'
,
'软卧'
:
4
,
'硬卧'
:
3
,
'硬座'
:
1
,
'无座'
:
1
,
}
PROJECT_DIR
=
path
.
dirname
(
path
.
dirname
(
path
.
abspath
(
__file__
)))
+
'/'
# Query
...
...
py12306/helpers/api.py
View file @
27a5a13c
...
...
@@ -43,6 +43,12 @@ API_USER_INFO = {
'url'
:
BASE_URL_OF_12306
+
'/otn/modifyUser/initQueryUserInfoApi'
}
API_USER_PASSENGERS
=
BASE_URL_OF_12306
+
'/otn/confirmPassenger/getPassengerDTOs'
API_SUBMIT_ORDER_REQUEST
=
BASE_URL_OF_12306
+
'/otn/leftTicket/submitOrderRequest'
API_CHECK_ORDER_INFO
=
BASE_URL_OF_12306
+
'/otn/confirmPassenger/checkOrderInfo'
API_INITDC_URL
=
BASE_URL_OF_12306
+
'/otn/confirmPassenger/initDc'
# 生成订单时需要先请求这个页面
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?{}'
# 排队查询
urls
=
{
"auth"
:
{
# 登录接口
...
...
py12306/helpers/func.py
View file @
27a5a13c
...
...
@@ -59,8 +59,10 @@ def get_interval_num(interval, decimal=2):
return
round
(
random
.
uniform
(
interval
.
get
(
'min'
),
interval
.
get
(
'max'
)),
decimal
)
def
stay_second
(
second
):
def
stay_second
(
second
,
call_back
=
None
):
sleep
(
second
)
if
call_back
:
return
call_back
()
def
is_main_thread
():
...
...
py12306/log/order_log.py
0 → 100644
View file @
27a5a13c
from
py12306.log.base
import
BaseLog
from
py12306.helpers.func
import
*
@
singleton
class
OrderLog
(
BaseLog
):
MESSAGE_REQUEST_INIT_DC_PAGE_FAIL
=
'请求初始化订单页面失败'
MESSAGE_SUBMIT_ORDER_REQUEST_FAIL
=
'提交订单失败,错误原因 {}'
MESSAGE_SUBMIT_ORDER_REQUEST_SUCCESS
=
'提交订单成功'
MESSAGE_CHECK_ORDER_INFO_FAIL
=
'检查订单失败,错误原因 {}'
MESSAGE_CHECK_ORDER_INFO_SUCCESS
=
'检查订单成功'
MESSAGE_GET_QUEUE_COUNT_SUCCESS
=
'排队成功,你当前排在第 {} 位, 余票还剩余 {} 张'
MESSAGE_GET_QUEUE_COUNT_FAIL
=
'排队失败,错误原因 {}'
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_SUCCESS
=
'# 提交订单成功!#'
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_ERROR
=
'提交订单出错,错误原因 {}'
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_FAIL
=
'提交订单失败,错误原因 {}'
MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING
=
'排队等待中,预计还需要 {} 秒'
MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL
=
'排队失败,错误原因 {}'
MESSAGE_QUERY_ORDER_WAIT_TIME_INFO
=
'第 {} 次排队,请耐心等待'
MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE
=
'车票购买成功!'
MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT
=
'请及时器登录12306,打开
\'
未完成订单
\'
,在30分钟内完成支付!'
@
classmethod
def
print_passenger_did_deleted
(
cls
,
passengers
):
self
=
cls
()
result
=
[
passenger
.
get
(
'name'
)
+
'('
+
passenger
.
get
(
'type_text'
)
+
')'
for
passenger
in
passengers
]
self
.
add_quick_log
(
'# 删减后的乘客列表 {} #'
.
format
(
', '
.
join
(
result
)))
self
.
flush
()
return
self
@
classmethod
def
print_ticket_did_ordered
(
cls
,
order_id
):
self
=
cls
()
self
.
add_quick_log
(
'# 车票购买成功,订单号{} #'
.
format
(
order_id
))
self
.
flush
()
return
self
py12306/log/query_log.py
View file @
27a5a13c
...
...
@@ -63,7 +63,7 @@ class QueryLog(BaseLog):
self
.
add_quick_log
(
'余票数小于乘车人数,当前余票数: {rest_num}, 实际人数 {actual_num}, 删减人车人数到: {take_num}'
.
format
(
rest_num
=
rest_num
,
actual_num
=
job
.
member_num
,
take
=
job
.
member_num_take
))
take
_num
=
job
.
member_num_take
))
self
.
flush
()
return
self
...
...
py12306/log/user_log.py
View file @
27a5a13c
...
...
@@ -17,6 +17,8 @@ class UserLog(BaseLog):
MESSAGE_GET_USER_PASSENGERS_FAIL
=
'获取用户乘客列表失败,错误原因: {} {} 秒后重试'
MESSAGE_USER_PASSENGERS_IS_INVALID
=
'乘客信息校验失败,在账号 {} 中未找到该乘客: {}'
MESSAGE_WAIT_USER_INIT_COMPLETE
=
'未找到可用账号或用户正在初始化,{} 秒重试'
def
__init__
(
self
):
super
()
.
__init__
()
self
.
init_data
()
...
...
py12306/order/order.py
View file @
27a5a13c
import
urllib
import
random
from
py12306.config
import
UserType
from
py12306.helpers.api
import
*
from
py12306.helpers.app
import
*
from
py12306.helpers.func
import
*
from
py12306.log.order_log
import
OrderLog
from
py12306.log.user_log
import
UserLog
from
py12306.user.job
import
UserJob
# from py12306.query.job import Job
# from py12306.user.job import UserJob
class
Order
:
"""
处理下单
"""
heartbeat
=
60
*
2
users
=
[]
session
=
None
query_ins
=
None
user_ins
=
None
def
__init__
(
self
):
pass
passenger_ticket_str
=
''
old_passenger_str
=
''
is_need_auth_code
=
False
max_queue_wait
=
120
current_queue_wait
=
0
retry_time
=
3
wait_queue_interval
=
3
@
classmethod
def
run
(
cls
):
self
=
cls
()
app_available_check
()
self
.
start
()
def
__init__
(
self
,
query
,
user
):
self
.
session
=
user
.
session
# assert isinstance(query, Job) # 循环引用
# assert isinstance(user, UserJob)
self
.
query_ins
=
query
self
.
user_ins
=
user
self
.
make_passenger_ticket_str
()
def
order
(
self
):
"""
开始下单
下单模式 暂时不清楚,使用正常步骤下单
:return:
"""
self
.
normal_order
()
pass
def
start
(
self
):
self
.
init_users
()
UserLog
.
print_init_users
(
users
=
self
.
users
)
# 多线程维护用户
create_thread_and_run
(
jobs
=
self
.
users
,
callback_name
=
'run'
,
wait
=
False
)
def
init_users
(
self
):
accounts
=
config
.
USER_ACCOUNTS
for
account
in
accounts
:
user
=
UserJob
(
info
=
account
,
user
=
self
)
self
.
users
.
append
(
user
)
def
normal_order
(
self
):
if
not
self
.
submit_order_request
():
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
:
# 发送通知
OrderLog
.
print_ticket_did_ordered
(
order_id
)
OrderLog
.
notification
(
OrderLog
.
MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE
,
OrderLog
.
MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT
)
def
submit_order_request
(
self
):
data
=
{
'secretStr'
:
urllib
.
parse
.
unquote
(
self
.
query_ins
.
get_info_of_secret_str
()),
# 解密
'train_date'
:
self
.
query_ins
.
left_date
,
# 出发时间
'back_train_date'
:
self
.
query_ins
.
left_date
,
# 返程时间
'tour_flag'
:
'dc'
,
# 旅途类型
'purpose_codes'
:
'ADULT'
,
# 成人 | 学生
'query_from_station_name'
:
self
.
query_ins
.
left_station
,
'query_to_station_name'
:
self
.
query_ins
.
arrive_station
,
}
response
=
self
.
session
.
post
(
API_SUBMIT_ORDER_REQUEST
,
data
)
result
=
response
.
json
()
if
result
.
get
(
'data'
)
==
'N'
:
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_SUBMIT_ORDER_REQUEST_SUCCESS
)
.
flush
()
return
True
else
:
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_SUBMIT_ORDER_REQUEST_FAIL
.
format
(
result
.
get
(
'messages'
,
'-'
)))
.
flush
()
return
False
def
check_order_info
(
self
):
"""
cancel_flag=2
bed_level_order_num=000000000000000000000000000000
passengerTicketStr=
tour_flag=dc
randCode=
whatsSelect=1
_json_att=
REPEAT_SUBMIT_TOKEN=458bf1b0a69431f34f9d2e9d3a11cfe9
:return:
"""
data
=
{
#
'cancel_flag'
:
2
,
'bed_level_order_num'
:
'000000000000000000000000000000'
,
'passengerTicketStr'
:
self
.
passenger_ticket_str
,
'oldPassengerStr'
:
self
.
old_passenger_str
,
'tour_flag'
:
'dc'
,
'randCode'
:
''
,
'whatsSelect'
:
'1'
,
'_json_att'
:
''
,
'REPEAT_SUBMIT_TOKEN'
:
self
.
user_ins
.
global_repeat_submit_token
}
response
=
self
.
session
.
post
(
API_CHECK_ORDER_INFO
,
data
)
result
=
response
.
json
()
if
'data'
in
result
and
result
[
'data'
]
.
get
(
'submitStatus'
):
# 成功
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_CHECK_ORDER_INFO_SUCCESS
)
.
flush
()
if
result
[
'data'
]
.
get
(
"ifShowPassCode"
)
!=
'N'
:
self
.
is_need_auth_code
=
True
return
True
else
:
result_data
=
result
.
get
(
'data'
,
{})
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_CHECK_ORDER_INFO_FAIL
.
format
(
result_data
.
get
(
'errMsg'
,
result
.
get
(
'messages'
,
'-'
))
))
.
flush
()
return
False
def
get_queue_count
(
self
):
"""
获取队列人数
train_date Mon Jan 01 2019 00:00:00 GMT+0800 (China Standard Time)
train_no 630000Z12208
stationTrainCode Z122
seatType 4
fromStationTelecode GZQ
toStationTelecode RXW
leftTicket CmDJZYrwUoJ1jFNonIgPzPFdMBvSSE8xfdUwvb2lq8CCWn
%2
Bzk1vM3roJaHk
%3
D
purpose_codes 00
train_location QY
_json_att
REPEAT_SUBMIT_TOKEN 0977caf26f25d1da43e3213eb35ff87c
:return:
"""
data
=
{
#
'train_date'
:
'{} 00:00:00 GMT+0800 (China Standard Time)'
.
format
(
datetime
.
datetime
.
today
()
.
strftime
(
"
%
a
%
h
%
d
%
Y"
)),
'train_no'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'queryLeftTicketRequestDTO'
][
'train_no'
],
'stationTrainCode'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'queryLeftTicketRequestDTO'
][
'station_train_code'
],
'seatType'
:
self
.
query_ins
.
current_order_seat
,
'fromStationTelecode'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'queryLeftTicketRequestDTO'
][
'from_station'
],
'toStationTelecode'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'queryLeftTicketRequestDTO'
][
'to_station'
],
'leftTicket'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'leftTicketStr'
],
'purpose_codes'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'purpose_codes'
],
'train_location'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'train_location'
],
'_json_att'
:
''
,
'REPEAT_SUBMIT_TOKEN'
:
self
.
user_ins
.
global_repeat_submit_token
,
}
response
=
self
.
session
.
post
(
API_GET_QUEUE_COUNT
,
data
)
result
=
response
.
json
()
if
'data'
in
result
and
(
'countT'
in
result
[
'data'
]
or
'ticket'
in
result
[
'data'
]):
# 成功
"""
"data": {
"count": "66",
"ticket": "0,73",
"op_2": "false",
"countT": "0",
"op_1": "true"
}
"""
ticket
=
result
[
'data'
][
'ticket'
]
.
split
(
','
)
# 暂不清楚具体作用
ticket_number
=
sum
(
map
(
int
,
ticket
))
current_position
=
int
(
data
.
get
(
'countT'
,
0
))
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_GET_QUEUE_COUNT_SUCCESS
.
format
(
current_position
,
ticket_number
))
.
flush
()
return
True
else
:
# 加入小黑屋
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_GET_QUEUE_COUNT_FAIL
.
format
(
result
.
get
(
'messages'
,
result
.
get
(
'validateMessages'
,
'-'
))))
.
flush
()
return
False
def
confirm_single_for_queue
(
self
):
"""
确认排队
passengerTicketStr
oldPassengerStr
randCode
purpose_codes 00
key_check_isChange FEE6C6634A3EAA93E1E6CFC39A99E555A92E438436F18AFF78837CDB
leftTicketStr CmDJZYrwUoJ1jFNonIgPzPFdMBvSSE8xfdUwvb2lq8CCWn
%2
Bzk1vM3roJaHk
%3
D
train_location QY
choose_seats
seatDetailType 000
whatsSelect 1
roomType 00
dwAll N
_json_att
REPEAT_SUBMIT_TOKEN 0977caf26f25d1da43e3213eb35ff87c
:return:
"""
data
=
{
#
'passengerTicketStr'
:
self
.
passenger_ticket_str
,
'oldPassengerStr'
:
self
.
old_passenger_str
,
'randCode'
:
''
,
'purpose_codes'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'purpose_codes'
],
'key_check_isChange'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'key_check_isChange'
],
'leftTicketStr'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'leftTicketStr'
],
'train_location'
:
self
.
user_ins
.
ticket_info_for_passenger_form
[
'train_location'
],
'choose_seats'
:
''
,
'seatDetailType'
:
'000'
,
'whatsSelect'
:
'1'
,
'roomType'
:
'00'
,
'dwAll'
:
'N'
,
'_json_att'
:
''
,
'REPEAT_SUBMIT_TOKEN'
:
self
.
user_ins
.
global_repeat_submit_token
,
}
if
self
.
is_need_auth_code
:
# 目前好像是都不需要了,有问题再处理
pass
response
=
self
.
session
.
post
(
API_CONFIRM_SINGLE_FOR_QUEUE
,
data
)
result
=
response
.
json
()
if
'data'
in
result
:
"""
"data": {
"submitStatus": true
}
"""
if
result
[
'data'
]
.
get
(
'submitStatus'
):
# 成功
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_SUCCESS
)
.
flush
()
return
True
else
:
# 加入小黑屋 TODO
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_ERROR
.
format
(
result
[
'data'
]
.
get
(
'errMsg'
,
'-'
)))
.
flush
()
else
:
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_FAIL
.
format
(
result
.
get
(
'messages'
,
'-'
)))
.
flush
()
return
False
def
query_order_wait_time
(
self
):
"""
排队查询
random 1546849953542
tourFlag dc
_json_att
REPEAT_SUBMIT_TOKEN 0977caf26f25d1da43e3213eb35ff87c
:return:
"""
self
.
current_queue_wait
=
self
.
max_queue_wait
while
self
.
current_queue_wait
:
self
.
current_queue_wait
-=
1
# TODO 取消超时订单,待优化
data
=
{
#
'random'
:
str
(
random
.
random
())[
2
:],
'tourFlag'
:
'dc'
,
'_json_att'
:
''
,
'REPEAT_SUBMIT_TOKEN'
:
self
.
user_ins
.
global_repeat_submit_token
,
}
response
=
self
.
session
.
get
(
API_QUERY_ORDER_WAIT_TIME
.
format
(
urllib
.
parse
.
urlencode
(
data
)))
result
=
response
.
json
()
if
result
.
get
(
'status'
)
and
'data'
in
result
:
"""
"data": {
"queryOrderWaitTimeStatus": true,
"count": 0,
"waitTime": -1,
"requestId": 6487958947291482523,
"waitCount": 0,
"tourFlag": "dc",
"orderId": "E222646122"
}
"""
result_data
=
result
[
'data'
]
order_id
=
result_data
.
get
(
'orderId'
)
if
order_id
:
# 成功
return
order_id
elif
result_data
.
get
(
'waitTime'
)
and
result_data
.
get
(
'waitTime'
)
>=
0
:
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING
.
format
(
result_data
.
get
(
'waitTime'
)))
.
flush
()
elif
result_data
.
get
(
'msg'
):
# 失败
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL
.
format
(
result_data
.
get
(
'msg'
,
'-'
)))
.
flush
()
return
False
elif
result
.
get
(
'messages'
)
or
result
.
get
(
'validateMessages'
):
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL
.
format
(
result
.
get
(
'messages'
,
result
.
get
(
'validateMessages'
))))
.
flush
()
else
:
pass
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_QUERY_ORDER_WAIT_TIME_INFO
.
format
(
self
.
current_queue_wait
))
.
flush
()
stay_second
(
self
.
wait_queue_interval
)
return
False
def
make_passenger_ticket_str
(
self
):
"""
生成提交车次的内容
格式:
1(seatType),0,1(车票类型:ticket_type_codes),张三(passenger_name),1(证件类型:passenger_id_type_code),xxxxxx(passenger_id_no),xxxx(mobile_no),N
passengerTicketStr:
张三(passenger_name),1(证件类型:passenger_id_type_code),xxxxxx(passenger_id_no),1_
oldPassengerStr
:return:
"""
passenger_tickets
=
[]
old_passengers
=
[]
available_passengers
=
self
.
query_ins
.
passengers
if
len
(
available_passengers
)
>
self
.
query_ins
.
member_num_take
:
# 删除人数
available_passengers
=
available_passengers
[
0
:
self
.
query_ins
.
member_num_take
]
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_'
.
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'
]
)
passenger_tickets
.
append
(
tmp_str
)
if
int
(
passenger
[
'type'
])
!=
UserType
.
CHILD
:
tmp_old_str
=
'{passenger_name},{passenger_id_card_type},{passenger_id_card},{passenger_type}_'
.
format
(
passenger_name
=
passenger
[
'name'
],
passenger_id_card_type
=
passenger
[
'id_card_type'
],
passenger_id_card
=
passenger
[
'id_card'
],
passenger_type
=
passenger
[
'type'
],
)
old_passengers
.
append
(
tmp_old_str
)
self
.
passenger_ticket_str
=
''
.
join
(
passenger_tickets
)
.
rstrip
(
'_'
)
self
.
old_passenger_str
=
''
.
join
(
old_passengers
)
.
rstrip
(
'_'
)
+
'__ _ _'
# 不加后面请求会出错
py12306/query/job.py
View file @
27a5a13c
...
...
@@ -3,6 +3,7 @@ from py12306.helpers.station import Station
from
py12306.log.query_log
import
QueryLog
from
py12306.helpers.func
import
*
from
py12306.log.user_log
import
UserLog
from
py12306.order.order
import
Order
from
py12306.user.user
import
User
...
...
@@ -12,6 +13,7 @@ class Job:
"""
left_dates
=
[]
left_date
=
None
left_station
=
''
arrive_station
=
''
left_station_code
=
''
...
...
@@ -19,6 +21,8 @@ class Job:
account_key
=
0
allow_seats
=
[]
current_seat
=
None
current_order_seat
=
None
allow_train_numbers
=
[]
members
=
[]
member_num
=
0
...
...
@@ -32,10 +36,12 @@ class Job:
ticket_info
=
{}
INDEX_TICKET_NUM
=
11
INDEX_TRAIN_NUMBER
=
3
INDEX_TRAIN_NO
=
2
INDEX_LEFT_DATE
=
13
INDEX_LEFT_STATION
=
6
# 4 5 始发 终点
INDEX_ARRIVE_STATION
=
7
INDEX_ORDER_TEXT
=
1
# 下单文字
INDEX_SECRET_STR
=
0
def
__init__
(
self
,
info
,
query
):
self
.
left_dates
=
info
.
get
(
'left_dates'
)
...
...
@@ -67,22 +73,20 @@ class Job:
:param job:
:return:
"""
if
not
self
.
passengers
:
User
.
check_members
(
self
.
members
,
self
.
account_key
,
call_back
=
self
.
set_passengers
)
QueryLog
.
print_job_start
()
for
date
in
self
.
left_dates
:
self
.
left_date
=
date
response
=
self
.
query_by_date
(
date
)
self
.
handle_response
(
response
)
self
.
safe_stay
()
if
is_main_thread
():
QueryLog
.
flush
(
sep
=
'
\t
\t
'
)
QueryLog
.
flush
(
sep
=
'
\t
'
)
else
:
QueryLog
.
add_log
(
'
\n
'
)
if
is_main_thread
():
QueryLog
.
add_quick_log
(
''
)
.
flush
()
else
:
QueryLog
.
flush
(
sep
=
'
\t
\t
'
)
QueryLog
.
flush
(
sep
=
'
\t
'
)
def
query_by_date
(
self
,
date
):
"""
...
...
@@ -116,12 +120,14 @@ class Job:
self
.
get_info_of_ticket_num
()))
if
not
self
.
is_has_ticket
(
ticket_info
):
continue
allow_seats
=
self
.
allow_seats
if
self
.
allow_seats
else
list
(
config
.
SEAT_TYPES
.
values
())
# 未设置 则所有可用
allow_seats
=
self
.
allow_seats
if
self
.
allow_seats
else
list
(
config
.
SEAT_TYPES
.
values
())
# 未设置 则所有可用 TODO 合法检测
self
.
handle_seats
(
allow_seats
,
ticket_info
)
def
handle_seats
(
self
,
allow_seats
,
ticket_info
):
for
seat
in
allow_seats
:
# 检查座位是否有票
ticket_of_seat
=
ticket_info
[
get_seat_number_by_name
(
seat
)]
self
.
set_seat
(
seat
)
ticket_of_seat
=
ticket_info
[
self
.
current_seat
]
if
not
self
.
is_has_ticket_by_seat
(
ticket_of_seat
):
# 座位是否有效
continue
QueryLog
.
print_ticket_seat_available
(
left_date
=
self
.
get_info_of_left_date
(),
...
...
@@ -139,7 +145,9 @@ class Job:
QueryLog
.
print_ticket_available
(
left_date
=
self
.
get_info_of_left_date
(),
train_number
=
self
.
get_info_of_train_number
(),
rest_num
=
ticket_of_seat
)
print
(
'检查完成 开始提交订单'
)
self
.
check_passengers
()
order
=
Order
(
user
=
self
.
get_user
(),
query
=
self
)
order
.
order
()
def
get_results
(
self
,
response
):
"""
...
...
@@ -179,6 +187,22 @@ class Job:
UserLog
.
print_user_passenger_init_success
(
passengers
)
self
.
passengers
=
passengers
def
set_seat
(
self
,
seat
):
self
.
current_seat
=
get_seat_number_by_name
(
seat
)
self
.
current_order_seat
=
config
.
ORDER_SEAT_TYPES
[
seat
]
def
get_user
(
self
):
user
=
User
.
get_user
(
self
.
account_key
)
if
not
user
.
check_is_ready
():
# TODO user is not ready
pass
return
user
def
check_passengers
(
self
):
if
not
self
.
passengers
:
User
.
check_members
(
self
.
members
,
self
.
account_key
,
call_back
=
self
.
set_passengers
)
return
True
# 提供一些便利方法
def
get_info_of_left_date
(
self
):
return
self
.
ticket_info
[
self
.
INDEX_LEFT_DATE
]
...
...
@@ -189,6 +213,9 @@ class Job:
def
get_info_of_train_number
(
self
):
return
self
.
ticket_info
[
self
.
INDEX_TRAIN_NUMBER
]
def
get_info_of_train_no
(
self
):
return
self
.
ticket_info
[
self
.
INDEX_TRAIN_NO
]
def
get_info_of_left_station
(
self
):
return
Station
.
get_station_name_by_key
(
self
.
ticket_info
[
self
.
INDEX_LEFT_STATION
])
...
...
@@ -197,3 +224,6 @@ class Job:
def
get_info_of_order_text
(
self
):
return
self
.
ticket_info
[
self
.
INDEX_ORDER_TEXT
]
def
get_info_of_secret_str
(
self
):
return
self
.
ticket_info
[
self
.
INDEX_SECRET_STR
]
py12306/query/query.py
View file @
27a5a13c
...
...
@@ -31,7 +31,7 @@ class Query:
pass
def
start
(
self
):
return
# DEBUG
#
return # DEBUG
self
.
init_jobs
()
QueryLog
.
print_init_jobs
(
jobs
=
self
.
jobs
)
while
True
:
...
...
py12306/user/job.py
View file @
27a5a13c
import
json
import
pickle
import
re
from
os
import
path
from
py12306.config
import
*
...
...
@@ -7,6 +9,7 @@ from py12306.helpers.app import *
from
py12306.helpers.auth_code
import
AuthCode
from
py12306.helpers.func
import
*
from
py12306.helpers.request
import
Request
from
py12306.log.order_log
import
OrderLog
from
py12306.log.user_log
import
UserLog
...
...
@@ -23,6 +26,11 @@ class UserJob:
passengers
=
[]
retry_time
=
5
# Init page
global_repeat_submit_token
=
None
ticket_info_for_passenger_form
=
None
order_request_dto
=
None
def
__init__
(
self
,
info
,
user
):
self
.
session
=
Request
()
self
.
heartbeat
=
user
.
heartbeat
...
...
@@ -229,9 +237,35 @@ class UserJob:
new_member
=
{
'name'
:
passenger
.
get
(
'passenger_name'
),
'id_card'
:
passenger
.
get
(
'passenger_id_no'
),
'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'
)))
}
results
.
append
(
new_member
)
return
results
def
request_init_dc_page
(
self
):
"""
请求下单页面 拿到 token
:return:
"""
data
=
{
'_json_att'
:
''
}
response
=
self
.
session
.
post
(
API_INITDC_URL
,
data
)
html
=
response
.
text
token
=
re
.
search
(
r'var globalRepeatSubmitToken = \'(.+?)\''
,
html
)
form
=
re
.
search
(
r'var ticketInfoForPassengerForm *= *(\{.+\})'
,
html
)
order
=
re
.
search
(
r'var orderRequestDTO *= *(\{.+\})'
,
html
)
# 系统忙,请稍后重试
if
html
.
find
(
'系统忙,请稍后重试'
)
!=
-
1
:
OrderLog
.
add_quick_log
(
OrderLog
.
MESSAGE_REQUEST_INIT_DC_PAGE_FAIL
)
.
flush
()
# 重试无用,直接跳过
return
False
try
:
self
.
global_repeat_submit_token
=
token
.
groups
()[
0
]
self
.
ticket_info_for_passenger_form
=
json
.
loads
(
form
.
groups
()[
0
]
.
replace
(
"'"
,
'"'
))
self
.
order_request_dto
=
json
.
loads
(
order
.
groups
()[
0
]
.
replace
(
"'"
,
'"'
))
except
:
pass
# TODO Error
return
True
py12306/user/user.py
View file @
27a5a13c
...
...
@@ -9,6 +9,8 @@ class User:
heartbeat
=
60
*
2
users
=
[]
retry_time
=
3
def
__init__
(
self
):
self
.
interval
=
config
.
USER_HEARTBEAT_INTERVAL
...
...
@@ -32,7 +34,15 @@ class User:
self
.
users
.
append
(
user
)
@
classmethod
def
check_members
(
cls
,
members
,
user_key
,
call_back
):
def
get_user
(
cls
,
key
):
self
=
cls
()
for
user
in
self
.
users
:
if
user
.
key
==
key
:
return
user
return
None
@
classmethod
def
check_members
(
cls
,
members
,
key
,
call_back
):
"""
检测乘客信息
:param passengers:
...
...
@@ -42,7 +52,10 @@ class User:
for
user
in
self
.
users
:
assert
isinstance
(
user
,
UserJob
)
if
user
.
key
==
user_
key
and
user
.
check_is_ready
():
if
user
.
key
==
key
and
user
.
check_is_ready
():
passengers
=
user
.
get_passengers_by_members
(
members
)
call_back
(
passengers
)
pass
return
call_back
(
passengers
)
UserLog
.
add_quick_log
(
UserLog
.
MESSAGE_WAIT_USER_INIT_COMPLETE
.
format
(
self
.
retry_time
))
.
flush
()
stay_second
(
self
.
retry_time
)
return
self
.
check_members
(
members
,
key
,
call_back
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment