整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

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

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

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

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

          鎖定爬取目標

          爬取地址如下:

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

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

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

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

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

          ??通過分析,發(fā)現(xiàn)每一行數(shù)據(jù)都是存儲在一個<tr>標簽下。我們需要的 區(qū)域碼區(qū)域名稱存儲在第一和第二個<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 {
          
                  // 區(qū)域碼
                  private String code;
          
                  // 區(qū)域名稱
                  private String name;
          
                  // 父級
                  private String parent;
          
              }
          }
          

          爬蟲代碼編寫

          public static void main(String[] args) throws IOException{
            // 請求網(wǎng)頁
            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())));
          }
          

          解析結果

          代碼優(yōu)化

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

          public static void main(String[] args) throws IOException{
            // 請求網(wǎng)頁
            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()))
              // 前面提到,區(qū)域碼和區(qū)域名稱分別存儲在 第一和第二個td,所以過濾掉不符合規(guī)范的數(shù)據(jù)行。
              .filter(e -> e.size() == 2)
              // 轉換為 area 對象
              .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)));
          }
          

          解析結果

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

          private static String calcParent(String areaCode){
              // 省 - 針對第一行特殊處理
              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{
          
              // 爬取目標
              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;
          
                  // 父級
                  private String parent;
          
              }
          
              public static void main(String[] args) throws IOException{
                  // 請求網(wǎng)頁
                  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()))
                          // 前面提到,區(qū)域碼和區(qū)域名稱分別存儲在 第一和第二個td,所以過濾掉不符合規(guī)范的數(shù)據(jù)行。
                          .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());
          
                  // 去除 第一行 "行政區(qū)劃代碼|單位名稱"
                  areaList.remove(0);
          
                  areaList.forEach(area -> System.out.println(JSONUtil.toJsonStr(area)));
              }
          
              private static String calcParent(String areaCode){
                  // 省 - 針對第一行特殊處理
                  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ù)修正

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

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

          • JSON-2020-11縣以上行政區(qū)劃代碼
          • SQL-2020-11縣以上行政區(qū)劃代碼

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

          總結

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

          結尾

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

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

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

          用PHP+MySql+Ajax+jQuery實現(xiàn)省市區(qū)三級聯(lián)動功能

          要求:寫一個省市區(qū)(或者年月日)的三級聯(lián)動,實現(xiàn)地區(qū)或時間的下拉選擇。

          實現(xiàn)技術:php ajax

          實現(xiàn):省級下拉變化時市下拉區(qū)下拉跟著變化,市級下拉變化時區(qū)下拉跟著變化。

          使用chinastates表查詢

          Ajax加載數(shù)據(jù)

          1.這是chinastates表

          2.做一個簡單php:Ajax_eg.php

          <!DOCTYPE html>

          <html>

          <head>

          <meta charset="UTF-8">

          <title></title>

          <script src="bootstrap/js/jquery-1.11.2.min.js"></script>

          </head>

          <style>

          .sanji{

          margin-left: 550px;

          margin-top: 150px;

          }

          </style>

          <body>

          <div class="sanji"> </div>

          </body>

          </html>

          3.根據(jù)前一個頁面做jquery:Ajax_ssq.js

          // JavaScript Document

          //當頁面內容都加載完才執(zhí)行

          $(document).ready(function(e) {

          //加載三個下拉列表

          $("#sanji").html("<select id='sheng'></select><select id='shi'></select><select id='qu'></select>");

          //加載顯示數(shù)據(jù)

          //1.加載省份

          LoadSheng();

          //2.加載市

          LoadShi();

          //3.加載區(qū)

          LoadQu();

          //當省份選中變化,重新加載市和區(qū)

          $("#sheng").change(function(){ //當元素的值發(fā)生改變時,會發(fā)生 change 事件,該事件僅適用于文本域(text field),以及 textarea 和 select 元素。

          //加載市

          LoadShi();

          //加載區(qū)

          LoadQu();

          })

          //當市選中變化,重新加載區(qū)

          $("#shi").change(function(){

          //加載區(qū)

          LoadQu();

          })

          });

          //加載省份信息

          function LoadSheng()

          {

          //取父級代號

          var pcode ="0001";

          //根據(jù)父級代號查數(shù)據(jù)

          $.ajax({

          //取消異步,也就是必須完成上面才能走下面

          async:false,

          url:"load.php",

          data:{pcode:pcode},

          type:"POST",

          dataType:"JSON",

          success: function(data){

          var str="";

          //遍歷數(shù)組,把它放入sj

          for(var k in data){

          str=str+"<option value='"+data[k].[0]+"'>"+data[k].[1]+"</option>";

          }

          $("#sheng").html(str);

          }

          });

          }

          //加載市信息

          function LoadShi()

          {

          //取父級代號

          var pcode =$("#sheng").val();

          //根據(jù)父級代號查數(shù)據(jù)

          $.ajax({

          //取消異步,也就是必須完成上面才能走下面

          async:false,

          url:"load.php",

          data:{pcode:pcode},

          type:"POST",

          dataType:"JSON",

          success: function(data){

          var str="";

          //遍歷數(shù)組,把它放入sj

          for(var k in data){

          str=str+"<option value='"+data[k].[0]+"'>"+data[k].[0]+"</option>";

          }

          $("#shi").html(str);

          }

          });

          }

          //加載區(qū)信息

          function LoadQu()

          {

          //取父級代號

          var pcode =$("#shi").val();

          //根據(jù)父級代號查數(shù)據(jù)

          $.ajax({

          //不需要取消異步

          url:"load.php",

          data:{pcode:pcode},

          type:"POST",

          dataType:"JSON",

          success: function(data){

          var str="";

          //遍歷數(shù)組,把它放入sj

          for(var k in data){

          str=str+"<option value='"+data[k].[0]+"'>"+data[k].[1]+"</option>";

          }

          $("#qu").html(str);

          }

          });

          }

          4.再把數(shù)據(jù)庫連接起來 :load.php,把DBDA重新加載一個方法:JsonQuery

          <?php

          $pcode = $_POST["pcode"];

          require_once "./DBDA.class.php";

          $db = new DBDA();

          $sql = "select * from chinastates where parentareacode='{$pcode}'";

          echo $db->JsonQuery($sql,0);


          封裝類

          <?php

          class DBDA{

          public $host="localhost";

          public $uid="root";

          public $pwd="";

          public $dbname="0710_info";

          /*

          query方法:執(zhí)行用戶給的sql語句,并返回相應的結果

          $sql:用戶需要執(zhí)行的sql語句

          $type:用戶需要執(zhí)行的sql語句的類型

          return:如果是增刪語句改返回true或false,如果是查詢語句返回二維數(shù)組

          */

          public function query($sql,$type=1){//默認true為增刪改

          $db = new MySQLi($this->host,$this->uid,$this->pwd,$this->dbname);

          if(mysqli_connect_error()){

          return "連接失敗!";

          }

          $result = $db->query($sql);

          if($type==1){

          return $result;//增刪改語句返回true或false

          }else{

          return $result->fetch_all();//查詢語句返回二維數(shù)組

          }

          }

          //此方法用于ajax中用于對取出的數(shù)據(jù)(二維數(shù)組)進行拼接字符串處理

          public function StrQuery($sql,$type=1){

          $db = new MySQLi($this->host,$this->uid,$this->pwd,$this->dbname);

          if(mysqli_connect_error()){

          return "連接失敗!";

          }

          $result = $db->query($sql);

          if($type==1){

          return $result;//增刪改語句返回true或false

          }else{

          $arr = $result->fetch_all();//查詢語句返回二維數(shù)組

          $str = "";

          foreach($arr as $v){

          $str = $str.implode("^", $v)."|";

          }

          $str = substr($str, 0,strlen($str)-1);

          return $str;

          }

          }

          //此方法用于ajax中用于返回為json數(shù)據(jù)類型時使用

          public function JsonQuery($sql,$type=1){

          $db = new MySQLi($this->host,$this->uid,$this->pwd,$this->dbname);

          if(mysqli_connect_error()){

          return "連接失敗!";

          }

          $result = $db->query($sql);

          if($type==1){

          return $result;//增刪改語句返回true或false

          }else{

          $arr = $result->fetch_all();//查詢語句返回二維(關聯(lián))數(shù)組

          return json_encode($arr);//將數(shù)組轉換成json

          }

          }

          }

          實現(xiàn)效果:

          ue實現(xiàn)城市三級聯(lián)動,可以通過使用Vue的v-model指令和computed屬性來實現(xiàn)。首先,需要準備一個包含省市區(qū)數(shù)據(jù)的JSON文件,例如:

          ```json

          {

          "provinces": [

          {

          "name": "北京市",

          "cities": [

          {

          "name": "北京市",

          "areas": [

          "東城區(qū)",

          "西城區(qū)",

          "朝陽區(qū)",

          "豐臺區(qū)",

          "石景山區(qū)",

          "海淀區(qū)",

          "門頭溝區(qū)",

          "房山區(qū)",

          "通州區(qū)",

          "順義區(qū)",

          "昌平區(qū)",

          "大興區(qū)",

          "懷柔區(qū)",

          "平谷區(qū)",

          "密云區(qū)",

          "延慶區(qū)"

          ]

          }

          ]

          },

          {

          "name": "上海市",

          "cities": [

          {

          "name": "上海市",

          "areas": [

          "黃浦區(qū)",

          "徐匯區(qū)",

          "長寧區(qū)",

          "靜安區(qū)",

          "普陀區(qū)",

          "虹口區(qū)",

          "楊浦區(qū)",

          "閔行區(qū)",

          //省市區(qū)數(shù)據(jù)

          const data = {

          provinces: [

          {

          name: "北京市",

          cities: [

          {

          name: "北京市",

          areas: [

          "東城區(qū)",

          "西城區(qū)",

          "朝陽區(qū)",

          "豐臺區(qū)",

          "石景山區(qū)",

          "海淀區(qū)",

          "門頭溝區(qū)",

          "房山區(qū)",

          "通州區(qū)",

          "順義區(qū)",

          "昌平區(qū)",

          "大興區(qū)",

          "懷柔區(qū)",

          "平谷區(qū)",

          "密云區(qū)",

          "延慶區(qū)"

          ]

          }

          ]

          },

          {

          name: "上海市",

          cities: [

          {

          name: "上海市",

          areas: [

          "黃浦區(qū)",

          "徐匯區(qū)",

          "長寧區(qū)",

          "靜安區(qū)",

          "普陀區(qū)",

          "虹口區(qū)",

          "楊浦區(qū)",

          "閔行區(qū)"

          ]

          }

          ]

          },

          {

          name: "廣東省",

          cities: [

          {

          name: "廣州市",

          areas: [

          "荔灣區(qū)",

          "越秀區(qū)這是一個JSON文件,包含了省市區(qū)的數(shù)據(jù)。接下來,在Vue組件中使用這個數(shù)據(jù),實現(xiàn)城市三級聯(lián)動。

          首先,需要在Vue組件中引入這個數(shù)據(jù)文件,并將其賦值給一個變量:

          ```javascript

          import data from './data.json';

          export default {

          data() {

          return {

          provinces: data.provinces,

          selectedProvince: '',

          selectedCity: '',

          selectedArea: ''

          }

          }

          }

          ```

          然后,在模板中使用v-model指令將選擇的省市區(qū)綁定到對應的變量上:

          ```html

          <template>

          <div>

          <select v-model="selectedProvince">

          <option value="">請選擇省份</option>

          <option v-for="province in provinces" :value="province.name">{{ province.name }}</option>

          </select>

          <select v-model="selectedCity">

          <option value="">請選擇城市</option>

          <option v-for="city in selectedProvince.cities" :value="city.name">{{ city.name }}</option>

          </select>

          <select v-model="selectedArea">

          <option value="">請選擇區(qū)域</option>

          <option v-for="area in selectedCity.areas" :value="area">{{ area }}</option>

          </select>

          </div>

          </template>

          ```

          最后,使用computed屬性來動態(tài)獲取選擇的省市區(qū)的數(shù)據(jù):

          ```javascript

          computed: {

          selectedProvince() {

          return this.provinces.find(province => province.name === this.selectedProvince);

          },

          selectedCity() {

          if (this.selectedProvince) {

          return this.selectedProvince.cities.find(city => city.name === this.selectedCity);

          }

          return null;

          }

          }

          ```

          這樣,當選擇省份的時候,城市和區(qū)域的下拉框會根據(jù)選擇的省份動態(tài)更新。當選擇城市的時候,區(qū)域的下拉框會根據(jù)選擇的城市動態(tài)更新。最后,可以通過訪問`selectedProvince`、`selectedCity`和`selectedArea`來獲取選擇的省市區(qū)的數(shù)據(jù)。


          主站蜘蛛池模板: 国产精品毛片一区二区三区 | 国产日韩一区二区三区在线播放| 无码av人妻一区二区三区四区| 日本一区二区三区在线视频观看免费 | 无码精品蜜桃一区二区三区WW| 久久久久人妻一区二区三区vr | 日韩精品无码视频一区二区蜜桃| 中文字幕一区二区三区有限公司| 久久无码人妻一区二区三区| 日韩国产免费一区二区三区| 国产在线步兵一区二区三区| 久久综合精品国产一区二区三区| 91国在线啪精品一区| 无码人妻精品一区二区三区东京热| 一区二区三区高清| 青娱乐国产官网极品一区| 久久婷婷色一区二区三区| 精彩视频一区二区三区| 一本一道波多野结衣一区| 无码人妻一区二区三区免费| 麻豆视频一区二区三区| 亚洲色婷婷一区二区三区| 亚洲综合一区二区精品导航| 亚洲一区二区三区免费在线观看| 国产高清不卡一区二区| 99国产精品一区二区| 亚洲丰满熟女一区二区v| 日韩精品一区二区三区中文字幕 | 北岛玲在线一区二区| 少妇激情av一区二区| 精品视频在线观看一区二区三区| 99精品一区二区三区| 亲子乱AV视频一区二区| 一区二区精品在线| 久久亚洲一区二区| 精品免费AV一区二区三区| 在线播放国产一区二区三区| 国产成人免费一区二区三区| 精品一区二区三区自拍图片区| 亚洲国产av一区二区三区| 国99精品无码一区二区三区|