首页 > 编程语言 >Java爬取中国天气网实况天气数据

Java爬取中国天气网实况天气数据

时间:2023-01-03 12:07:13浏览次数:39  
标签:Java String getString jsonObject System 天气 爬取 println out


因实验室需求,需要找一个实况天气API。

百度云、阿里云、腾讯云上边我都去找了,很多平台要么没有,要么要收费(免费的可调用次数太少了)。而我在高德开放平台上找到了一个,但是不符合要求,被老师pass掉了。

百度搜一下,基本上都是用Python自动化测试Selenium写的,那也太没意思了吧。找不到,那我只好自己写一个爬虫去爬取了。

分析

如果想在中国天气网上爬取实况天气还是很简单的,但是由于思路一直受限制,所以道路很曲折。

Java爬取中国天气网实况天气数据_System

原来是考虑着爬取这个图,每天爬一次就够了。

我费劲脑汁,我还想用x、y的比值来计算出每个点所在的位置然后得出每个点对应的数据。但是经过几次测试之后,误差较大,所以这个方案就放弃了。

然后考虑追溯每个点数据的来源,但是这个网站的js文件用了混淆加密,变量全是a、b、c、dxxxx看不出来意思的英文字母。后来又想想。网页上的数据无非来自两个地方:

  • 静态的(在源代码中可以直接找到的)
  • 异步请求(在开发者工具栏中network中可以查找)
  • 其他的都是玄学

那么根据这个网站,不是静态的。但是network中有那么多的请求,不好找?。

我们就在网站源代码中找​​js​​​文件,看看哪个​​js​​​文件中有请求。看到一个请求像是在请求数据(一般数据都放在一个服务器上),所以我们根据该请求的​​Domain​​,缩小network中的我们寻找的部分。

Java爬取中国天气网实况天气数据_天气_02

在Domain是​​d1.weather.com.cn​​中进行寻找,果然数据基本上都出于这个Domain。

Java爬取中国天气网实况天气数据_爬虫_03

成功了一半,但是请求链接后面加的那一串数字是什么?

​http://d1.weather.com.cn/sk_2d/101180101.html?_=1546572266854​

越看越像时间戳,然后再​​eclipse​​中测试一下,果然是时间戳。

那么问题就简单了。直接写代码就行了。

总结

遇到爬取任务时,要先分析:

找数据
  • 看数据是否就在网站源代码中
  • 看数据是否是异步加载的
  • 若network中请求不多,直接遍历查看请求即可。
  • 反之,通过请求链接寻找​​Domain​​,然后缩小范围寻找请求。
  • 如果上两个都不容易,那就在开发者工具中​​Break on subtree modifications​​调试js文件
  • 如果js文件使用了混淆加密,你不想掉头发的话,就直接找异步请求吧。
检查数据

要知道很多网站都有反爬虫机制,也就是说 你获取的数据中可能被"投了毒"。好好检查检查数据是否正确。

写代码爬取数据

要注意以下几部分

  • 请求头伪装的像浏览器一点
  • 让爬虫随机获取​​user-agent​
  • 设置​​referer​​(这个还是比较有用的)
  • 请求之间有一些延迟最好
  • 如果需要的话,就上下边的终极武器。
  • 构造​​cookies​​池
  • 构造​​IP​​池

Java代码

我用了​​quartz​​定时任务框架来实现定时爬取。

