python监控小猪巴士票预售

数据获取

本篇将记录如何使用python查询小猪巴士是否有新票放出,在ubuntu下使用fiddler对Android应用进行抓包
已经记录了如何真机抓包,线路查询接口如下图所示:

使用curl尝试发送请求:

1
curl -X POST -d "lineId=150716105019140882&lineBaseId=150716105018892878" http://bsapp.pig84.com/customline_app/app_book/getLineAndClassInfo.action

响应结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
{
"a1": "07:30",
"a2": "岗头市场南(B班)",
"a3": "岗头市场南(B班)",
"a4": "软件产业基地",
"a5": "22",
"a6": "60",
"a7": "6.90",
"a8": "150129085654531320",
"a9": "150716105019140882",
"a10": "6.90",
"a11": "30",
"a12": "粤BAP278",
"a13": "0",
"a14": "",
"a15": "",
"list": [
{
"a1": "150817110913979834",
"a2": "岗头市场南(B班)",
"a3": "114.067946",
"a4": "22.665774",
"a5": "1"
},

{
"a1": "150814204118757900",
"a2": "岗头市场南(B班)",
"a3": "114.067897",
"a4": "22.665882",
"a5": "1"
},

{
"a1": "150814204118963901",
"a2": "华为单身公寓北",
"a3": "114.072399",
"a4": "22.656271",
"a5": "1"
},

{
"a1": "150814204119170902",
"a2": "万科城北",
"a3": "114.072945",
"a4": "22.653974",
"a5": "1"
},

{
"a1": "150814204119335903",
"a2": "大冲①",
"a3": "113.958042",
"a4": "22.546029",
"a5": "2"
},

{
"a1": "150814204119503904",
"a2": "高科技中心",
"a3": "113.952042",
"a4": "22.543585",
"a5": "2"
},

{
"a1": "150814204119686905",
"a2": "深港研究基地",
"a3": "113.952079",
"a4": "22.539312",
"a5": "2"
},

{
"a1": "150814204119826906",
"a2": "软件产业基地",
"a3": "113.945932",
"a4": "22.530629",
"a5": "2"
}

],

"list1": [
{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2015-12-31",
"freeSeat": "-1",
"lineClassid": "151216145140168993",
"orderSeats": "47",
"price": "6.90",
"isbook": "1"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-01",
"freeSeat": "-1",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-02",
"freeSeat": "-1",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-03",
"freeSeat": "-1",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-04",
"freeSeat": "0",
"lineClassid": "151230103249617270",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-05",
"freeSeat": "0",
"lineClassid": "151230103249629272",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-06",
"freeSeat": "0",
"lineClassid": "151230103249636274",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-07",
"freeSeat": "0",
"lineClassid": "151230103249644276",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-08",
"freeSeat": "0",
"lineClassid": "151230103249654278",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-09",
"freeSeat": "-1",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-10",
"freeSeat": "-1",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-11",
"freeSeat": "0",
"lineClassid": "151230103249623271",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-12",
"freeSeat": "0",
"lineClassid": "151230103249633273",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-13",
"freeSeat": "0",
"lineClassid": "151230103249641275",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-14",
"freeSeat": "0",
"lineClassid": "151230103249649277",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-15",
"freeSeat": "0",
"lineClassid": "151230103249658279",
"orderSeats": "47",
"price": "6.90",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-16",
"freeSeat": "-1",
"isbook": "0"
},

{
"lineBaseId": "150716105018892878",
"orderStartTime": "07:30",
"orderDate": "2016-01-17",
"freeSeat": "-1",
"isbook": "0"
}

]
}

其中list为站点信息,list1为预售日期信息,预售期内的日期有返回price,所以将list1反转,
找到第一次出现price的条目并保存,再次请求时取出数据与前一次相比较,若相同则无新票预售。
代码如下:

check_bus.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
import json
import memcache
import datetime

# connect to memcached
mc = memcache.Client(['localhost:11211'], debug=0)


class BusBookChecker():

def __init__(self, lineId, lineBaseId):
self.url = 'http://bsapp.pig84.com/customline_app/app_book/getLineAndClassInfo.action'
self.payload = {"lineId": lineId, "lineBaseId": lineBaseId}
self.bookable_date = mc.get('bookable_date')
if not self.bookable_date:
bookable_date = datetime.date.today().strftime("%Y-%m-%d")
mc.set('bookable_date', bookable_date)
self.bookable_date = bookable_date

def check(self):
result = requests.post(self.url, self.payload)
order_dates = result.json()['list1']
order_dates.reverse()
for date in order_dates:
if 'price' in date:
if self.bookable_date != date['orderDate']:
mc.set('bookable_date', date['orderDate'])
send_message()
break
return self.bookable_date


def send_message():
print 'send sms to user'


if __name__ == "__main__":
checker = BusBookChecker(
'150716105019140882', '150716105018892878')
print u'当前预售期到' + checker.check()

修改check_bus.py的权限,增加可执行权限:

1
2
3
$ chmod u+x check_bus.py
$ ./check_bus.py
当前预售期到2016-01-15

定时执行

使用crontab每小时执行一次脚本,编辑任务列表

1
$ crontab -e

在文件末尾添加一行,每小时执行一次查询。

1
0 * * * * /path/check_bus.py

查看当前有哪些定时任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
0 * * * * /path/check_bus.py

删除所有定时任务,不提示是否确认:

1
2
3
$ crontab -r
$ crontab -l
no crontab for ming

删除任务时提示是否确认:

1
2
3
4
$ crontab -ir
crontab: really delete ming's crontab? (y/n) y
$ crontab -l
no crontab for ming

参考链接:
python 链接和操作 memcache
Ubuntu中memcached的安装、配置和启用关闭
每天一个linux命令(50):crontab命令