安卓天气预报项目(二)之获取中国天气网所有的城市编号

本文讲述了获取中国天气预报数据的过程,包括尝试使用中国天气网的API和XML数据,以及最终通过逐个城市编号爬取网页解决数据获取难题。作者通过分析城市代码规律,实现了对近30万个网页的爬取,生成了包含省、市、区的天气数据,但由于某些数据不连续,仍需后期手动校验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

获取天气预报的数据

所有省份数据

数据来自网络
于是我们瞄准好中国天气网,使用java获得网页内容.
首先我们要获得所有的省份,以及各个省份下的市,以及各个市下面对应的区; 在app打开的一瞬间,得到数据,存放到数据库.

方案一 (失败)

首先我打算找一个中国天气网的api接口,尝试着看看能不能获得所有的城市;
在这里插入图片描述https://j.i8tq.com/weather2020/search/city.js
果不其然里面是一个城市的以json格式存储.
用Eclispe爬取一下看看

String urlInfo="https://j.i8tq.com/weather2020/search/city.js";
try {
	url=new URL(urlInfo);
    HttpURLConnection connection=(HttpURLConnection)url.openConnection();
    connection.setRequestMethod("GET");
	connection.connect();
 	connection.setReadTimeout(10000);
 	InputStream is=connection.getInputStream();
	BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
	StringBuilder sb=new StringBuilder();
	String line;
	while ((line = br.readLine()) != null) 
		sb.append(line);
	is.close();
	br.close();
	FileWriter f=new FileWriter(new File("城市json.txt"),true);
	BufferedWriter bf=new BufferedWriter(f);bf.write(data);bf.close();
	String data=sb.toString();
	System.out.println(data);
	}catch(Exceptione e){

	}

打印一下网页数据 这里只展示部分数据

{
	"北京": {
		"北京": {
			"北京": {
				"AREAID": "101010100",
				"NAMECN": "北京"
			},
			"海淀": {
				"AREAID": "101010200",
				"NAMECN": "海淀"
			},
			"朝阳": {
				"AREAID": "101010300",
				"NAMECN": "朝阳"
			},
			"顺义": {
				"AREAID": "101010400",
				"NAMECN": "顺义"
			}
		}
	}	
}

想要通过json进行解析都非常麻烦,需要所有城市都拿取一遍 因为不是数组的格式,而是一个一个单独的对象,解析所有城市不太可能.

