爬虫获取mobike共享单车信息

背景:端午节假期的时候参加了学校的数学建模比赛,题目是关于共享单车的供需匹配问题,需要获得共享单车的数量和时空分布情况。

在苦苦找寻数据无果的情况下决定自己用爬虫对天津地区的mobike进行统计。

在网上找到了这篇爬虫的代码,本着少造轮子的基本原则,我选择了这个代码进行统计,这里记录一下历程,方便日后查阅。

先上原作者github地址:git clone https://github.com/derekhe/mobike-crawler。python3环境,爬取的是微信小程序,之前是可以爬手机客户端的,不过随着客户端完善变得难爬,小程序的爬取

能用到什么时候要也不确定。

我会把我的一些代码和数据放到百度云里,链接在文末,有需要的小伙伴可以自取。

一、数据之初探

首先确定了要爬取微信小程序的时候,先需要确定一个大概的方向,下载fiddler,对微信小程序进行抓包处理,这一步进展比较顺利。不太了解这一步的可以搜索手机APP抓包相关的知识,这里不再赘述。

比较容易的发现在请求页面需要post你的经纬度坐标给https://mwx.mobike.com/mobike-api/rent/nearbyBikesInfo.do这个网页,然后返回周围的车的信息,包括

bikeID,distX,distY,distance等信息,比较方便的是这些信息都放在了json文件中。而我们关系的只是车的位置和距离即distX,distY,distance。

注意点是要把浏览器头部伪装成手机浏览器。

z.json()[‘object‘]即可。

import requests
headers = {
    ‘User-Agent‘: ‘Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E304 MicroMessenger/6.5.7 NetType/WIFI Language/zh_CN‘,
    ‘Content-Type‘: ‘application/x-www-form-urlencoded‘,
    ‘Referer‘: ‘https://servicewechat.com/wx80f809371ae33eda/23/page-frame.html‘,
}
url = ‘https://mwx.mobike.com/mobike-api/rent/nearbyBikesInfo.do‘
data = {
    ‘longitude‘:‘121.1883‘,# 经度
    ‘latitude‘:‘31.05147‘, # 纬度
    ‘citycode‘:‘021‘,
    ‘errMsg‘:‘getMapCenterLocation:ok‘

}
z = requests.post(url,data=data,headers=headers,verify=False)

二、数据之再思考

有了第一步的初探,下一步需要做的东西也十分清楚。要获得天津地区的Mobike数量可以近似画一个长方形,用爬虫爬取这个长方形内的自行车数目即可。

直接贴原作者的代码,我的代码在其中做了一些修改,不过我是放在了jupyter notebook中运行的,页面中有将近十万的运行结果数据的原因,每次打开代码都会卡死。。。

需要注意的点是,在我电脑上运行时找不到retrying库,直接去掉即可运行。运行结果放在db文件夹下。

offset设置为0.002左右即可,太大容易导致漏数,太小会有重复误差。这也是网上有其他代码用数据库的原因,不过由于数学建模的时间紧张,再加我对数据库不太熟悉,直接暴力设定爬取步长也没出现问题。

import datetime
import os
import os.path
import random
import sqlite3
import threading
import time
import ujson
from concurrent.futures import ThreadPoolExecutor

import numpy as np
import requests
from retrying import retry

from modules.ProxyProvider import ProxyProvider

