php爬蟲全國地址信息

首先我得道歉,因爲我做了一回標題黨。但我想也並沒讓你失望吧,雖然沒有現在成的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);

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