實戰|省市區三級聯動數據爬取

image

前言

??最近收到客服反應,系統的省市區數據好像不準,并且缺了一些地區。經過詢問同事得知,數據庫內的數據是從老項目拷貝過來的,有些年頭了。難怪會缺一些數據。正好最近在對接網商銀行,發現網商提供了省市區的數據的接口。這就很舒服了哇,抄起鍵盤就是干,很快的就把同步程序寫好了。

??然后在同步的過程中,發現網商提供的數據和數據庫有些對不上。于是默默的打開淘寶京東添加收貨地址,看看到底是誰錯了。對比到后面發現都有些差異。這就很蛋疼了。看來這個時候誰都不能相信了,只能信國家了。于是我打開了中華人民共和國民政部網站來比對異常的數據。

??對比的過程中,石錘網商數據不準。值得的是表揚淘寶京東已經同步了最新的數據了。但是呢,我并沒有找到它們的數據接口。為了修正系統的數據,只能自己爬取了。

鎖定爬取目標

image
image

爬取地址如下:

https://preview.www.mca.gov.cn/article/sj/xzqh/2020/2020/202101041104.html

??爬取原理很簡單,就是解析HTML元素,然后獲取到相應的屬性值保存下來就好了。由于使用Java進行開發,所以選用Jsoup來完成這個工作。

<!-- HTML解析器 -->
<dependency>
  <groupId>org.jsoup</groupId>
  <artifactId>jsoup</artifactId>
  <version>1.13.1</version>
</dependency>

網頁數據分析

??由于需要解析HTML才能取到數據,所以需要知道數據存儲在什么元素上。我們可以打開chrom的控制臺,然后選中對應的數據,即可查看存儲數據的元素。

image

??通過分析,發現每一行數據都是存儲在一個<tr>標簽下。我們需要的 區域碼區域名稱存儲在第一和第二個<td>內 。與此同時還要很多空白<td>標簽,在編寫代碼是需要將其過濾掉。

定義基礎代碼

??先定義好我們的爬取目標,以及Area實體類。

public class AreaSpider{

    // 爬取目標
    private static final String TARGET = "http://preview.www.mca.gov.cn/article/sj/xzqh/2020/2020/202101041104.html";

    @Data
    @AllArgsConstructor
    private static class Area {

        // 區域碼
        private String code;

        // 區域名稱
        private String name;

        // 父級
        private String parent;

    }
}

爬蟲代碼編寫

public static void main(String[] args) throws IOException{
  // 請求網頁
  Jsoup.connect(TARGET).timeout(10000).get()
    // 篩選出 tr 標簽
    .select("tr")
    // 篩選出 tr 下的 td 標簽
    .forEach(tr -> tr.select("td")
    // 過濾 值為空的 td 標簽
    .stream().filter(td -> StringUtils.isNotBlank(td.text()))
    // 輸出結果
    .forEach(td -> System.out.println(td.text())));
}

解析結果

image

代碼優化

??通過上面的代碼,我們已經爬取到了頁面上的數據。但是并沒有達到我們的預期,所以進一步處理將其轉換為Area實體。

public static void main(String[] args) throws IOException{
  // 請求網頁
  List<Area> areaList = Jsoup.connect(TARGET).timeout(10000).get()
    // 篩選出 tr 標簽
    .select("tr")
    // 篩選出 tr 下的 td 標簽
    .stream().map(tr -> tr.select("td")
    // 過濾 值為空的 td 標簽,并轉換為 td 列表
    .stream().filter(td -> StringUtils.isNotBlank(td.text())).collect(Collectors.toList()))
    // 前面提到,區域碼和區域名稱分別存儲在 第一和第二個td,所以過濾掉不符合規范的數據行。
    .filter(e -> e.size() == 2)
    // 轉換為 area 對象
    .map(e -> new Area(e.get(0).text(), e.get(1).text(), "0")).collect(Collectors.toList());
  
    // 遍歷數據
  areaList.forEach(area -> System.out.println(JSONUtil.toJsonStr(area)));
}

解析結果

image

??至此,離我們想要的數據還差了父級區域碼 ,我們可以通過區域碼計算出來。以河北省為例:河北省:130000石家莊市:130100長安區:130102可以發現規律:0000 結尾是省份,00是市。所以就有了如下代碼:

private static String calcParent(String areaCode){
    // 省 - 針對第一行特殊處理
    if(areaCode.contains("0000") || areaCode.equals("行政區劃代碼")){
        return "0";
    // 市
    }else if (areaCode.contains("00")) {
        return String.valueOf(Integer.parseInt(areaCode) / 10000 * 10000);
    // 區
    }else {
        return String.valueOf(Integer.parseInt(areaCode) / 100 * 100);
    }
}

最終代碼

public class AreaSpider{

    // 爬取目標
    private static final String TARGET = "http://preview.www.mca.gov.cn/article/sj/xzqh/2020/2020/202101041104.html";

    @Data
    @AllArgsConstructor
    private static class Area{

        // 區域碼
        private String code;

        // 區域名稱
        private String name;

        // 父級
        private String parent;

    }

    public static void main(String[] args) throws IOException{
        // 請求網頁
        List<Area> areaList = Jsoup.connect(TARGET).timeout(10000).get()
                // 篩選出 tr 標簽
                .select("tr")
                // 篩選出 tr 下的 td 標簽
                .stream().map(tr -> tr.select("td")
                // 過濾 值為空的 td 標簽,并轉換為 td 列表
                .stream().filter(td -> StringUtils.isNotBlank(td.text())).collect(Collectors.toList()))
                // 前面提到,區域碼和區域名稱分別存儲在 第一和第二個td,所以過濾掉不符合規范的數據行。
                .filter(e -> e.size() == 2)
                // 轉換為 area 對象
                .map(e -> new Area(e.get(0).text(), e.get(1).text(), calcParent(e.get(0).text()))).collect(Collectors.toList());

        // 去除 第一行 "行政區劃代碼|單位名稱"
        areaList.remove(0);

        areaList.forEach(area -> System.out.println(JSONUtil.toJsonStr(area)));
    }

    private static String calcParent(String areaCode){
        // 省 - 針對第一行特殊處理
        if(areaCode.contains("0000") || areaCode.equals("行政區劃代碼")){
            return "0";
        // 市
        }else if (areaCode.contains("00")) {
            return String.valueOf(Integer.parseInt(areaCode) / 10000 * 10000);
        // 區
        }else {
            return String.valueOf(Integer.parseInt(areaCode) / 100 * 100);
        }
    }
}

數據修正

image

??由于我們需要的是省市區三級數據聯動,但是了直轄市只有兩級,所以我們人工的給它加上一級。以北京市為例:變成了 北京 -> 北京市- >東城區,對于其他的直轄市也是同樣的處理邏輯。

??修正好的數據奉上,有需要的小伙伴可以自取哦。

對于直轄市也可以做兩級的,這個主要看產品的需求吧

總結

??總體來講,這個爬蟲比較簡單,只有簡單的幾行代碼。畢竟網站也沒啥反扒的機制,所以很輕松的就拿到了數據。

結尾

??嘿嘿話說,你都爬過哪些網站呢?

??如果覺得對你有幫助,可以多多評論,多多點贊哦,也可以到我的主頁看看,說不定有你喜歡的文章,也可以隨手點個關注哦,謝謝。

??我是不一樣的科技宅,每天進步一點點,體驗不一樣的生活。我們下期見!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容