class Crawler:
    def __init__(self):
        self.start_time = datetime.datetime.now()
        self.csv_path = "./db/" + datetime.datetime.now().strftime("%Y%m%d")
        os.makedirs(self.csv_path, exist_ok=True)
        self.csv_name = self.csv_path + "/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + ‘.csv‘
        self.db_name = "./temp.db"
        self.lock = threading.Lock()
        self.proxyProvider = ProxyProvider()
        self.total = 0
        self.done = 0

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

            payload = "latitude=%s&longitude=%s&errMsg=getMapCenterLocation" % (args[0], args[1])

            headers = {
                ‘charset‘: "utf-8",
                ‘platform‘: "4",
                "referer":"https://servicewechat.com/wx40f112341ae33edb/1/",
                ‘content-type‘: "application/x-www-form-urlencoded",
                ‘user-agent‘: "MicroMessenger/6.5.4.1000 NetType/WIFI Language/zh_CN",
                ‘host‘: "mwx.mobike.com",
                ‘connection‘: "Keep-Alive",
                ‘accept-encoding‘: "gzip",
                ‘cache-control‘: "no-cache"
            }

            self.request(headers, payload, args, url)
        except Exception as ex:
            print(ex)

    def request(self, headers, payload, args, url):
        while True:
            proxy = self.proxyProvider.pick()
            try:
                response = requests.request(
                    "POST", url, data=payload, headers=headers,
                    proxies={"https": proxy.url},
                    timeout=5,verify=False
                )

                with self.lock:
                    with sqlite3.connect(self.db_name) as c:
                        try:
                            print(response.text)
                            decoded = ujson.decode(response.text)[‘object‘]
                            self.done += 1
                            for x in decoded:
                                c.execute("INSERT INTO mobike VALUES (%d,‘%s‘,%d,%d,%s,%s,%f,%f)" % (
                                    int(time.time()) * 1000, x[‘bikeIds‘], int(x[‘biketype‘]), int(x[‘distId‘]),
                                    x[‘distNum‘], x[‘type‘], x[‘distX‘],
                                    x[‘distY‘]))

                            timespend = datetime.datetime.now() - self.start_time
                            percent = self.done / self.total
                            total = timespend / percent
                            print(args, self.done, percent * 100, self.done / timespend.total_seconds() * 60, total,
                                  total - timespend)
                        except Exception as ex:
                            print(ex)
                    break
            except Exception as ex:
                proxy.fatal_error()

    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

        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()

    def group_data(self):
        print("Creating group data")
        conn = sqlite3.connect(self.db_name)
        cursor = conn.cursor()

        f = open(self.csv_name, "w")
        for row in cursor.execute(‘‘‘SELECT * FROM mobike‘‘‘):
            timestamp, bikeIds, bikeType, distId, distNumber, type, lon, lat = row
            f.write("%s,%s,%s,%s,%s,%s,%s,%s\n" % (
                datetime.datetime.fromtimestamp(int(timestamp) / 1000).isoformat(), bikeIds, bikeType, distId, distNumber, type, lon, lat))
        f.flush()
        f.close()

        os.system("gzip -9 " + self.csv_name)

Crawler().start()

三、数据简单处理和分析

爬取天津主城区(红桥区,河西区,河东区,和平区,南开区,河北区)和周边范围的Mobike,

爬取结果大概为98398辆,利用Kmeans聚类进行聚类分析。

分别取聚类点50,75,100,150,200来通过matplotlib绘图观察聚类结果。选择n_clusters=50。

得到聚类中心点坐标,然后再利用反解析软件解析坐标对应的地点信息,即可获得共享单车的主要分布区域。

最后,一些数据和代码放在百度云上,用则自取。

百度云地址:http://pan.baidu.com/s/1eRHjmVK密码:d5dw

以上。

:)

时间: 2024-08-02 06:59:05

爬虫获取mobike共享单车信息的相关文章

共享单车微信小程序

微信小程序bike单车,前台使用小程序地图控件+weui+小程序相关组件和API,后台使用SpringBoot+JPA,用户及单车信息保存进mongodb,短信平台的配置信息和临时生成的验证码存放进redis用于校验.实现定位,单车增加及搜索,用户注册,短信接口调用,支付押金等功能. 1. 地图定位及显示周围单车数量 页面通过<map>标签来引入微信地图 <map id='myMap' longitude='{{longitude}}' latitude='{{latitude}}' c

python3爬虫-通过requests获取安居客房屋信息

import requests from fake_useragent import UserAgent from lxml import etree from http import cookiejar import re, time import pymysql import random from requests.exceptions import Timeout ua = UserAgent() session = requests.Session() class MyExceptio

聊一聊共享单车