{
    "city_data": [
        {
            "浙江省": [
                {
                    "温州市": [
                        {
                            "x县": [
                                {
                                    "AREAID": "101010100",
                                    "NAMECN": "北京"
                                }
                            ]
                        },
                        
                        {
                            "y县": [
                                {
                                    "AREAID": "101010101",
                                    "NAMECN": "北京"
                                }
                            ]
                        }
                    ]
                },
                {
                    "杭州市": [
                        {
                            "xx县": [
                                {
                                    "AREAID": "101010100",
                                    "NAMECN": "北京"
                                }
                            ]
                        },
                        {
                            "yy县": [
                                {
                                    "AREAID": "101010101",
                                    "NAMECN": "北京"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}

尝试自己把json内容改成数组的格式 但是无法确定 右括号 ] 的位置;
无法使用gson格式进行加载,因为两个省份和市的的名字重复,并且需要建立所有的区的对象,数据量较大.

方案二(启发)

只能靠前辈们留下的数据了
https://blog.csdn.net/ljheee/article/details/54134621?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-8&spm=1001.2101.3001.4242
有前辈们从以前的接口里面爬到了数据.xml !!
可以通过直接解析xml文件直接获得所有的省份!!!
并且通过解析我们能够非常轻易的获得所有分开的的省份,市级,县级 能够轻易得到对应的id
于是我去下载了这样的一个文件,看了一下他的算法.非常令人可惜的是,代码是通过读取一个txt文件,
把所有的城市数据在读出来.非常可惜不是最根本的方法.并且也存在城市信息不全的问题…

<China>
  <province id="01" name="北京">
    <city id="0101" name="北京">
      <county id="010101" name="北京" weatherCode="101010100"/>
      <county id="010102" name="海淀" weatherCode="101010200"/>
      <county id="010103" name="朝阳" weatherCode="101010300"/>
      <county id="010104" name="顺义" weatherCode="101010400"/>
      <county id="010105" name="怀柔" weatherCode="101010500"/>
      <county id="010106" name="通州" weatherCode="101010600"/>
      <county id="010107" name="昌平" weatherCode="101010700"/>
      <county id="010108" name="延庆" weatherCode="101010800"/>
      <county id="010109" name="丰台" weatherCode="101010900"/>
      <county id="010110" name="石景山" weatherCode="101011000"/>
      <county id="010111" name="大兴" weatherCode="101011100"/>
      <county id="010112" name="房山" weatherCode="101011200"/>
      <county id="010113" name="密云" weatherCode="101011300"/>
      <county id="010114" name="门头沟" weatherCode="101011400"/>
      <county id="010115" name="平谷" weatherCode="101011500"/>
    </city>
  </province>

有一天我突然看到中国天气网的城市在这里插入图片描述
为什么不可以自己把所有的城市按城市编号进行爬取一遍获得城市的省和市!!!
动手敲代码
从北京101010100到台湾的云林101340406 总共需要访问网页近30w次,非常恐怖的数字;
我的笔记本试过了从开始的1k次 平均1秒能达到6次访问,到后面平均1秒访问1.5次,怕是跑个2天差不多.
于是找一下技巧
1 所有城市编号的倒数第4位没有超过2 例如01021600 顶多16个城市
2 所有以市开头的省份 城市代码均相差100,一定以00结尾 ; 否则相差1,但并不是都是以1结尾,仅有一个城市是以1结尾,我忘了
3 和省份同名的城市会显示城区

4 特别注意海南地区在这里插入图片描述是没有市的!!

上代码!! 注意当时没有想到另外一种方法 就是当一个省份的读取完了之后
直接将i 赋值为另外一个城市的 城市编码 进行跳转, 这样的速度非常快
当然如果你直接使用这种方式 我建议你把内容写进文件里面,
因为在控制台里面字符显示不够长
我是这样每次读完一个省份我就终止程序 手动更新i的数值,然后得到城市

		String ncity = "";
		String npro = "";
		String ncoun = "";
		HttpURLConnection connection;
		for (long i = 101010100; i <= 101340406;i+=1) {
			//在这里
			int flag=1;
			String k = String.valueOf(i);
			if(k.charAt(5)>=50){
				i=i/10000;
				i=(i+1)*10000;
			} 
			String urlInfo = "http://www.weather.com.cn/weather/" + i + ".shtml";
			URL url;
			try {
				url = new URL(urlInfo);
				connection = (HttpURLConnection) url.openConnection();
//				connection.setRequestMethod("GET");
				connection.connect();
				connection.setReadTimeout(100);
				InputStream is = connection.getInputStream();
				BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
				StringBuilder sb = new StringBuilder();
				String line;
				while ((line = br.readLine()) != null) {
					if(line.equals("<!-- empty -->")) {flag=0;connection.disconnect();break;}
					sb.append(line);
				}
				if(flag==0)continue;
				is.close();
				br.close();
				String data = sb.toString();
				String coun = null;
				String city = null;
				String pro = null;
				try {
					String info = null;
					if (i <= 101044100||(i>=101310101&&i<=101320103)) {
						info = null;
						info = data.split("div class=\"crumbs fl\">")[1];
						city = pro = info.split("</a>")[1].split("target=\"_blank\">")[1];
						coun = info.split("<span>></span>")[1].split("</span>")[0].split("<span>")[1];
					}
					// 离谱居然有一个是&gt
					else {
							info = data.split("div class=\"crumbs fl\">")[1];
							pro = info.split("</a>")[1].split("target=\"_blank\">")[1];	
							city = info.split("</a>")[2].split("target=\"_blank\">")[1];
							coun = info.split("<span>></span>")[2].split("</span>")[0].split("<span>")[1];// 离谱居然有一个是&gt
						}	
						if (coun.equals("城区"))	coun = city;
						if (!npro.equals(pro)) {
							System.out.println("</province>");
						}
						if (!npro.equals(pro)) {
							npro = pro;
							System.out.println("<province id=\"" + k.substring(3, 5) + "\" name=\"" + pro + "\">");
						}
						if (!ncity.equals(city)) {
							System.out.println("  </city>");
						}
						if (!ncity.equals(city)) {
							ncity = city;
							System.out.println("  <city id=\"" + k.substring(3, 7) + "\" name=\""+city+"\">");
						}
						System.out.println("    <county id=\"" + k.substring(3) + "\" " + "name=\"" + coun + "\" "
								+ "weatherCode=\"" + i + "\"/>");
					}
				 catch (Exception e) {
				}

			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	</city>
</province>
<province id="01" name="北京"> 
    <city id="0101" name="北京"> 
      <county id="010100" name="北京" weatherCode="101010100"/>  
      <county id="010200" name="海淀" weatherCode="101010200"/>  
      <county id="010300" name="朝阳" weatherCode="101010300"/>  
      <county id="010400" name="顺义" weatherCode="101010400"/>  
      <county id="010500" name="怀柔" weatherCode="101010500"/>  
      <county id="010600" name="通州" weatherCode="101010600"/>  
      <county id="010700" name="昌平" weatherCode="101010700"/>  
      <county id="010800" name="延庆" weatherCode="101010800"/>  
      <county id="010900" name="丰台" weatherCode="101010900"/>  
      <county id="011000" name="石景山" weatherCode="101011000"/>  
      <county id="011100" name="大兴" weatherCode="101011100"/>  
      <county id="011200" name="房山" weatherCode="101011200"/>  
      <county id="011300" name="密云" weatherCode="101011300"/>  
      <county id="011400" name="门头沟" weatherCode="101011400"/>  
      <county id="011500" name="平谷" weatherCode="101011500"/>  
      <county id="011600" name="东城" weatherCode="101011600"/>  
      <county id="011700" name="西城" weatherCode="101011700"/> 
    </city> 
  </province>  

最后得到这样的数据, 我没有打全否则太长了
手动把开头的那两行删掉 头加一个 尾巴加一个
不要计较那么多啦,有数据就行了. 其中也有一些地区明明是一个市级下面的却不连续的,
只能进行手动修改
类似于!

//		长春地区无
//		<city id="0601" name="长春">
//		<city id="2216" name="巢湖">
		
		
//		  <city id="0812" name="锡林郭勒">
//		    <county id="081206" name="锡林郭勒" weatherCode="101081206"/>
//		  </city>
//		  <city id="0812" name="乌鲁木齐">
//		    <county id="081207" name="水磨沟" weatherCode="101081207"/>
//		  </city>
//		 <city id="2820" name="茂名">
//		 <city id="2821" name="汕尾">
		
//		 <city id="1304" name="乌鲁木齐">
//	     <county id="130403" name="米东" weatherCode="101130403"/>

//		 <city id="1407" name="那曲">
//	    <county id="140703" name="申扎" weatherCode="101140703"/>
//	    </city>

所以即使用了这种方法还需要手动检查一遍
但是因为我是一个一个省份手动复制粘贴,所以这一类的数据还是能及时发现的

所有城市文件我还没有上传, 如果有人需要的话,和我私信吧
既然都看到这里了,给我点个赞吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值