开发那点事(六)php抓取北京实时公交数据

开发背景
自己开发一款北京实时公交的小程序,奈何在网上苦苦寻找api接口无果,最后只得爬取网上数据
项目构思
1 选定爬虫框架—QueryList
2 数据源选定—北京公交网
3 根据需求将div格式化成json数据
开发实践
1 QueryList安装,利用composer直接进行安装,点我进官网查看示例

composer require jaeger/querylist

在控制器中引用

find('img')->attrs('src');
       //打印结果
       print_r($data->all());
    }
}

2 数据源接口确定

获取行驶方向

http://www.bjbus.com/home/ajax_rtbus_data.php?act=getLineDir&selBLine=428

返回内容

428(天通北苑-地铁龙泽站)
428(地铁龙泽站-天通北苑)

获取行驶情况

http://www.bjbus.com/home/ajax_rtbus_data.php?act=busTime&selBLine=1&selBDir=

返回内容

{
    "html": "

428路

天通北苑-地铁龙泽站

天通北苑 5:30-23:00 分段计价 所属客一分公司

车辆均已过站

  • 天通北苑
  • 天通东苑三区
    ...
  • 天通北苑三区
    ...
  • 天通北苑三区
    ...
  • 天通北苑二区
    ...
  • 狮子营西门
  • 天通北苑二区
    ...
  • 天通北苑一区
    ...
  • 地铁天通苑北
    ...
  • 东三旗
  • 半截塔村东站
  • 半截塔村北站
  • 魏窑村
  • 绿野福苑
  • 小辛庄东
  • 小辛庄
  • 小辛庄西
  • 龙锦苑东二区
    ...
  • 上坡路口西
  • 和谐家园一区
    ...
  • 龙锦苑二区
  • 田园风光雅苑
  • 龙锦苑四区
  • 马连店南口
  • 龙禧苑三区北
    ...
  • 龙禧苑三区路
    ...
  • 回龙观公交场
    ...
  • 风雅园北
  • 三合庄园
  • 龙华园
  • 龙华园南区
  • 地铁龙泽站
途中车辆到站车辆
", "w": 1532, "seq": "1" }

3 将div格式化成json
获取公交线路比较简单,只有两个a标签,我们只需获取其中的text以及uuid就可以,以下是代码

  public function getBusLine($busName)
    {
        $rules = [
            // 公交车名称
            'name' => ['a', 'text'],
            // 公交车uuid
            'uuid' => ['a', 'data-uuid']
        ];
        //采集某页面所有的图片
        $data = QueryList::get('http://www.bjbus.com/home/ajax_rtbus_data.php?act=getLineDir&selBLine=' . $busName
        )->rules($rules)->query()->getData();;
        //打印结果
        $result = $data->all();
        if (count($result) === 0) {
            throw new ParameterException(['msg' => '暂无公交信息']);
        }
        for ($i = 0; $i < count($result); $i++) {
            $array = explode('(', $result[$i]['name']);
            $result[$i]['name'] = $array[0];
            $result[$i]['busLine'] = substr($array[1], 0, strlen($array[1]) - 1);
        }

        return $result;
    }

获取公交行驶情况比较复杂,需要注意span标签与i标签的关系

  public function getBusInfo($uuid)
    {
        $rules = [
            // 公交车名称
            'status' => ['div>i', 'class'],
            'name' => ['div>span', 'title'],
            'headInfo' => ['article>p', 'text']
        ];
        $result = get('http://www.bjbus.com/home/ajax_rtbus_data.php?act=busTime&selBLine=1&selBDir=' . $uuid . '&selBStop=1');
        $result = json_decode($result, true);
        if (!array_key_exists('html', $result)) {
            throw new ParameterException(['msg' => '查询公交信息失败']);
        }
        $data = QueryList::html($result['html'])->rules($rules)->query()->getData();
        $busResult = $data->all();
        $result = [
            'time' => '',
            'busInfo' => [],
            'busc' => 0
        ];
        $result['time'] = $busResult[0]['headInfo'];
        //for循环是精髓
        for ($i = 0; $i < count($busResult) / 2; $i++) {
            $resultItem = [];
            $resultItem['busName'] = $busResult[$i]['name'];
            if ($i == 0) {
                $resultItem['buss'] = $busResult[$i]['status'] == 'buss';
                $resultItem['busc'] = $busResult[$i + 1]['status'] == 'busc';
                if ($resultItem['buss']) {
                    $result['busc'] = $result['busc'] + 1;
                }
                if ($resultItem['busc']) {
                    $result['busc'] = $result['busc'] + 1;
                }
            } else {
                $resultItem['buss'] = $busResult[($i * 2)]['status'] == 'buss';
                if ($resultItem['buss']) {
                    $result['busc'] = $result['busc'] + 1;
                }
                if ($i !== (count($busResult) - 1) / 2) {
                    $resultItem['busc'] = $busResult[($i * 2 + 1)]['status'] == 'busc';
                    if ($resultItem['busc']) {
                        $result['busc'] = $result['busc'] + 1;
                    }
                }
            }
            array_push($result['busInfo'], $resultItem);
        }

        return $result;
    }

4 最后格式化完成后的json数据
公交线路

{
    "responseCode": 0,
    "responseMessage": "查询成功",
    "data": [
        {
            "name": "428",
            "uuid": "4907320871547002333",
            "busLine": "天通北苑-地铁龙泽站"
        },
        {
            "name": "428",
            "uuid": "5415569149649522461",
            "busLine": "地铁龙泽站-天通北苑"
        }
    ]
}

公交信息(其中busc表示途中车辆,buss表示到站车辆)

{
    "responseCode": 0,
    "responseMessage": "查询成功",
    "data": {
        "time": "天通北苑 5:30-23:00 分段计价 所属客一分公司",
        "busInfo": [
            {
                "busName": "天通北苑",
                "buss": false,
                "busc": false
            },
            {
                "busName": "天通东苑三区西门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "天通北苑三区南门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "天通北苑三区南",
                "buss": false,
                "busc": false
            },
            {
                "busName": "天通北苑二区东门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "狮子营西门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "天通北苑二区北门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "天通北苑一区北门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "地铁天通苑北站南",
                "buss": false,
                "busc": false
            },
            {
                "busName": "东三旗",
                "buss": false,
                "busc": false
            },
            {
                "busName": "半截塔村东站",
                "buss": false,
                "busc": false
            },
            {
                "busName": "半截塔村北站",
                "buss": false,
                "busc": false
            },
            {
                "busName": "魏窑村",
                "buss": false,
                "busc": false
            },
            {
                "busName": "绿野福苑",
                "buss": false,
                "busc": false
            },
            {
                "busName": "小辛庄东",
                "buss": false,
                "busc": false
            },
            {
                "busName": "小辛庄",
                "buss": false,
                "busc": false
            },
            {
                "busName": "小辛庄西",
                "buss": false,
                "busc": false
            },
            {
                "busName": "龙锦苑东二区北门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "上坡路口西",
                "buss": false,
                "busc": false
            },
            {
                "busName": "和谐家园一区北门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "龙锦苑二区",
                "buss": false,
                "busc": false
            },
            {
                "busName": "田园风光雅苑",
                "buss": false,
                "busc": false
            },
            {
                "busName": "龙锦苑四区",
                "buss": false,
                "busc": false
            },
            {
                "busName": "马连店南口",
                "buss": false,
                "busc": false
            },
            {
                "busName": "龙禧苑三区北门",
                "buss": false,
                "busc": false
            },
            {
                "busName": "龙禧苑三区路口西",
                "buss": false,
                "busc": false
            },
            {
                "busName": "回龙观公交场站",
                "buss": false,
                "busc": false
            },
            {
                "busName": "风雅园北",
                "buss": false,
                "busc": false
            },
            {
                "busName": "三合庄园",
                "buss": false,
                "busc": false
            },
            {
                "busName": "龙华园",
                "buss": false,
                "busc": true
            },
            {
                "busName": "龙华园南区",
                "buss": false,
                "busc": false
            },
            {
                "busName": "地铁龙泽站",
                "buss": false
            }
        ],
        "busc": 1
    }
}

总的来说,比较简单,需要注意的就是两个接口关联的地方uuid,以及span与i标签的关系

你可能感兴趣的:(开发那点事(六)php抓取北京实时公交数据)