實(shí)戰(zhàn)|省市區(qū)三級(jí)聯(lián)動(dòng)數(shù)據(jù)爬取

image

前言

??最近收到客服反應(yīng)军援,系統(tǒng)的省市區(qū)數(shù)據(jù)好像不準(zhǔn),并且缺了一些地區(qū)称勋。經(jīng)過詢問同事得知胸哥,數(shù)據(jù)庫內(nèi)的數(shù)據(jù)是從老項(xiàng)目拷貝過來的,有些年頭了赡鲜。難怪會(huì)缺一些數(shù)據(jù)空厌。正好最近在對(duì)接網(wǎng)商銀行,發(fā)現(xiàn)網(wǎng)商提供了省市區(qū)的數(shù)據(jù)的接口银酬。這就很舒服了哇嘲更,抄起鍵盤就是干,很快的就把同步程序?qū)懞昧恕?/p>

??然后在同步的過程中揩瞪,發(fā)現(xiàn)網(wǎng)商提供的數(shù)據(jù)和數(shù)據(jù)庫有些對(duì)不上赋朦。于是默默的打開淘寶京東添加收貨地址,看看到底是誰錯(cuò)了李破。對(duì)比到后面發(fā)現(xiàn)都有些差異宠哄。這就很蛋疼了∴凸ィ看來這個(gè)時(shí)候誰都不能相信了毛嫉,只能信國家了。于是我打開了中華人民共和國民政部網(wǎng)站來比對(duì)異常的數(shù)據(jù)妇菱。

??對(duì)比的過程中狱庇,石錘網(wǎng)商數(shù)據(jù)不準(zhǔn)。值得的是表揚(yáng)淘寶京東已經(jīng)同步了最新的數(shù)據(jù)了恶耽。但是呢,我并沒有找到它們的數(shù)據(jù)接口颜启。為了修正系統(tǒng)的數(shù)據(jù)偷俭,只能自己爬取了。

鎖定爬取目標(biāo)

image
image

爬取地址如下:

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

??爬取原理很簡(jiǎn)單缰盏,就是解析HTML元素涌萤,然后獲取到相應(yīng)的屬性值保存下來就好了淹遵。由于使用Java進(jìn)行開發(fā),所以選用Jsoup來完成這個(gè)工作负溪。

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

網(wǎng)頁數(shù)據(jù)分析

??由于需要解析HTML才能取到數(shù)據(jù)透揣,所以需要知道數(shù)據(jù)存儲(chǔ)在什么元素上。我們可以打開chrom的控制臺(tái)川抡,然后選中對(duì)應(yīng)的數(shù)據(jù)辐真,即可查看存儲(chǔ)數(shù)據(jù)的元素。

image

??通過分析崖堤,發(fā)現(xiàn)每一行數(shù)據(jù)都是存儲(chǔ)在一個(gè)<tr>標(biāo)簽下侍咱。我們需要的 區(qū)域碼區(qū)域名稱存儲(chǔ)在第一和第二個(gè)<td>內(nèi) 。與此同時(shí)還要很多空白<td>標(biāo)簽密幔,在編寫代碼是需要將其過濾掉楔脯。

定義基礎(chǔ)代碼

??先定義好我們的爬取目標(biāo),以及Area實(shí)體類胯甩。

public class AreaSpider{

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

    @Data
    @AllArgsConstructor
    private static class Area {

        // 區(qū)域碼
        private String code;

        // 區(qū)域名稱
        private String name;

        // 父級(jí)
        private String parent;

    }
}

爬蟲代碼編寫

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

解析結(jié)果

image

代碼優(yōu)化

??通過上面的代碼昧廷,我們已經(jīng)爬取到了頁面上的數(shù)據(jù)。但是并沒有達(dá)到我們的預(yù)期偎箫,所以進(jìn)一步處理將其轉(zhuǎn)換為Area實(shí)體木柬。

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

解析結(jié)果

image

??至此娇唯,離我們想要的數(shù)據(jù)還差了父級(jí)區(qū)域碼 齐遵,我們可以通過區(qū)域碼計(jì)算出來。以河北省為例:河北省:130000塔插、石家莊市:130100梗摇、長(zhǎng)安區(qū):130102可以發(fā)現(xiàn)規(guī)律:0000 結(jié)尾是省份,00是市想许。所以就有了如下代碼:

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

