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
85fb384b
Commit
85fb384b
authored
Jan 06, 2019
by
Jalin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完善查询功能
parent
e6e19056
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
269 additions
and
57 deletions
+269
-57
config.py
py12306/config.py
+3
-0
func.py
py12306/helpers/func.py
+24
-0
base.py
py12306/log/base.py
+15
-3
query_log.py
py12306/log/query_log.py
+75
-5
job.py
py12306/query/job.py
+121
-2
query.py
py12306/query/query.py
+9
-47
user.py
py12306/user/user.py
+22
-0
No files found.
py12306/config.py
View file @
85fb384b
...
@@ -7,6 +7,9 @@ USER_ACCOUNTS = []
...
@@ -7,6 +7,9 @@ USER_ACCOUNTS = []
# 查询任务
# 查询任务
QUERY_JOBS
=
[]
QUERY_JOBS
=
[]
# 查询间隔
QUERY_INTERVAL
=
1
SEAT_TYPES
=
{
SEAT_TYPES
=
{
'商务座'
:
32
,
'商务座'
:
32
,
...
...
py12306/helpers/func.py
View file @
85fb384b
import
random
from
time
import
sleep
from
py12306
import
config
from
py12306
import
config
import
functools
import
functools
...
@@ -36,4 +39,25 @@ def get_seat_name_by_number(number):
...
@@ -36,4 +39,25 @@ def get_seat_name_by_number(number):
return
[
k
for
k
,
v
in
config
.
SEAT_TYPES
.
items
()
if
v
==
number
]
.
pop
()
return
[
k
for
k
,
v
in
config
.
SEAT_TYPES
.
items
()
if
v
==
number
]
.
pop
()
# 初始化间隔
def
init_interval_by_number
(
number
):
if
isinstance
(
number
,
dict
):
min
=
float
(
number
.
get
(
'min'
))
max
=
float
(
number
.
get
(
'max'
))
else
:
min
=
number
/
2
max
=
number
return
{
'min'
:
min
,
'max'
:
max
}
def
get_interval_num
(
interval
,
decimal
=
2
):
return
round
(
random
.
uniform
(
interval
.
get
(
'min'
),
interval
.
get
(
'max'
)),
decimal
)
def
stay_second
(
second
):
sleep
(
second
)
# def test:
# def test:
py12306/log/base.py
View file @
85fb384b
...
@@ -3,6 +3,7 @@ from py12306.helpers.func import *
...
@@ -3,6 +3,7 @@ from py12306.helpers.func import *
class
BaseLog
:
class
BaseLog
:
logs
=
[]
logs
=
[]
quick_log
=
[]
@
classmethod
@
classmethod
def
add_log
(
cls
,
content
):
def
add_log
(
cls
,
content
):
...
@@ -11,8 +12,19 @@ class BaseLog:
...
@@ -11,8 +12,19 @@ class BaseLog:
return
self
return
self
@
classmethod
@
classmethod
def
flush
(
cls
):
def
flush
(
cls
,
sep
=
'
\n
'
,
end
=
'
\n
'
,
file
=
None
):
self
=
cls
()
self
=
cls
()
for
i
in
self
.
logs
:
logs
=
self
.
quick_log
if
self
.
quick_log
else
self
.
logs
print
(
i
)
# for i in logs:
print
(
*
logs
,
sep
=
sep
,
end
=
end
,
file
=
file
)
if
self
.
quick_log
:
self
.
quick_log
=
[]
else
:
self
.
logs
=
[]
# print(self.logs)
# print(self.logs)
@
classmethod
def
add_quick_log
(
cls
,
content
):
self
=
cls
()
self
.
quick_log
.
append
(
content
)
return
self
py12306/log/query_log.py
View file @
85fb384b
import
datetime
import
json
import
json
from
os
import
path
from
os
import
path
from
py12306.log.base
import
BaseLog
from
py12306.log.base
import
BaseLog
...
@@ -7,12 +8,17 @@ from py12306.helpers.func import *
...
@@ -7,12 +8,17 @@ from py12306.helpers.func import *
@
singleton
@
singleton
class
QueryLog
(
BaseLog
):
class
QueryLog
(
BaseLog
):
data
=
{
data
=
{
'query_count'
:
0
,
'query_count'
:
1
,
'last_time'
:
''
,
'last_time'
:
''
,
}
}
data_path
=
config
.
QUERY_DATA_DIR
+
'/status.json'
LOG_INIT_JOBS
=
''
LOG_INIT_JOBS
=
''
MESSAGE_GIVE_UP_CHANCE_CAUSE_TICKET_NUM_LESS_THAN_SPECIFIED
=
'余票数小于乘车人数,放弃此次提交机会'
MESSAGE_QUERY_LOG_OF_EVERY_TRAIN
=
'{}-{}'
MESSAGE_QUERY_START_BY_DATE
=
'出发日期 {}: {} - {}'
def
__init__
(
self
):
def
__init__
(
self
):
super
()
.
__init__
()
super
()
.
__init__
()
self
.
init_data
()
self
.
init_data
()
...
@@ -20,12 +26,12 @@ class QueryLog(BaseLog):
...
@@ -20,12 +26,12 @@ class QueryLog(BaseLog):
def
init_data
(
self
):
def
init_data
(
self
):
# 获取上次记录
# 获取上次记录
print
(
'Query Log 初始化'
)
print
(
'Query Log 初始化'
)
file_path
=
config
.
QUERY_DATA_DIR
+
'/status.json'
if
path
.
exists
(
self
.
data_path
):
if
path
.
exists
(
file_path
):
result
=
open
(
self
.
data_path
,
encoding
=
'utf-8'
)
.
read
()
result
=
open
(
file_path
,
encoding
=
'utf-8'
)
.
read
()
if
result
:
if
result
:
result
=
json
.
loads
(
result
)
result
=
json
.
loads
(
result
)
self
.
data
=
{
**
self
.
data
,
**
result
}
self
.
data
=
{
**
self
.
data
,
**
result
}
self
.
print_data_restored
()
@
classmethod
@
classmethod
def
print_init_jobs
(
cls
,
jobs
):
def
print_init_jobs
(
cls
,
jobs
):
...
@@ -34,7 +40,7 @@ class QueryLog(BaseLog):
...
@@ -34,7 +40,7 @@ class QueryLog(BaseLog):
输出初始化信息
输出初始化信息
:return:
:return:
"""
"""
self
.
add_log
(
'# 发现
任务 {} 条
#'
.
format
(
len
(
jobs
)))
self
.
add_log
(
'# 发现
{} 个任务
#'
.
format
(
len
(
jobs
)))
index
=
1
index
=
1
for
job
in
jobs
:
for
job
in
jobs
:
self
.
add_log
(
'================== 任务 {} =================='
.
format
(
index
))
self
.
add_log
(
'================== 任务 {} =================='
.
format
(
index
))
...
@@ -45,5 +51,69 @@ class QueryLog(BaseLog):
...
@@ -45,5 +51,69 @@ class QueryLog(BaseLog):
self
.
add_log
(
'筛选车次:{}'
.
format
(
','
.
join
(
job
.
allow_train_numbers
)))
self
.
add_log
(
'筛选车次:{}'
.
format
(
','
.
join
(
job
.
allow_train_numbers
)))
# 乘车日期:['2019-01-24', '2019-01-25', '2019-01-26', '2019-01-27']
# 乘车日期:['2019-01-24', '2019-01-25', '2019-01-26', '2019-01-27']
index
+=
1
index
+=
1
self
.
add_log
(
''
)
self
.
flush
()
return
self
@
classmethod
def
print_ticket_num_less_than_specified
(
cls
,
rest_num
,
job
):
self
=
cls
()
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
))
self
.
flush
()
return
self
@
classmethod
def
print_ticket_seat_available
(
cls
,
left_date
,
train_number
,
seat_type
,
rest_num
):
self
=
cls
()
self
.
add_quick_log
(
'查询到座位可用 出发时间 {left_date} 车次 {train_number} 座位类型 {seat_type} 余票数量 {rest_num}'
.
format
(
left_date
=
left_date
,
train_number
=
train_number
,
seat_type
=
seat_type
,
rest_num
=
rest_num
))
self
.
flush
()
return
self
@
classmethod
def
print_query_error
(
cls
,
reason
,
code
=
None
):
self
=
cls
()
self
.
add_quick_log
(
'查询余票请求失败'
)
if
code
:
self
.
add_quick_log
(
'状态码{} '
.
format
(
code
))
if
reason
:
self
.
add_quick_log
(
'错误原因{} '
.
format
(
reason
))
self
.
flush
(
sep
=
'
\t
'
)
return
self
@
classmethod
def
print_job_start
(
cls
):
self
=
cls
()
self
.
add_quick_log
(
'=== 正在进行第 {query_count} 次查询 === {time}'
.
format
(
query_count
=
self
.
data
.
get
(
'query_count'
),
time
=
datetime
.
datetime
.
now
()))
self
.
refresh_data
()
self
.
flush
()
return
self
@
classmethod
def
add_stay_log
(
cls
,
second
):
self
=
cls
()
self
.
add_log
(
'安全停留 {}'
.
format
(
second
))
return
self
def
print_data_restored
(
self
):
self
.
add_quick_log
(
'============================================================'
)
self
.
add_quick_log
(
'|=== 查询记录恢复成功 上次查询 {last_date} ===|'
.
format
(
last_date
=
self
.
data
.
get
(
'last_time'
)))
self
.
add_quick_log
(
'============================================================'
)
self
.
add_log
(
''
)
self
.
flush
()
return
self
return
self
def
refresh_data
(
self
):
self
.
data
[
'query_count'
]
+=
1
self
.
data
[
'last_time'
]
=
str
(
datetime
.
datetime
.
now
())
self
.
save_data
()
def
save_data
(
self
):
with
open
(
self
.
data_path
,
'w'
)
as
file
:
file
.
write
(
json
.
dumps
(
self
.
data
))
py12306/query/job.py
View file @
85fb384b
from
py12306.helpers.api
import
LEFT_TICKETS
from
py12306.helpers.station
import
Station
from
py12306.helpers.station
import
Station
from
py12306.log.query_log
import
QueryLog
from
py12306.helpers.func
import
*
class
Job
:
class
Job
:
...
@@ -15,10 +18,19 @@ class Job:
...
@@ -15,10 +18,19 @@ class Job:
allow_seats
=
[]
allow_seats
=
[]
allow_train_numbers
=
[]
allow_train_numbers
=
[]
members
=
[]
members
=
[]
member_num
=
[]
member_num
=
0
member_num_take
=
0
# 最终提交的人数
allow_less_member
=
False
interval
=
{}
def
__init__
(
self
,
info
):
query
=
None
INDEX_TICKET_NUM
=
11
INDEX_TRAIN_NUMBER
=
3
INDEX_LEFT_DATE
=
13
def
__init__
(
self
,
info
,
query
):
self
.
left_dates
=
info
.
get
(
'left_dates'
)
self
.
left_dates
=
info
.
get
(
'left_dates'
)
self
.
left_station
=
info
.
get
(
'stations'
)
.
get
(
'left'
)
self
.
left_station
=
info
.
get
(
'stations'
)
.
get
(
'left'
)
self
.
arrive_station
=
info
.
get
(
'stations'
)
.
get
(
'arrive'
)
self
.
arrive_station
=
info
.
get
(
'stations'
)
.
get
(
'arrive'
)
...
@@ -29,3 +41,110 @@ class Job:
...
@@ -29,3 +41,110 @@ class Job:
self
.
allow_train_numbers
=
info
.
get
(
'train_numbers'
)
self
.
allow_train_numbers
=
info
.
get
(
'train_numbers'
)
self
.
members
=
info
.
get
(
'members'
)
self
.
members
=
info
.
get
(
'members'
)
self
.
member_num
=
len
(
self
.
members
)
self
.
member_num
=
len
(
self
.
members
)
self
.
member_num_take
=
self
.
member_num
self
.
allow_less_member
=
bool
(
info
.
get
(
'allow_less_member'
))
self
.
interval
=
query
.
interval
self
.
query
=
query
def
run
(
self
):
self
.
start
()
def
start
(
self
):
"""
处理单个任务
根据日期循环查询
展示处理时间
:param job:
:return:
"""
QueryLog
.
print_job_start
()
for
date
in
self
.
left_dates
:
response
=
self
.
query_by_date
(
date
)
self
.
handle_response
(
response
)
self
.
safe_stay
()
QueryLog
.
flush
(
sep
=
'
\t\t
'
)
QueryLog
.
add_quick_log
(
''
)
.
flush
()
def
query_by_date
(
self
,
date
):
"""
通过日期进行查询
:return:
"""
QueryLog
.
add_log
(
QueryLog
.
MESSAGE_QUERY_START_BY_DATE
.
format
(
date
,
self
.
left_station
,
self
.
arrive_station
))
url
=
LEFT_TICKETS
.
get
(
'url'
)
.
format
(
left_date
=
date
,
left_station
=
self
.
left_station_code
,
arrive_station
=
self
.
arrive_station_code
,
type
=
'leftTicket/queryZ'
)
return
self
.
query
.
session
.
get
(
url
)
def
handle_response
(
self
,
response
):
"""
错误判断
余票判断
小黑屋判断
座位判断
乘车人判断
:param result:
:return:
"""
results
=
self
.
get_results
(
response
)
if
not
results
:
return
False
for
result
in
results
:
ticket_info
=
result
.
split
(
'|'
)
if
not
self
.
is_trains_number_valid
(
ticket_info
):
# 车次是否有效
continue
QueryLog
.
add_log
(
QueryLog
.
MESSAGE_QUERY_LOG_OF_EVERY_TRAIN
.
format
(
ticket_info
[
self
.
INDEX_TRAIN_NUMBER
],
ticket_info
[
self
.
INDEX_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
())
# 未设置 则所有可用
for
seat
in
allow_seats
:
# 检查座位是否有票
ticket_of_seat
=
ticket_info
[
get_seat_number_by_name
(
seat
)]
if
not
self
.
is_has_ticket_by_seat
(
ticket_of_seat
):
# 座位是否有效
continue
QueryLog
.
print_ticket_seat_available
(
left_date
=
ticket_info
[
self
.
INDEX_LEFT_DATE
],
train_number
=
ticket_info
[
self
.
INDEX_TRAIN_NUMBER
],
seat_type
=
seat
,
rest_num
=
ticket_of_seat
)
if
not
self
.
is_member_number_valid
(
ticket_of_seat
):
# 乘车人数是否有效
if
self
.
allow_less_member
:
self
.
member_num_take
=
int
(
ticket_of_seat
)
QueryLog
.
print_ticket_num_less_than_specified
(
ticket_of_seat
,
self
)
else
:
QueryLog
.
add_quick_log
(
QueryLog
.
MESSAGE_GIVE_UP_CHANCE_CAUSE_TICKET_NUM_LESS_THAN_SPECIFIED
)
.
flush
()
continue
# 检查完成 开始提交订单
print
(
'检查完成 开始提交订单'
)
def
get_results
(
self
,
response
):
"""
解析查询返回结果
:param response:
:return:
"""
if
response
.
status_code
!=
200
:
QueryLog
.
print_query_error
(
response
.
reason
,
response
.
status_code
)
try
:
result_data
=
response
.
json
()
.
get
(
'data'
,
{})
result
=
result_data
.
get
(
'result'
,
[])
except
:
pass
# TODO
return
result
if
result
else
False
def
is_has_ticket
(
self
,
ticket_info
):
return
ticket_info
[
11
]
==
'Y'
and
ticket_info
[
1
]
==
'预订'
def
is_has_ticket_by_seat
(
self
,
seat
):
return
seat
!=
''
and
seat
!=
'无'
and
seat
!=
'*'
def
is_trains_number_valid
(
self
,
ticket_info
):
if
self
.
allow_train_numbers
:
return
ticket_info
[
3
]
in
self
.
allow_train_numbers
return
True
def
is_member_number_valid
(
self
,
seat
):
return
seat
==
'有'
or
self
.
member_num
<=
int
(
seat
)
def
safe_stay
(
self
):
interval
=
get_interval_num
(
self
.
interval
)
QueryLog
.
add_stay_log
(
interval
)
stay_second
(
interval
)
py12306/query/query.py
View file @
85fb384b
from
requests_html
import
HTMLSession
from
requests_html
import
HTMLSession
import
py12306.config
as
config
from
py12306.helpers.api
import
LEFT_TICKETS
from
py12306.helpers.func
import
*
from
py12306.helpers.func
import
*
from
py12306.helpers.station
import
Station
from
py12306.log.query_log
import
QueryLog
from
py12306.log.query_log
import
QueryLog
from
py12306.query.job
import
Job
from
py12306.query.job
import
Job
...
@@ -16,7 +13,11 @@ class Query:
...
@@ -16,7 +13,11 @@ class Query:
jobs
=
[]
jobs
=
[]
session
=
{}
session
=
{}
# 查询间隔
interval
=
{}
def
__init__
(
self
):
def
__init__
(
self
):
self
.
interval
=
init_interval_by_number
(
config
.
QUERY_INTERVAL
)
self
.
session
=
HTMLSession
()
self
.
session
=
HTMLSession
()
@
classmethod
@
classmethod
...
@@ -27,52 +28,13 @@ class Query:
...
@@ -27,52 +28,13 @@ class Query:
def
start
(
self
):
def
start
(
self
):
self
.
init_jobs
()
self
.
init_jobs
()
QueryLog
.
print_init_jobs
(
jobs
=
self
.
jobs
)
.
flush
()
QueryLog
.
print_init_jobs
(
jobs
=
self
.
jobs
)
while
True
:
for
job
in
self
.
jobs
:
for
job
in
self
.
jobs
:
self
.
handle_single_job
(
job
)
job
.
run
(
)
def
init_jobs
(
self
):
def
init_jobs
(
self
):
jobs
=
config
.
QUERY_JOBS
jobs
=
config
.
QUERY_JOBS
for
job
in
jobs
:
for
job
in
jobs
:
job
=
Job
(
info
=
job
)
job
=
Job
(
info
=
job
,
query
=
self
)
self
.
jobs
.
append
(
job
)
self
.
jobs
.
append
(
job
)
def
handle_single_job
(
self
,
job
):
"""
处理单个任务
根据日期循环查询
展示处理时间
:param job:
:return:
"""
for
date
in
job
.
left_dates
:
result
=
self
.
query_by_job_and_date
(
job
,
date
)
self
.
handle_single_result
(
result
)
station
=
Station
.
get_station_by_name
(
'广州'
)
print
(
station
)
pass
def
query_by_job_and_date
(
self
,
job
,
date
):
"""
通过日期进行查询
:return:
"""
QueryLog
.
add_log
(
'正在查询 {}, {} - {}'
.
format
(
date
,
job
.
left_station
,
job
.
arrive_station
))
url
=
LEFT_TICKETS
.
get
(
'url'
)
.
format
(
left_date
=
date
,
left_station
=
job
.
left_station_code
,
arrive_station
=
job
.
arrive_station_code
,
type
=
'leftTicket/queryZ'
)
return
self
.
session
.
get
(
url
)
def
handle_single_result
(
self
,
result
):
"""
错误判断
余票判断
小黑屋判断
座位判断
乘车人判断
:param result:
:return:
"""
pass
py12306/user/user.py
0 → 100644
View file @
85fb384b
from
py12306.helpers.func
import
*
@
singleton
class
User
:
def
__init__
(
self
):
"""
初始化用户
恢复
登录
"""
pass
@
classmethod
def
run
(
cls
):
self
=
cls
()
self
.
start
()
pass
def
start
(
self
):
pass
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