背景
北京的公交基本都能查询实时公交,这个功能对于公交出行能带来很大的便利,能节省很多等车的时间。最直接的方法就是去公交官网查询,但是每次操作起来都有些吃力,统计了一下公交列表发现有1300+趟车,在其中找特定的一辆得老半天,让人脑阔疼。再一个就是在北京公交集团的微信公众号上面查询,这个还算可以,但是有一次遇到了不准的问题,就不愿意用了。正好最近也比较迷,不知道该干什么好(怀疑人生ing)。趁着周末有空就自己写个Python脚本来实现一下。
环境
python 3.0+
依赖外部库:requests
相关文件参见:https://github.com/Himryang/bjbus-query
效果展示
效果展示思路
用到Chrome的开发者工具(Fiddler也差不多),在官网上单步正常操作,在时间轴上能看到自己每次操作对应的内容。主要就是捕捉ajax的请求,分析一下每步request的header,看cookies内容,发现从主页的get请求开始,到最后一步都是一样的(除了SESSIONID里面的时间戳不一样),所以就比较简单了,直接用requests库创建一个session来自动处理过程中的cookies就行了,时间戳相关的部分会自动同步的,不用担心。
这里提取内容都直接写正则实现的,也可以用美味汤(BeautifulSoup)来解析html(为了让最后打包的exe文件,re和bs4我想最好就只用一个库咯)。
代码和注释
import requests
import re
from os import system
from time import sleep
from ast import literal_eval
def getLineDir(bus,s):
# 构建请求链接
selbline = requests.utils.quote(bus)
url = 'http://www.bjbus.com/home/ajax_rtbus_data.php?act=getLineDir&selBLine={}'.format(selbline)
r = s.get(url,verify=False)
r.encoding = r.apparent_encoding #处理编码
rt = r.text
LineDir_info = dict()
# 匹配信息
uuid_list = re.findall('(?<=data-uuid=")\d+',rt)
busdir_list = re.findall('\((.*?)\)',rt)
for i in [1,2]:
flist = []
flist.append(uuid_list[i-1])
flist.append(busdir_list[i-1])
LineDir_info["{}".format(i)]=flist
return LineDir_info
def getbus(uuid,s):
url = 'http://www.bjbus.com/home/ajax_rtbus_data.php?act=busTime&selBLine=1&selBDir={}&selBStop=1'.format(uuid)
r = s.get(url,verify=False)
html = literal_eval(r.text)['html']
busc = re.findall('(?<=id=")\d+(?=m"><i class="busc")',html)
busc = [int(i)-1 for i in busc]
buss = re.findall('(?<=id=")\d+(?="><i class="buss")',html)
buss = [int(i)-1 for i in buss]
bus_list = re.findall('(?<=title=").+?(?=")',html)
return busc,buss,bus_list
def print_res(busc,buss,bus_list):
for i in range(0,len(bus_list)):
if i in busc:
print("====================\t<======途中车辆")
elif i in buss:
print("{0:{1}<10}\t<------到站".format(bus_list[i],chr(12288)))
continue
print("{0:{1}<10}".format(bus_list[i],chr(12288)))
def rec_str(mystr):
# 输入't19'或者'T19'都能自动转换为'特19'
return re.sub('t','特',mystr,flags=re.I)
def main():
# 创建session,自动处理cookies,添加头信息
s = requests.Session()
UA='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
header = {'User-Agent':UA}
s.headers.update(header)
# 输入车次信息,获取班车的特征码uuid以及始末站
bus = rec_str(input("输入查询车次:"))
line_info = getLineDir(bus,s)
fint = input("选择方向:\n[1]{}\n[2]{}\n选择(Enter确认):".format(line_info["1"][1],line_info["2"][1]))
res = system('cls')
uuid = line_info[fint][0]
# 循环查询,间隔10s
while 1:
busc,buss,bus_list = getbus(uuid,s)
print_res(busc,buss,bus_list)
sleep(15)#为了避免给服务器造成影响,时间间隔设置为跟网页查询的一样比较合适
res = system("cls")
main()
后记
最后上一张在Android手机上使用的截图效果:
demo for Android
Android平台的Termux真的很强大,而且还挺稳定,就类似于一个linux bash。在上面安装python3和requests库之后就能正常跑这个脚本了。为了避免每次都繁琐的输入,可以写个简单的shell脚本,内容python ./bus_query.py
,取个简单的名字,比如a
,然后chmod 777 ./a
给权限,就能直接用./a
来运行了。一般更多的只会查询固定班次的车,可以改源码来定制。
差不多就这些东西了,又要继续去搬砖了Orz...
注:仅供学习交流,请合理参考使用
网友评论