最終代碼

public class AreaSpider{

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

    @Data
    @AllArgsConstructor
    private static class Area{

        // 區(qū)域碼
        private String code;

        // 區(qū)域名稱
        private String name;

        // 父級(jí)
        private String parent;

    }

    public static void main(String[] args) throws IOException{
        // 請(qǐng)求網(wǎng)頁
        List<Area> areaList = Jsoup.connect(TARGET).timeout(10000).get()
                // 篩選出 tr 標(biāo)簽
                .select("tr")
                // 篩選出 tr 下的 td 標(biāo)簽
                .stream().map(tr -> tr.select("td")
                // 過濾 值為空的 td 標(biāo)簽伶授,并轉(zhuǎn)換為 td 列表
                .stream().filter(td -> StringUtils.isNotBlank(td.text())).collect(Collectors.toList()))
                // 前面提到,區(qū)域碼和區(qū)域名稱分別存儲(chǔ)在 第一和第二個(gè)td流纹,所以過濾掉不符合規(guī)范的數(shù)據(jù)行糜烹。
                .filter(e -> e.size() == 2)
                // 轉(zhuǎn)換為 area 對(duì)象
                .map(e -> new Area(e.get(0).text(), e.get(1).text(), calcParent(e.get(0).text()))).collect(Collectors.toList());

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

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

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

數(shù)據(jù)修正

image

??由于我們需要的是省市區(qū)三級(jí)數(shù)據(jù)聯(lián)動(dòng),但是了直轄市只有兩級(jí)漱凝,所以我們?nèi)斯さ慕o它加上一級(jí)疮蹦。以北京市為例:變成了 北京 -> 北京市- >東城區(qū),對(duì)于其他的直轄市也是同樣的處理邏輯茸炒。

??修正好的數(shù)據(jù)奉上愕乎,有需要的小伙伴可以自取哦阵苇。

對(duì)于直轄市也可以做兩級(jí)的,這個(gè)主要看產(chǎn)品的需求吧

總結(jié)

??總體來講感论,這個(gè)爬蟲比較簡(jiǎn)單绅项,只有簡(jiǎn)單的幾行代碼。畢竟網(wǎng)站也沒啥反扒的機(jī)制比肄,所以很輕松的就拿到了數(shù)據(jù)快耿。

結(jié)尾

??嘿嘿話說,你都爬過哪些網(wǎng)站呢薪前?

??如果覺得對(duì)你有幫助润努,可以多多評(píng)論,多多點(diǎn)贊哦示括,也可以到我的主頁看看铺浇,說不定有你喜歡的文章,也可以隨手點(diǎn)個(gè)關(guān)注哦垛膝,謝謝鳍侣。

??我是不一樣的科技宅,每天進(jìn)步一點(diǎn)點(diǎn)吼拥,體驗(yàn)不一樣的生活倚聚。我們下期見!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凿可,一起剝皮案震驚了整個(gè)濱河市惑折,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枯跑,老刑警劉巖惨驶,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異敛助,居然都是意外死亡粗卜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門纳击,熙熙樓的掌柜王于貴愁眉苦臉地迎上來续扔,“玉大人,你說我怎么就攤上這事焕数∩疵粒” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵堡赔,是天一觀的道長(zhǎng)砌些。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么存璃? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮雕拼,結(jié)果婚禮上纵东,老公的妹妹穿的比我還像新娘。我一直安慰自己啥寇,他們只是感情好偎球,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辑甜,像睡著了一般衰絮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上磷醋,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天猫牡,我揣著相機(jī)與錄音,去河邊找鬼邓线。 笑死淌友,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的骇陈。 我是一名探鬼主播震庭,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼你雌!你這毒婦竟也來了器联?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤婿崭,失蹤者是張志新(化名)和其女友劉穎拨拓,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逛球,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡千元,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颤绕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幸海。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖奥务,靈堂內(nèi)的尸體忽然破棺而出物独,到底是詐尸還是另有隱情,我是刑警寧澤氯葬,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布挡篓,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏官研。R本人自食惡果不足惜秽澳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望戏羽。 院中可真熱鬧担神,春花似錦、人聲如沸始花。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酷宵。三九已至亥贸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浇垦,已是汗流浹背炕置。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留溜族,地道東北人讹俊。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像煌抒,于是被迫代替她去往敵國和親仍劈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容