1.共享单车的模式用户交押金,然后骑车,按照骑车时间进行计费.其实,严格意义上来讲,这还并不属于共享经济,更像分时租赁. 2.共享单车的用户人群 & 特征用户人群:80后.90后的低频打车人群,其中学生.白领偏多用户特征:年轻群体.接受新兴事物能力强,追求时尚:城市节奏生活快,白领.学生等时间紧张,交通拥堵现象严重:中低端消费人群,追求性价比:城市污染问题日益严重,追求环保出行方式 3.满足需求:主要满足了用户 短途出行的需求,具体如下:固定需求:固定线路:上学/放学.上班/下班,从学校.公司等

FM源码、OFO共享单车源码、股票K线分时线源码等

iOS精选源码 一个多环条形联动的动画 仿今日头条的菜单栏,可编辑菜单栏条目 一款优秀的 聆听夜空FM 源码 仿汽车报价大全PK界面 高度自定义的视频播放器 高仿OFO共享单车(SWIFT版) 一款实现股票k线图.分时图的demo 基本满足股票的需求 原创情侣应用-小冤家 React Native编写的简易购物车Demo 扩大循环菜单按钮ASExtendedCircularMenu iOS优质博客 iOS开发者的Weex伪最佳实践指北 引子这篇文章是笔者近期关于Weex在iOS端的一些研究和实践

关于共享单车的供电问题如何解决?

摩拜一代,后轮上的发电机. 给后轮上安装一个发电花鼓,然后在正常骑行的时候少工作或者不工作,在刹车的时候满负荷工作,所以这种车骑的时候稍微重一点,而且刹车的时候手感和一般自行车不太一样: 一般自行车,无论你多用力捏闸,这种摩擦减速的特性不会被改变的一点是:车速越快,制动效果越差,停车时,制动效果最强.制动力与车速成反比关系.这是一般自行车,实际上也是所有通过摩擦产生制动效果的机械的共有特性. 然而摩拜单车的后轮制动效果,从感受上来说,几乎是反过来的:车速越快,制动效果越强劲,停车时,完全感受不到

Windows批处理:自动开启远程桌面,并获取登录所需信息

公司办公场地分别在两个不同的楼层,处理问题要来回跑,所以思考使用远程访问的方式解决问题.同事大多对电脑不熟悉,使用「通讯软件」和「电话」教同事开启远程桌面沟通成本挺高,另外公司IP地址.账号密码都没统一管理,使用远程桌面的前提:①开启远程 ②获取IP地址 ③获取用户名密码.经过一番思考,发现使用批处理解决这些问题并不复杂. 当同事遇到问题时:我通过「通讯软件」将脚本发送给同事 > 同事执行 > 我使用远程桌面操作. 脚本先开启远程桌面服务,接下来获取当前用户名.让用户输入密码.获取IP,这些信

ASP.NET MVC单点登录(多站点共享用户信息)

一.多站点共享用户信息解决方案: 采用分布式缓存Memcache模拟Session进行用户信息信息共享 1.视图部分 @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>XX商城后台管理系统登录</title> <script type="text/javascript"> if (window.parent.window != window) { wi

从利民出行到扰乱城市交通,共享单车怎么了?

8月18日,上海市交委发布通知,率先对共享单车按下"STOP"键,禁止共享单车在上海新增投放车辆.这标志着上海政府正式插手对共享单车的管理,共享单车的发展进入一个新阶段. 除了上海以外,8月22日,广州市交委也明确要求,禁止共享单车新车投放.南京.合肥等地也有相关政策. 政府插手共享单车市场早有先例 其实,早在今年3月份,上海市交委就要求6家共享单车公司暂停在市中心城区投放新车辆:几乎同一时间,北京市中心的西城区发布消息称禁止共享单车在指定的10条大街上停放车辆. 可是,与共享单车的疯

关于共享单车,说点什么

共享单车,这也许是今年夏天以来最火的一个词语了.然而,它的火不只是在概念上,也真真切切的深入到我们每个人的身边.先上几张图片吧! mobike ofo 先简单说一些,我对这两款产品的看法. 1.从科技角度 这一点,相信不用多说,大家都有结论.ofo单车,可以说和普通自行车没有一点不同.而mobike单车,明显不同于传统的单车.从铃铛到车轮,再到轮胎,再到链条.充满了大量创新元素.科技元素.其中包括,发电及供电设备.移动通信设备.精度定位设备.人机交互设备.从二维码扫码开锁,到自动定位.预约,再到