首先我得道歉,因爲我做了一回標題黨。但我想也並沒讓你失望吧,雖然沒有現在成的sql,但親寫的php腳本同樣可以生成燙手的sql!
本博客參考中國統計局2017最新數據進行編寫的,有必要的話你可以改成對應最新版本即可。
準備:一張表(id,pid,url,level,name)
注意:本腳本默認獲取三級,最多可獲取到4級,自行調整!由於平臺限制,可能得刷新請求大概5次左右才能完全下載完省市區(直接返回空數組,即下載完成)
技術點:運用了遞歸和正則匹配,特別的名稱進行了處理(如:省直轄縣級行政區劃、市轄區、縣),至於數據庫看着替換上即可!
以下代碼附上:
function curl_get($url){
//初始化
$curl = curl_init();
//設置抓取的url
curl_setopt($curl, CURLOPT_URL, $url);
//設置頭文件的信息作爲數據流輸出
curl_setopt($curl, CURLOPT_HEADER, 1);
//設置獲取的信息以文件流的形式返回,而不是直接輸出。
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//執行命令
$data = curl_exec($curl);
if (curl_errno($curl)) {
$curl_error = curl_error($curl);
throw new Exception ($curl_error, 0);
} else {
$httpStatusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if (200 !== $httpStatusCode) {
throw new Exception ($data, $httpStatusCode);
}
}
//關閉URL請求
curl_close($curl);
//顯示獲得的數據
return $data;
}
function getAddress($url, $pid=0, $level=1, $p_name , $data=array()){
try{
// 拼接請求鏈接
$html = curl_get($url);
// 以下爲節點要點字眼,選擇自己要的地區等級字眼則可
// provincetr|citytr|countytr|towntr|villagetr
preg_match_all('/(provincetr|citytr|countytr).*<td(.*)td/i',$html,$res1);
if($res1){
$tr = $res1[0][0];
preg_match_all('/<td.*?>.*?href=[\'|"](.*?)[\'|"]>(.*?)(<\/br>)?<\/a><\/td/',$tr,$res2);
foreach ($res2[2] as $key => $value) {
$curll_val = $res2[1][$key];
$curll_url = substr($url,0, strrpos($url, '/') + 1) . $curll_val;
$select_sql = "select * from test_region where url='{$curll_val}'";
$exist = $GLOBALS['db_separate']->getRow($select_sql);
// 如果已經存在該父級節點,則跳過
if ($exist){
continue;
}
$value = trim(strip_tags($value));
if (!is_numeric($value) && !empty($value)) {
// 轉換成數據庫的編碼
$encode = mb_detect_encoding($value, array('ASCII','UTF-8','GB2312','GBK','BIG5'));
// EUC-CN
$value = iconv( $encode, 'utf-8',$value);
// 湖北仙桃 河南濟源 海南五指山 文昌等
if($value == '省直轄縣級行政區劃'){ // 向上推一級
$data += getAddress($curll_url, $pid, $level, $value); // 可選擇性去掉
} else {
// 每個頂級節點做一次事務,從而保障就算出錯也不會出現漏數據
$level == 1 && $GLOBALS['db_separate']->beginTransaction();
// 如果是市轄區或只有縣,則用低級名稱
//縣 重慶城口 豐都等
if($value == '市轄區' || $value == '縣'){ // 替換成上級的名稱
$value = $p_name;
}
// 初始保證變量沒被污染
$sub_pid = '';
if($value == '重慶市'){
$sql = "select id from test_region where level='{$level}' and region_name='{$value}'";
$sub_pid = $GLOBALS['db_separate']->getOne($sql);
}
if(empty($sub_pid)){
$row = array('region_name'=>trim(strip_tags($value)), 'url'=>$curll_val, 'level'=>$level, 'pid'=>$pid);
// 向數據庫插入一條數據
$GLOBALS['db_separate']->insert('test_region', $row);
// 把當前的id作爲自己子級的父ID
$sub_pid = $GLOBALS['db_separate']->lastInsertId();
}
// 遞歸查找自己的子級
$row['child'] = getAddress($curll_url, $sub_pid, $level +1, $value);
$data[] = $row;
// 如果該頂節點回調完纔會提交自己的事務
$level == 1 && $GLOBALS['db_separate']->commit();
}
}
// file_put_contents('res.txt', var_export($data,true));
}
}
}catch (Exception $e){
// 如果幫忙錯,則回滾事務再刷新當前頁,以此來繼續操作插入完成未處理的數據
echo '出錯了哦~' . $e->getMessage();
$reload_srcipt = "<script>location.reload()</script>";
try{
$GLOBALS['db_separate']->rollBack(); // 必須先回滾再刷新
echo $reload_srcipt;
}catch (Exception $e_sub){
echo $reload_srcipt;
}
}
// 返回本次處理過的結果集
return $data;
}
set_time_limit(0);
$url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2017/index.html';
$data = getAddress($url);
var_dump($data);