開發那點事(六)php抓取北京實時公交數據

開發背景
自己開發一款北京實時公交的小程序,奈何在網上苦苦尋找api接口無果,最後只得爬取網上數據
項目構思
1 選定爬蟲框架—QueryList
2 數據源選定—北京公交網
3 根據需求將div格式化成json數據
開發實踐
1 QueryList安裝,利用composer直接進行安裝,點我進官網查看示例

composer require jaeger/querylist

在控制器中引用

<?php
namespace app\index\controller;
use QL\QueryList;
class Index
{
    public function index()
    {
       //採集某頁面所有的圖片
       $data = QueryList::get('http://cms.querylist.cc/bizhi/453.html')->find('img')->attrs('src');
       //打印結果
       print_r($data->all());
    }
}

2 數據源接口確定

獲取行駛方向

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

返回內容

<a href="javascript:;" data-uuid="4907320871547002333">428(天通北苑-地鐵龍澤站)</a>
<a href="javascript:;" data-uuid="5415569149649522461">428(地鐵龍澤站-天通北苑)</a>

獲取行駛情況

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

返回內容

{
    "html": "<div class=\"inquiry_header\"><div class=\"left fixed\"><h3 id=\"lh\">428路</h3></div><div class=\"inner\"><h2 id=\"lm\">天通北苑-地鐵龍澤站</h2><article><p>天通北苑&nbsp;5:30-23:00&nbsp;分段計價&nbsp;所屬客一分公司</p><p>車輛均已過站</p></article></div></div><div id=\"cc_stop\" class=\"inquiry_main\" unselectable=\"on\" onselectstart=\"return false;\"><ul class=\"fixed\"><li><div id=\"1\"><i></i><p class=\"sicon\"></p><span title=\"天通北苑\">天通北苑</span></div></li><li><div id=\"2m\"><i ></i></div></li><li><div id=\"2\"><i></i><p class=\"sicon\"></p><span title=\"天通東苑三區西門\">天通東苑三區<br/>...</span></div></li><li><div id=\"3m\"><i ></i></div></li><li><div id=\"3\"><i></i><p class=\"sicon\"></p><span title=\"天通北苑三區南門\">天通北苑三區<br/>...</span></div></li><li><div id=\"4m\"><i ></i></div></li><li><div id=\"4\"><i></i><p class=\"sicon\"></p><span title=\"天通北苑三區南\">天通北苑三區<br/>...</span></div></li><li><div id=\"5m\"><i ></i></div></li><li><div id=\"5\"><i></i><p class=\"sicon\"></p><span title=\"天通北苑二區東門\">天通北苑二區<br/>...</span></div></li><li><div id=\"6m\"><i ></i></div></li><li><div id=\"6\"><i></i><p class=\"sicon\"></p><span title=\"獅子營西門\">獅子營西門</span></div></li><li><div id=\"7m\"><i ></i></div></li><li><div id=\"7\"><i></i><p class=\"sicon\"></p><span title=\"天通北苑二區北門\">天通北苑二區<br/>...</span></div></li><li><div id=\"8m\"><i ></i></div></li><li><div id=\"8\"><i></i><p class=\"sicon\"></p><span title=\"天通北苑一區北門\">天通北苑一區<br/>...</span></div></li><li><div id=\"9m\"><i  class=\"busc\" clstag=\"\"></i></div></li><li><div id=\"9\"><i></i><p class=\"sicon\"></p><span title=\"地鐵天通苑北站南\">地鐵天通苑北<br/>...</span></div></li><li><div id=\"10m\"><i ></i></div></li><li><div id=\"10\"><i></i><p class=\"sicon\"></p><span title=\"東三旗\">東三旗</span></div></li><li><div id=\"11m\"><i ></i></div></li><li><div id=\"11\"><i></i><p class=\"sicon\"></p><span title=\"半截塔村東站\">半截塔村東站</span></div></li><li><div id=\"12m\"><i ></i></div></li><li><div id=\"12\"><i></i><p class=\"sicon\"></p><span title=\"半截塔村北站\">半截塔村北站</span></div></li><li><div id=\"13m\"><i ></i></div></li><li><div id=\"13\"><i></i><p class=\"sicon\"></p><span title=\"魏窯村\">魏窯村</span></div></li><li><div id=\"14m\"><i ></i></div></li><li><div id=\"14\"><i></i><p class=\"sicon\"></p><span title=\"綠野福苑\">綠野福苑</span></div></li><li><div id=\"15m\"><i ></i></div></li><li><div id=\"15\"><i></i><p class=\"sicon\"></p><span title=\"小辛莊東\">小辛莊東</span></div></li><li><div id=\"16m\"><i ></i></div></li><li><div id=\"16\"><i></i><p class=\"sicon\"></p><span title=\"小辛莊\">小辛莊</span></div></li><li><div id=\"17m\"><i ></i></div></li><li><div id=\"17\"><i></i><p class=\"sicon\"></p><span title=\"小辛莊西\">小辛莊西</span></div></li><li><div id=\"18m\"><i ></i></div></li><li><div id=\"18\"><i></i><p class=\"sicon\"></p><span title=\"龍錦苑東二區北門\">龍錦苑東二區<br/>...</span></div></li><li><div id=\"19m\"><i ></i></div></li><li><div id=\"19\"><i></i><p class=\"sicon\"></p><span title=\"上坡路口西\">上坡路口西</span></div></li><li><div id=\"20m\"><i ></i></div></li><li><div id=\"20\"><i></i><p class=\"sicon\"></p><span title=\"和諧家園一區北門\">和諧家園一區<br/>...</span></div></li><li><div id=\"21m\"><i ></i></div></li><li><div id=\"21\"><i></i><p class=\"sicon\"></p><span title=\"龍錦苑二區\">龍錦苑二區</span></div></li><li><div id=\"22m\"><i ></i></div></li><li><div id=\"22\"><i></i><p class=\"sicon\"></p><span title=\"田園風光雅苑\">田園風光雅苑</span></div></li><li><div id=\"23m\"><i ></i></div></li><li><div id=\"23\"><i class=\"buss\" clstag=\"-1\"></i><p class=\"sicon\"></p><span title=\"龍錦苑四區\">龍錦苑四區</span></div></li><li><div id=\"24m\"><i ></i></div></li><li><div id=\"24\"><i></i><p class=\"sicon\"></p><span title=\"馬連店南口\">馬連店南口</span></div></li><li><div id=\"25m\"><i ></i></div></li><li><div id=\"25\"><i></i><p class=\"sicon\"></p><span title=\"龍禧苑三區北門\">龍禧苑三區北<br/>...</span></div></li><li><div id=\"26m\"><i ></i></div></li><li><div id=\"26\"><i></i><p class=\"sicon\"></p><span title=\"龍禧苑三區路口西\">龍禧苑三區路<br/>...</span></div></li><li><div id=\"27m\"><i ></i></div></li><li><div id=\"27\"><i></i><p class=\"sicon\"></p><span title=\"回龍觀公交場站\">回龍觀公交場<br/>...</span></div></li><li><div id=\"28m\"><i ></i></div></li><li><div id=\"28\"><i></i><p class=\"sicon\"></p><span title=\"風雅園北\">風雅園北</span></div></li><li><div id=\"29m\"><i ></i></div></li><li><div id=\"29\"><i></i><p class=\"sicon\"></p><span title=\"三合莊園\">三合莊園</span></div></li><li><div id=\"30m\"><i ></i></div></li><li><div id=\"30\"><i></i><p class=\"sicon\"></p><span title=\"龍華園\">龍華園</span></div></li><li><div id=\"31m\"><i ></i></div></li><li><div id=\"31\"><i></i><p class=\"sicon\"></p><span title=\"龍華園南區\">龍華園南區</span></div></li><li><div id=\"32m\"><i ></i></div></li><li><div id=\"32\"><i></i><p class=\"sicon\"></p><span title=\"地鐵龍澤站\">地鐵龍澤站</span></div></li></ul></div><div class=\"inquiry_footer\"><section><div class=\"inner\"><span class=\"buss\">途中車輛</span><span class=\"busc\">到站車輛</span></div></section></div>",
    "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標籤的關係

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章