4

做了一个爬取api的类.可以获取2017全国行政区域.

git: https://github.com/buffge/loa...

效果图:

clipboard.png

差不多有40000多行 只要90秒就可以爬完

首先这个api在阿里云市场 是免费的.每个人都可以用.
地址在这里

要先注册阿里云,然后购买他这个,一次只能买1000.你可以买三四次,应该就可以全部下载完毕了.

爬虫思路:

1.初始化curl_multi 并将curl 句柄添加进去.
2.执行所有的curl句柄
3.处理所有的curl返回的结果  

那个api是有2种接口,第一是通过名称获取城市的信息,第二是通过父城市id获取所有子城市
因为父城市id我们不知道,所以第一步必须是通过名称获取城市的信息
定义数组 全国所有省级行政区(共34个)

clipboard.png

爬虫运行顺序

第一步是获取这34个省(level=1)的信息.
第二步就是循环34次 每次循环查询当前城市的所有子城市(level=2)
第三步就是循环(level=2)城市的个数次,然后查询level=3城市的信息
第四步就是循环(level=3)城市的个数,查询level=4城市的信.最大就到level4 也就是乡镇一级
有的城市连level3都没有,没有的情况下就会continue

代码块分析

    public
            function start() {
//启动一个mcurl
        $mh = curl_multi_init();
        $orinigal_chs = [];
//初始化mcurl 并添加一定数量(最高为全部或者最大并发)curl进去
        $this->curlMultiInit($mh, $orinigal_chs);
//执行所有的curl句柄并返回所有curl句柄数组
        $chs = $this->curlMultiExec($mh, $orinigal_chs);
//获取所有的curl返回的结果
        $res = $this->getCurlResult($chs);
//如果为正常结果
        if (is_array($res)) {
//对每一个curl结果进行处理
            $this->dataHandle($res);
        }
        else {
//输出错误信息
            echo "当前列表中所有城市都没有子城市.\n";
        }
    }

这是启动方法所有的操作都在里面.这里使用的是多线程爬虫.如果不会的可以百度.
核心的代码就是最后一个对curl结果进行处理的方法;
主要做的内容是插入上一次获取到的城市信息到数据库
接着对每一个获取到的城市进行子城市 查询 也就是上面所说的循环
由于我是个菜鸟,我有好久没用过mysql了,不知道为什么这里的affected_rows为什么总是等于-1.
知道的 能告诉我一下就好了.
如下:

 protected
            function dataHandle(array $res) {
        $mysqli = new \mysqli($this->host, $this->name, $this->pwd, $this->dbname);
        foreach ($res as $k => $v) {
            $mixedInfo = json_decode($v[0]);
            $cityInfo = $mixedInfo->showapi_res_body->data;
            $citysLength = count($cityInfo);
            $sql = "INSERT INTO `allcitys` ( `provinceId`, `simpleName`, `lon`, `areaCode`, `cityId`, `remark`, `prePinYin`, `cid`, `pinYin`, `parentId`, `level`, `areaName`, `simplePy`, `zipCode`, `countyId`, `lat`, `wholeName`) VALUES ";
            $sql_values = '';
            for ($i = 0; $i < $citysLength; $i++) {
                $sql_values .= "('{$cityInfo[$i]->provinceId}', '{$cityInfo[$i]->simpleName}', '{$cityInfo[$i]->lon}', '{$cityInfo[$i]->areaCode}', '{$cityInfo[$i]->cityId}', '{$cityInfo[$i]->remark}', '{$cityInfo[$i]->prePinYin}', '{$cityInfo[$i]->id}',\"{$cityInfo[$i]->pinYin}\", '{$cityInfo[$i]->parentId}', '{$cityInfo[$i]->level}', '{$cityInfo[$i]->areaName}', '{$cityInfo[$i]->simplePy}', '{$cityInfo[$i]->zipCode}', '{$cityInfo[$i]->countyId}', '{$cityInfo[$i]->lat}', '{$cityInfo[$i]->wholeName}'),";
            }
            $sql_values = substr_replace($sql_values, '', -1);
            $sql .= $sql_values;
            $mysqli->query($sql);
//不知道为什么这里的affect_rows 总是-1
//if ($mysqli->affected_rows == $citysLength) {
            if (1) {
                echo "{$citysLength}条数据添加成功\n";
                if ($this->level < 4) {
                    $temp_level = $this->level + 1;
                    for ($j = 0; $j < $citysLength; $j++) {
                        $tempearchCitysList[] = $cityInfo[$j]->id;
                    }
                    $config = [
                        'appcode'         => $this->appcode,
                        'level'           => $temp_level,
                        'amount'          => $citysLength,
                        'getInfo'         => self::SUB_LIST,
                        'searchCitysList' => $tempearchCitysList,
                        'host'            => $this->host,
                        'name'            => $this->name,
                        'pwd'             => $this->pwd,
                        'dbname'          => $this->dbname
                    ];
                    $subLoad = new self($config);
                    $tempearchCitysList = [];
                    $subLoad->start();
                }
            }
            else {
                echo $this->searchCitysList[$k] . "数据插入失败!\n";
            }
        }
        $mysqli->close();

    }

比较难理解的代码块就是curl_multi那个方法

我半年前做爬虫的时候 为了搞清楚这个百度谷歌都查 就是没有找到满意的答案.
后来干脆就这样随便写了.效果还可以.
其中 这一句

$mrc = curl_multi_exec($mh, $active);

表示执行$mh中所有的curl句柄.$active 表示当前还剩多少个没有执行完毕.

 $info = curl_multi_info_read($mh, $msgq);
 

这里这句就是读取$mh 已经执行完毕的内容如果$info为真,表示这个curl句柄已经完成了,
然后我们从这个info中读取handle 也就是当前curl句柄.
如果$info 为假那么就延时1000微秒,因为执行太快 对cpu压力很大.

因为我英语不好官方文档看不懂,也没有学过底层,这里的很多东西都是我根据效果猜的.里面如果有讲错来的地方请大家告诉我一下.

不仅仅是这个api ,其他的api 也可以通过这种思路去爬取.图片站 小说站都可以这样爬取.
我半年前做过一个爬取图片站的类.git上也有.希望对大家有帮助.


buff
382 声望16 粉丝

i++;