public void execute(JobExecutionContext arg0) {

String[] city = new String[124];
// 读取城市ID
int i = 0;
String str = "";
try {
URL resource = this.getClass().getResource("/cityId.txt");
String path = resource.getPath();// 获取文件的绝对路径
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(path)));
while ((str = br.readLine()) != null) {
city[i] = str;
i++;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setSocketTimeout(60000).setConnectTimeout(60000)
.setConnectionRequestTimeout(60000)
.setStaleConnectionCheckEnabled(true).build();
// 创建httpClient对象
CloseableHttpClient h = HttpClients.custom()
.setDefaultRequestConfig(defaultRequestConfig).build();

// 创建并设置URI
URIBuilder uri = null;
// 创建Get请求
HttpGet hg = null;
String url = "";
// 创建响应对象
CloseableHttpResponse response = null;
InputStream inputstream = null;
for (int j = 0; j < city.length; j++) {

try {
url = "http://d1.weather.com.cn/sk_2d/" + city[j] + ".html?_="
+ System.currentTimeMillis();
uri = new URIBuilder(url);
hg = new HttpGet(uri.build());
} catch (Exception e2) {
e2.printStackTrace();
}
// 设置请求头
hg.setHeader("Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
hg.setHeader("Accept-Encoding", "gzip, deflate");
hg.setHeader("Accept-Language",
"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
hg.setHeader("Cache-Control", "no-cache");
hg.setHeader("Connection", "keep-alive");
hg.setHeader("Host", "d1.weather.com.cn");
hg.setHeader("Upgrade-Insecure-Requests", "1");
hg.setHeader("Cookie",
"f_city=%E9%83%91%E5%B7%9E%7C101180101%7C; Hm_"
+ "lvt_080dabacb001ad3dc8b9b9049b36d"
+ "43b=1546482322; Hm_lpvt_080dabacb001a");
hg.setHeader(
"User-Agent",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36");
hg.setHeader("Referer",
"http://www.weather.com.cn/weather1dn/101180101.shtml");
// 发送请求
HttpEntity entity = null;
String line = "";
String Sline = "";

try {
response = h.execute(hg);
// 获取请求结果
entity = response.getEntity();
inputstream = entity.getContent();
BufferedReader bufferedreader = new BufferedReader(
new InputStreamReader(inputstream, "UTF-8"));
while ((line = bufferedreader.readLine()) != null) {

Sline += line + "\n";
}

Sline = Sline.substring(Sline.indexOf('{'));

JSONObject jsonObject = JSONObject.fromObject(Sline);
show(jsonObject);

} catch (ClientProtocolException e1) {
// TODO Auto-generated catch block
System.out.println("请求超时等问题");
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
System.out.println("I/O问题");
e1.printStackTrace();
} finally {
try {
inputstream.close();
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("I/O、response流关闭");
e.printStackTrace();
}
}
}

}

/**
* 样例对照表
*
* var dataSK = { "nameen":"zhengzhou", "cityname":"郑州", "city":"101180101",
* "temp":"1", 摄氏度 "tempf":"33", 华氏度 "WD":"西南风", 风向 "wde":"SW", 风向英文
* "WS":"1级", 风力等级 "wse":"<12km/h", 风速 "SD":"52%", 湿度 "time":"11:25",
* "weather":"晴", "weathere":"Sunny", "weathercode":"d00", "qy":"1019", 气压
* "njd":"4.94km", 能见度 "sd":"52%", 湿度 "rain":"0.0", 降雨量 "rain24h":"0",
* "aqi":"214", "limitnumber":"", "aqi_pm25":"214", pm2.5
* "date":"01月03日(星期四)" }
*/

public void show(JSONObject jsonObject) {
// 获取城市编号
String cityId = jsonObject.getString("city");
System.out.println(cityId);

String cityName = jsonObject.getString("cityname");
System.out.println(cityName);

// 获取当前气温
String temperature = jsonObject.getString("temp");
System.out.println("当前气温" + ":" + temperature);

// 获取当前风向
String windDirection = jsonObject.getString("WD");
System.out.println("风向:" + windDirection);
// 获取当前风向
String windDirectionEn = jsonObject.getString("wde");
System.out.println("风向符号:" + windDirectionEn);

// 获取当前风速等级
String windPower = jsonObject.getString("WS");
System.out.println("风力:" + windPower);

// 获取当前风速
String windSpeed = jsonObject.getString("wse");
System.out.println("风力:" + windSpeed);

// 获取当前湿度
String humidity = jsonObject.getString("SD");
System.out.println("湿度:" + humidity);

String time = jsonObject.getString("time");
System.out.println("时间:" + time);

String weather = jsonObject.getString("weather");
System.out.println("天气中文:" + weather);

String weatherEn = jsonObject.getString("weathere");
System.out.println("天气英文:" + weatherEn);

String weatherCode = jsonObject.getString("weathercode");
System.out.println("天气代号:" + weatherCode);

String airPressure = jsonObject.getString("qy");
System.out.println("气压:" + airPressure);

String visibility = jsonObject.getString("njd");
System.out.println("能见度:" + visibility);

String rain = jsonObject.getString("rain");
System.out.println("降雨量:" + rain);

String rain24h = jsonObject.getString("rain24h");
System.out.println("日降雨量" + rain24h);

String aqi_pm25 = jsonObject.getString("aqi");
System.out.println("PM2.5:" + aqi_pm25);

String date = jsonObject.getString("date");
System.out.println("时间" + date);

Connection con = JButil.getConnection();
String sql = "INSERT INTO weather_sk "
+ "(cityId, cityName, lastUpdate, temperature, windSpeed, windPower,"
+ " windDirectionEn, windDirection, humidity, weather, weatherEn, weatherCode,"
+ " visibility, airPressure, rain24h, rain, aqi_pm25, time, date) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
QueryRunner qr = new QueryRunner();
int m = 0;
try {
m = qr.update(con, sql, cityId, cityName,
Timestamp.valueOf(new Date().toLocaleString()),
temperature, windSpeed, windPower, windDirectionEn,
windDirection, humidity, weather, weatherEn, weatherCode,
visibility, airPressure, rain24h, rain, aqi_pm25, time,
date);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
DbUtils.closeQuietly(con);
}

}


标签:Java,String,getString,jsonObject,System,天气,爬取,println,out
From: https://blog.51cto.com/u_13758447/5985116

相关文章

  • nginx-clojure java 集成试用
    主要是基于java开发一个简单的扩展,学习下流程java项目pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4......
  • JavaScript 深拷贝
    在进行赋值之前,为指针类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝。这种拷贝称为深拷贝。————百度百科源码⚠还有部分类型不支持typescript:/......
  • Java面试问答总结
    问:什么是并发和并行?答:并发是在单核操作系统中,CPU通过切分时间片交替执行不同的线程;并行是在多核操作系统中,多个CPU同时执行不同的线程。并发和并行的目的都是为了最大化的......
  • java中私有构造函数的作用
    使用私有构造函数强化singleton属性。方法一:公有的静态成员是一个final域,成员的声明很清楚的表达了这个类是一个singleton。publicclassElvis{publicstatic......
  • java内存管理
    1.java是如何管理内存的 Java的内存管理就是对象的分配和释放问题。(两部分) 分配:内存的分配是由程序完成的,程序员需要通过关键字new为每个对象申请内存空间(基本类型......
  • Java程序员必看的 13 本 Java 书籍!
    关乎于程序员,除了做项目来提高自身的技术,还有一种提升自己的专业技能就是:多!看!书! 毕竟,书是学习的海洋呢!So,Java程序员你们准备好了吗?双手奉上Java程序员必读之热门书单。......
  • 初识Java
    初识JavaJava的特性和优势简单性就是c++语法的纯净版。没有头文件,指针运算,结构,联合,操作符重载,虚基类等等。面向对象面向对象是一种程序设计技术,他将重点放在数据(即对......
  • java中的HashSet的add()方法解析
     HashSet的add()方法解析示例代码如下:【可用于后续的源码追踪】1publicclassHomeWork04{2publicstaticvoidmain(String[]args){3HashS......
  • Javascript公共脚本库系列(二): 添…
    一.摘要本系列文章是为了抽象通用的,跨浏览器的脚本方法.本篇文章为我们的轻量级脚本库增加添加多播委托的方法.可以实现"单击页面空白区域则关闭页面上所有弹出层"等类似的......
  • java笔试题大全带答案(java笔试题大全带答案下载)
    谁有2008,2009,2010年计算机JAVA笔试试题和答案呢?2008年计算机Java笔试试题及答案2009年计算机考试Java笔试试题和答案2010年计算机考试Java笔试试题和答案下面地址也许有......