Java爬統計局12位區劃代碼

有朋友須要獲取全國2013年統計用區劃代碼和城鄉劃分代碼,因而寫了個爬蟲抓數據。html

仔細分析頁面後,發現其特色是根據最終的區域代碼,能夠反推上級省、市等代碼,故只保存最後一步數據。java

第一次接觸爬蟲,邊作邊研究。只寫了個單線程,下載了41分鐘。node

後來研究多線程爬蟲,又寫了個多線程爬知乎話題+回答的程序。因爲暫時沒法正確保存頁面上各類程序語言的代碼,半成品的程序就不放出來了。多線程

下面是單線程下載統計局全國區劃代碼的源碼,要改爲多線程也不難。不過已經下載到告終果,就懶得再作無用功了。測試

package king.statitics;

import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class GetNoAndAddress {
    // 因爲每一個網頁層數未知,用List來保存每一層網頁。
    // Map的第一個String爲網址,第二個String爲 代碼和地址,用SEPARATOR隔開
    private static List<Map<String, String>> tempList = new ArrayList<Map<String, String>>();
    private static final String SEPERATOR = "|";
    private static Map<String, String> result = new TreeMap<String, String>();
   
    public static void main(String[] args) throws Exception {
        // 網址: 2013年統計用區劃代碼和城鄉劃分代碼(截止2013年8月31日) 
        String urlStr = "http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/index.html";
        String filePath = "E:/result.txt";
        
        long start = System.currentTimeMillis();
        // 執行
        execute(urlStr, filePath);
        long end = (System.currentTimeMillis() - start) / (1000 * 60);
        System.out.println("總運行時間" + end + "分鐘");
    }
    
    /**
     * 程序入口
     * @param urlStr
     */
    public static void execute(String urlStr, String filePath) throws Exception {
        int index = -1; // 照顧下面的循環,從-1開始。
        do{
            Map<String, String> store = new TreeMap<String, String>();
            if (tempList.isEmpty()){ //第一次抓取,即最頂層頁面
                analysisHtml(urlStr, "", store);
            } else {
                for(Map.Entry<String, String> entry : tempList.get(index).entrySet()){
                    analysisHtml(entry.getKey(), getAddress(entry.getValue()), store);
                }
            }
            if (!store.isEmpty()) tempList.add(store);
        }while (++index < tempList.size());
        
        System.out.println("下載完成,開始寫入文件:");
//        print();
        
        // 把全部結果存入文件中
        PrintStream output = new PrintStream(filePath);
        for (Map.Entry<String, String> entry : result.entrySet()){
            output.println(entry.getKey() + " " + entry.getValue());
        }
        output.close();
        System.out.println("OK!");
    }
    
    /**
     * 獲取
     * @param urlStr 網址
     * @throws IOException
     */
    public static void analysisHtml(String urlStr, String parentPath
            , Map<String, String> store) throws IOException{
        // 獲取html
        Document doc = Jsoup.connect(urlStr).get();        
        // 經觀察,符合條件的數據皆以此開頭
        Elements links = doc.select("tr[class$=tr]");
        // 遍歷每一個 <a 標籤
        for (Element link : links) {
            // 用if 過濾結尾的 
            // <A class=STYLE3       href="http://www.miibeian.gov.cn/"       target=_blank>京ICP備05034670號</A>
            getStatistics(store, link, parentPath);         
        }
    }
    
    /**
     * 保存結果
     * @param store 每一層次頁面的結果
     * @param link 連接
     */
    public static void getStatistics(Map<String, String> store
            , Element link, String parentPath){
        String url = ""; // 絕對網址 
        String code = ""; // 相對網址
        String address = ""; // 地址
        if ("".equals(parentPath)){ // 父地址是空值,即最頂層頁面,提取方法與其餘不一樣
            // 包含多個td標籤, 每一個一組數據
            Elements td = link.getElementsByTag("td");
            for (Element e : td){
                url = e.getElementsByAttribute("href").attr("abs:href"); 
                code = e.getElementsByAttribute("href").attr("href");  
                if (code.toLowerCase().endsWith(".html")){
                    code = code.substring(0, code.indexOf(".")); // 提取代碼 
                }
                address = e.text(); 
                store.put(url, code + SEPERATOR + address);
            }
        } else{
            url = link.getElementsByAttribute("href").attr("abs:href");            
            // link包含多個td標籤,仍可進一步提取
            Elements td = link.getElementsByTag("td");
            // 它們都屬於同一條數據
            for (Element e : td){
                if (!e.text().matches("\\d{3}")){
                    if ("".equals(code)){
                        code = e.text();
                    }else{
                        address = parentPath + e.text();
                    }
                }
            }
            // 存儲 結果
            if (url == null || "".equals(url)){ //說明到了最底層
                result.put(code, address);
            } else {
                store.put(url, code + SEPERATOR + address);
            }
            // 控制檯輸出每一步數據,看看程序有沒有在執行
            System.out.println(code + "---->" + address);
        }
    }
    

    
    /**
     * 拆分字符串,提取出地址值
     * @param group eg:11|北京市
     */
    private static String getAddress(String group){
        return group.substring(group.indexOf(SEPERATOR) + 1);
    }
    
    // 用於測試
    private static void print(){
        for(Map.Entry<String, String> entry : tempList.get(0).entrySet()){
            System.out.println(entry.getKey() + " " + entry.getValue());
        }
    }
}

最終獲取的文件部份內容:

110101001001 北京市市轄區東城區東華門街道辦事處多福巷社區居委會
110101001002 北京市市轄區東城區東華門街道辦事處銀閘社區居委會
110101001005 北京市市轄區東城區東華門街道辦事處東廠社區居委會
110101001006 北京市市轄區東城區東華門街道辦事處智德社區居委會
110101001007 北京市市轄區東城區東華門街道辦事處南池子社區居委會
110101001008 北京市市轄區東城區東華門街道辦事處黃圖崗社區居委會
110101001009 北京市市轄區東城區東華門街道辦事處燈市口社區居委會
110101001010 北京市市轄區東城區東華門街道辦事處正義路社區居委會
110101001011 北京市市轄區東城區東華門街道辦事處甘雨社區居委會
110101001013 北京市市轄區東城區東華門街道辦事處臺基廠社區居委會
110101001014 北京市市轄區東城區東華門街道辦事處韶九社區居委會
110101001015 北京市市轄區東城區東華門街道辦事處王府井社區居委會
110101002001 北京市市轄區東城區景山街道辦事處隆福寺社區居委會


版權聲明:本文爲博主原創文章,未經博主容許不得轉載。url

相關文章
相關標籤/搜索