2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 中国天气网城市代码爬取

中国天气网城市代码爬取

时间:2023-10-28 21:53:04

相关推荐

中国天气网城市代码爬取

想试着收集一些气象数据,记得之前气象数据共享平台可以下,结果发现需要实名认证还要提交证件照之类的,想了想,脸黑,估计认证不过,还是算了。于是又网上找了找,发现在美国noaa网站可以下载,包含中国大概700多个站点的数据,时间从50年代一直到最近,但是细看了几个站点的数据后,发现有些站点数据只到2000年初或者更早。继续搜索后想到可以用爬虫,从天气网等网站爬取一些数据,考虑到权威性,选择了中国天气网。

目标网页

目标网页主要是各个城市的天气页面,主要是当前天气,以及过去24小时天气,每个城市的网址为:

/weather1d/+{城市代码}.shtml

因此,首先需要找到各个城市的代码,从网上搜了一些后,发现这些可能时间较早,与现在网站上数据不能一一对应,所以考虑从网页中重新爬取到城市代码,顺便可以练习一下相关爬虫技术。

网上搜到的爬虫案例大多基于python编写,但是个人最近刚看到一个用java爬取京东商品信息及图片的案例,因此想先用java试着爬取,个人感觉用python会显得更简洁,python代码可以很快的看到核心代码,而java,尤其是比较成熟的java代码,即使核心代码很短,却经常被包含在各种异常处理,各种线程,各种配置文件,各种分门别类里。

话不多说,说城市代码的获取,在研究每个城市天气页面的源码时,发现在一个select的div下,有对应城市的各个区县的代码,比如在上海闵行的页面里,可以看到上海市的各个区县(下图)的城市代码及名称。

再说城市代码的组成规则,前三位101代表中国,接下来的六位依次是省(自治区、直辖市、特区),地市以及区县,分别各占两位,直辖市区县最后两位都是0,真不明白为什么不直接用行政代码。

具体方法

用到的技术主要是发送请求的httpClient以及解析网页的Jsoup。

<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>${version}</version></dependency><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>${version}</version></dependency>

因为不清楚具体有多少个地级市,最先想到的是循环101010100-101350000,遍历所有页面,但这样循环次数过多,因此加了一层循环,内层循环连续出现无效页面次数大于100时,跳出内层循环,外层循环加10000,也就是调到下一个省。需要注意的是,该网站无效页面返回并不是404,而是空页面,因此可以通过判断html页面字符长度来确认无效页面。

for (long j = 101010100; j< 101360000; j+=10000) {//标记无效页面int countInvalid = 0;for(long i = j;i<101350000;i++) {String url = "/weather1d/" + i + ".shtml";String html = getHtml(url);StringBuilder sb = new StringBuilder();if (html!=null && html.length()>20) {//计数归零countInvalid=0;File file = new File("D:\\temp\\" + i +".txt");//解析HtmlDocument document = Jsoup.parse(html);Elements lis = document.select("#select ul").select("li");//System.out.println(lis.size());for (Element li : lis) {String cityCode = li.attr("tip");String cityName = li.text();sb.append(cityCode + "\t" + cityName + "\r\n");}FileUtils.writeStringToFile(file, sb.toString() , "UTF-8");}else {//连续100次出现无效页面,退出内循环countInvalid++;if(countInvalid > 100) {break;}}}}

用httpClient发送页面请求方法如下,用的是最基础的方法:

public static String getHtml(String url) throws Exception {// 创建Httpclient对象CloseableHttpClient httpclient = HttpClients.createDefault();// 创建http GET请求HttpGet httpGet = new HttpGet(url);CloseableHttpResponse response = null;try {// 执行请求response = httpclient.execute(httpGet);// 判断返回状态是否为200if (response.getStatusLine().getStatusCode() == 200) {String content = EntityUtils.toString(response.getEntity(), "UTF-8");return content;}} finally {if (response != null) {response.close();}httpclient.close();}return null;}

这样就得到每个区县级别对应的txt文件,接下来就是处理重复的txt文件,原本的想法是,每个地市级别(前7位代码)仅保留一个,最后将txt文件合并成一个。在实际操作中发现,遍历每个文件的每一行数据,删除掉重复项,写入一个列表里,最后将列表输出到一个txt文件,这样会快很多。最终得到3231条记录。

File[] files = new File("D:\\temp\\weatherCitycode").listFiles();File outFile = new File("D:\\temp\\weatherCitycode.txt");List<String> cityList = new ArrayList<String>();for(int idx = 0; idx<files.length;idx++) {File curFile = files[idx]; List<String> lines = FileUtils.readLines(curFile, "UTF-8");for(String line:lines) {if (!cityList.contains(line)){cityList.add(line);}}}FileUtils.writeLines(outFile, cityList);System.out.println(cityList.size());

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。