开发那点事(六)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标签的关系

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,158评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,600评论 1 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,785评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,655评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,075评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,002评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,146评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,918评论 0 211
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,671评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,838评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,318评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,636评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,343评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,187评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,982评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,126评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,934评论 2 279

推荐阅读更多精彩内容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,117评论 1 45
  • HTML标签解释大全 一、HTML标记 标签:!DOCTYPE 说明:指定了 HTML 文档遵循的文档类型定义(D...
    米塔塔阅读 3,177评论 1 41
  • 一:认识jquery jquery是javascript的类库,具有轻量级,完善的文档,丰富的插件支持,完善的Aj...
    xuguibin阅读 1,640评论 1 7
  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,371评论 0 15
  • width: 65%;border: 1px solid #ddd;outline: 1300px solid #...
    邵胜奥阅读 4,379评论 0 1