通过python获取共享汽车平台Evcard 的车辆位置信息*
我们直接开门见山,但是本文只是提供一个思路,具体还需要大家自行操作(由于是第一次写,有些许的紧张,如有错误的地方,望大家不吝赐教)。 因为我们本次需要爬取的是 Evcard的app所以需要使用抓包软件。常用的抓包工具有fiddler,mitmproxy,Charles。Charles使用需要收费,虽然有半个小时的免费使用时间但是对于我们这种小白来说肯定是不够的,所以我还是果断选择了fiddler。 1.下载fiddler fiddler下载网址(安装什么的网上已经有了很多的介绍我这里就不在讲解): https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe 2.安装好fiddler后打开.exe文件,开始配置,首先点击"tools" -> “Options…”,按照下面图进行配置(如果感觉连电脑端也抓取的话到时候不太分析的话可以选着仅从远端抓取) 3.打开浏览器,输入"http://localhost:8888/",点击最下方,下载证书 4.将下载的证书传到手机上,并进行安装。
安装好证书后,修改手机WLAN的配置 ,并且手机与电脑需要保证在同一局域网中。需要修改的是 : 将所连WiFi的代理改为手动,服务器主机名一项填写自己电脑的IP地址,服务器端口一项填写8888(因为Fiddler一般默认端口是8888),然后保存。就可以开始抓包了。这个配置环节有些麻烦,我当初因为配置错误也是倒腾了好长时间才抓取到数据的。虽然可以抓取到数据,但是抓取的全是带有小锁的不能解析,这个证书配置可以去百度一下,这个还是有很多大佬进行过详细介绍。 这里介绍个讲解fiddler抓包非常详细的大佬文章,大家可以进行参考: https://blog.csdn.net/weixin_43664254/article/details/94601280?ops_request_misc=&request_id=&biz_id=102&utm_term=fiddler%E4%B8%ADHeaders%E8%BF%94%E5%9B%9E%E7%9A%84%E5%90%84%E4%B8%AA%E5%8F%82%E6%95%B0%E7%9A%84%E4%BB%8B%E7%BB%8D&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-2-.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187
当所有所有配置弄好之后,我们真正激动的时刻就要来了,抓取我们需要的链接了,选择的抓取地点是镇江市。 我们先简单分析一下抓取到的所有的链接,通过访问的Host和Body两列可以大致的找到我们需要的链接,这两个链接都是访问的apigw-mas.evcard.vip网站,并且返回大量的数据。 打开这两条信息发现这个正是我们需要的租赁网点分布链接 接下来就要开始分析这个链接是如何请求的了,因为近年来随着APP的包含的数据量变多,导致App的反爬机制越来越牛逼。那么我们就来解析一下这个链接的请求方式,我们先在上面那个视图里面选择Raw,在这个里面可以看到一些请求的参数,了解爬取网站的伙伴应该知道,这些都是我们需要反馈给服务器的一些参数, 我之所以使用fiddler呢,还有一点就是因为这个还自带了一个模拟请求的功能。 可以看出,他已经帮我们设置好了请求的方式是POST还是GET了,以及请求的链接和需要传递的参数位置了,那么我们可以通过上图可以发现,这个是采用的POST请求,请求的链接为:https://apigw-mas.evcard.vip/evcard-mas/api/getGeohashShop?Release=4.14.2&no=0 采用的是HTTP/1.1的方式,这个对我们这个项目的没有什么影响。我们将raw下的参数全部复制到composer里面,下面数据框中填入需要传递的数据,就是raw里面“{}”里面的数据。点击Exeute,可以发现数据请求成功 在里面我们可以删除一些没有用的参数,确定最后需要传递的参数,此外通过解析传递的data可以发现,主要包括我们请求的数据城市,以及请求的范围(根据经纬度进行决定),其余的参数由于我们没有知道他们的具体意义,所以可以暂时不变。 接下来就是利用代码进行实现了。
headers = {
'X-Forwarded-For': 'x-forwarded-for',
'appType': 'Android',
'imei': 'd17fccc1-c16d-3d8f-9fc7-4ba2227a249f',
'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOiJDYzMxZjdhM2NlYTdjNDNjNTlmOGU3MTM4NTVlNDUyOGMiLCJkZXZpY2VJZCI6ImQxN2ZjY2MxLWMxNmQtM2Q4Zi05ZmM3LTRiYTIyMjdhMjQ5ZiIsImV4cGlyZUluIjoxNjI1NTM5MDE4OTU1LCJjcmVhdGVUaW1lIjoxNjIyOTQ3MDE4OTU1LCJwbGF0Zm9ybUNvZGUiOiJhcHAiLCJhcHBJZCI6InNhaWNfZXZjYXJkIiwiY2hhbm5lbENvZGUiOiJzYWljX2V2Y2FyZCIsImFjY291bnROYW1lIjoiMTc4NjE4MjMxMDAiLCJhY2NvdW50VHlwZSI6IjEiLCJ0YWciOiIyIiwicHJvZHVjdElkIjo3LCJlayI6IiJ9.GjnAW8Tj27isDiUdham_QHx7PL1IWplgk0MFE1ucCTm-ZjEBiNzdp-H3CYx-mf3WanCpwYjIYThwIrE7VLNo8Td4h8B26i-ZHiE469x0ZCNQU9JnTd3wzzEcD6Q9IrS8EoBE6_w9VrJ_1ZGF6ivXHe3mio4faNXYqyOma-7l8ds',
'version': '4.8.1',
'channel': 'yyb_1',
'Content-Type': 'application/json; charset=UTF-8',
'Content-Length': '377',
'Host': 'apigw-mas.evcard.vip',
'Connection': 'Keep-Alive',
'Accept-Encoding': 'gzip',
'User-Agent': 'okhttp/3.12.0',
'appkey': 'evcardapp',
'sign': 'A0108BC8DE43F572B35DF9F4DFBA09AB',
'random': 'IpleUh',
'timestamp': '1626850816431',
}
因为经过反复尝试其中三个参数的改变必须是同步的,而且 这个参数大概经过半个小时就会失效,就需要我们重新抓取,这个暂时没有想出很好的解决办法,如何有大佬可以破解这个的话可以在下面评论出来或者私信我。
url = 'https://apigw-mas.evcard.vip/evcard-mas/api/getGeohashShop?Release=4.8.1&no=0'
data = '{"modelList": "", "points": [{"lat": 32.315525, "lon": 118.517724, "type": 2}, {"lat": 31.513974,"lon": 119.037824, "type": 2}], "brandType": 0, "queryOrderType": 1, "restrict": 0, "lat": 31.997431421028207, "lon": 118.79237423494574, "city": "南京市", "positionFlag": 2, "orderVehicleType": 1, "level": 0, "systemType": 0, "businessTag": 0, "serviceCharge": 0, "returnVehicle": 0}'
byte_data = data.encode('utf-8')
r = requests.post(url, headers=headers, data=byte_data)
content = r.json()
因为我们传递的data里面有中文,所以我们需要进行编码,然后在进行传递 这样我们就能获取到每个网点的信息了,将我们需要的进行提取,这样获取没有网点的详细信息就完成了。 接下来就是该获取没有网点里面停放的车辆了,因为没有网点都将对应一个id,我们通过在获取请求车辆的链接就可以彻底完成了,这个步骤还是个前面获取网点信息的方法一样,其中传递的参数也是一样的,唯一改变的就是传递的data,这个我们通过解析获得请求的链接以及需要传递的data。
url = 'https://apigw-mas.evcard.vip/evcard-mas/api/getVehicleInfoList?Release=4.8.1&no=0'
data = '{"vehicleModelSeq":"","shopSeq":%s}' % id
byte_data = data.encode('utf-8')
carlist = requests.post(url, headers=headers, data=byte_data).json()
print(carlist)
通过解析传递的data可以发现,我们需要传递一个“shopSeq”,这个就是没有网点的id,部分代码如下:
data = '{"modelList":"","points":[{"lat":32.288109038885416,"lon":119.39875155576782,"type":2},{"lat":32.08202508045243,"lon":119.51765454521818,"type":2}],"brandType":0,"queryOrderType":1,"restrict":0,"lat":32.18512594156467,"lon":119.4582030504944,"city":"镇江市","positionFlag":2,"orderVehicleType":1,"level":0,"stack":0,"systemType":0,"businessTag":0,"serviceCharge":0,"dotType":0,"returnVehicle":0}'
byte_data = data.encode('utf-8')
r = requests.post(url, headers=headers, data=byte_data)
content = r.json()
ids = jsonpath.jsonpath(content, '$..id')
for id in ids:
Carlocation(id)
def Carlocation(id):
url = 'https://apigw-mas.evcard.vip/evcard-mas/api/getVehicleInfoList?Release=4.8.1&no=0'
data = '{"vehicleModelSeq":"","shopSeq":%s}' % id
byte_data = data.encode('utf-8')
carlist = requests.post(url, headers=headers, data=byte_data).json()
print(carlist)
获取数据如上图,可以看出这很好的获取到了每个网点的车辆数据,如何我们可以实现定时爬取的话,我们就可以获取到每个车辆的位置数据,然后进行分析就可以得到车辆的订单OD数据。 定时爬取以及数据处理这里就并不在介绍,大家如何感兴趣的话可以在评论去进行讨论。 因为是第一次写博客,肯定会有很多的不足,希望大家可以包容!!!! 谢谢大家!!!!
|