首页 存档 技术 查看内容

用python抓取摩拜单车API数据并做可视化分析(源码) 从哪里获得数据 高兴得太早。。。 ...

2018-3-30 13:00 |来自: 互联网 351 0

摘要: 数据挖掘入门与实战 公众号: datadw 警告:此篇文章仅作为学习研究参考用途,请不要用于非法目的。 摩拜是最早进入成都的共享单车,每天我从地铁站下来的时候,在APP中能看到很多单车,但走到那里的时候,才发现 ...



数据挖掘入门与实战 公众号: datadw


警告:此篇文章仅作为学习研究参考用途,请不要用于非法目的。


摩拜是最早进入成都的共享单车,每天我从地铁站下来的时候,在APP中能看到很多单车,但走到那里的时候,才发现车并不在那里。有些车不知道藏到了哪里;有些车或许是在高楼的后面,由于有GPS的误差而找不到了;有些车被放到了小区里面,一墙之隔让骑车人无法获得到车。


那么有没有一个办法通过获得这些单车的数据,来分析这些车是否变成了僵尸车?是否有人故意放到小区里面让人无法获取呢?


带着这些问题,我开始了研究如何获取这些数据。


从哪里获得数据

如果你能够看到数据,那么我们总有办法自动化的获取到这些数据。只不过获取数据的方式方法决定了获取数据的效率,对于摩拜单车的数据分析这个任务而言,这个爬虫要能够在短时间内(通常是10分钟左右)获取到更多的数据,对于数据分析才有用处。那么数据来源于哪里?


最直接的来源是摩拜单车的APP。现代的软件设计都讲究前后端分离,而且服务端会同时服务于APP、网页等。在这种趋势下我们只需要搞清楚软件的HTTP请求就好了。一般而言有以下一些工具可以帮忙:


直接抓包:

  • Wireshark (在路由器或者电脑)

  • Shark for Root (Android)

用代理进行HTTP请求抓包及调试:

  • Fiddler 4

  • Charles

  • Packet Capture (Android)

由于我的手机没有root,在路由器上抓包又太多的干扰,对于https也不好弄。所以只能首先采用Fiddler或者Charles的方式试试。挂上Fiddler的代理,然后在手机端不停的移动位置,看有没有新的请求。但遗憾的是似乎请求都是去拿高德地图的,并没有和摩拜车相关的数据。


那怎么一回事?试试手机端的。换成Packet Capture后果然就有流量了,在请求中找到了我最关心的那个:




这个API请求一看就很显然了,在postman中试了一下能够正确的返回信息,看来就是你了!


高兴得太早。。。

连续爬了几天的数据,将数据进行一分析,发现摩拜单车的GPS似乎一直在跳动,有时候跳动会超过几公里的距离,显然不是一个正常的值。


难道是他们的接口做了手脚返回的是假数据?我观察到即便在APP中,单车返回的数据也有跳动。有某一天凌晨到第二天早上,我隔段时间刷新一下我家附近的车,看看是否真的如此。


图片我找不到了,但是观察后得出的结论是,APP中返回的位置确实有问题。有一台车放在一个很偏僻的位置,一会儿就不见了,待会儿又回来了,和我抓下来的数据吻合。而且这个跳动和手机、手机号、甚至移动运营商没有关系,说明这个跳动是摩拜接口的问题,也可以从另一方面解释为什么有时候看到车但其实那里没有车。


这是之前发的一个朋友圈的视频截图,可以看到在营门口附近有一个尖,在那里其实车是停住的,但是GPS轨迹显示短时间内在附近攒动,甚至攒动到很远,又回到那个位置。



这样的数据对于数据分析来讲根本没法用,我差点就放弃了。


随着微信小程序的火爆,摩拜单车也在第一时间出了小程序。我一看就笑了,不错,又给我来了一个数据源,试试。用Packet Capture抓了一次数据后很容易确定API。抓取后爬取了两三天的数据,发现出现了转机,数据符合正常的单车的轨迹。


剩下事情,就是提高爬虫的效率了。



其他尝试

有时候直接分析APP的源代码会很方便的找到API入口,将摩拜的Android端的APP进行反编译,但发现里面除了一些资源文件有用外,其他的文件都是用奇虎360的混淆器加壳的。网上有文章分析如何进行脱壳,但我没有太多时间去钻研,也就算了。



摩拜单车的API之所以很容易抓取和分析,很大程度上来讲是由于API设计的太简陋:

  • 仅使用http请求,使得很容易进行抓包分析

  • 在这些API中都没有对request进行一些加密,使得自己的服务很容易被人利用。

  • 另外微信小程序也是泄露API的一个重要来源,毕竟在APP中request请求可以通过native代码进行加密然后在发出,但在小程序中似乎还没有这样的功能。

如果大家有兴趣,可以试着看一下小蓝单车APP的request,他们使用https请求,对数据的request进行了加密,要抓取到他们的数据难度会增加非常多。

当然了,如果摩拜单车官方并不care数据的事情的话,这样的API设计也是ok的。



声明:
此爬虫仅用于学习、研究用途,请不要用于非法用途。任何由此引发的法律纠纷自行负责。

没耐心看文章的请直接:


关注公众号datadw 后回复“摩拜”获取完整源码


目录结构

\analysis - jupyter做数据分析
\influx-importer - 导入到influxdb,但之前没怎么弄好
\modules - 代理模块
\web - 实时图形化显示模块,当时只是为了学一下react而已,效果请见这里
crawler.py - 爬虫核心代码
importToDb.py - 导入到postgres数据库中进行分析
sql.sql - 创建表的sql
start.sh - 持续运行的脚本

思路
核心代码放在crawler.py中,数据首先存储在sqlite3数据库中,然后去重复后导出到csv文件中以节约空间。

摩拜单车的API返回的是一个正方形区域中的单车,我只要按照一块一块的区域移动就能抓取到整个大区域的数据。

left,top,right,bottom定义了抓取的范围,目前是成都市绕城高速之内以及南至南湖的正方形区域。offset定义了抓取的间隔,现在以0.002为基准,在DigitalOcean 5$的服务器上能够15分钟内抓取一次。

def start(self):
left = 30.7828453209
top = 103.9213455517
right = 30.4781772402
bottom = 104.2178123382

offset = 0.002

if os.path.isfile(self.db_name):
os.remove(self.db_name)

try:
with sqlite3.connect(self.db_name) as c:
c.execute('''CREATE TABLE mobike
(Time DATETIME, bikeIds VARCHAR(12), bikeType TINYINT,distId INTEGER,distNum TINYINT, type TINYINT, x DOUBLE, y DOUBLE)''')
except Exception as ex:
pass

然后就启动了250个线程,至于你要问我为什么没有用协程,哼哼~~我当时没学~~~其实是可以的,说不定效率更高。

由于抓取后需要对数据进行去重,以便消除小正方形区域之间重复的部分,最后的group_data正是做这个事情。

executor = ThreadPoolExecutor(max_workers=250)
print("Start")
self.total = 0
lat_range = np.arange(left, right, -offset)
for lat in lat_range:
lon_range = np.arange(top, bottom, offset)
for lon in lon_range:
self.total = 1
executor.submit(self.get_nearby_bikes, (lat, lon))

executor.shutdown()
self.group_data()

最核心的API代码在这里。小程序的API接口,搞几个变量就可以了,十分简单。

def get_nearby_bikes(self, args):
try:
url = "https://mwx.mobike.com/mobike-api/rent/nearbyBikesInfo.do"

payload = "latitude=%s

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部