做了一个爬取api的类.可以获取2017全国行政区域.
git: https://github.com/buffge/loa...
效果图:
差不多有40000多行 只要90秒就可以爬完
首先这个api在阿里云市场 是免费的.每个人都可以用.
地址在这里
要先注册阿里云,然后购买他这个,一次只能买1000.你可以买三四次,应该就可以全部下载完毕了.
爬虫思路:
1.初始化curl_multi 并将curl 句柄添加进去.
2.执行所有的curl句柄
3.处理所有的curl返回的结果
那个api是有2种接口,第一是通过名称获取城市的信息,第二是通过父城市id获取所有子城市
因为父城市id我们不知道,所以第一步必须是通过名称获取城市的信息
定义数组 全国所有省级行政区(共34个)
爬虫运行顺序
第一步是获取这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上也有.希望对大家有帮助.