一、案例
本次要做的案例的是使用jsonp制作一个查询天气情况的网页,我会从如何抓取数据接口,到一步一步完成这个案例来详细讲解。
这个页面样式非常简单,截图如下。用户需要先选择一个城市,然后点击查看天气,那么最近5天的天气数据,就会展示到下面。
二、数据从何而来
当然我们不可能自己建气象站,我们只有通过互联网拿到别人“分享”给我们的数据接口,然后通过这个数据接口获取全国的气象数据。这样我们就必须使用jsonp了,因为提供气象数据服务的api,其所在的域名肯定跟我们自己的应用程序不是一个域名。
那么问题来了,我们如何知道哪里有api提供气象数据服务的?这个就要多观察多积累了。比如现在很多人的电脑上都会安装360,一般360杀毒在安装时候会篡改你的浏览器主页为“hao360”这个网站,那么你打开网页,每次都会看到这样的画面。
这个网站在非常显眼的地方提供了一个查看天气的模块。难道360还开着气象站?如果不是,那我们只要看看它是如何搞到数据的,我们就能如法炮制了。
一般你可以这样做:
1.在气象模块上点鼠标右键->审查元素。去看看他的结构
2.打开开发者选项工具窗口,点击Network(网络)选项卡,然后去查看请求报文,这样就能找到气象数据从哪儿来了。
不过,如果你没有经验,你会被请求报文列表中的数据给吓住,因为实在是太多了,至少不下300条请求项。那我们怎么去找真正需要的那个请求呢?
试想,这个hao360也不可能自己弄个气象站,所以它必然也是抓取的第三方api,所以也必然是通过jsonp的形式来实现的。那么我们只需要在所有的请求报文中按type这一列排下序,然后就只管看请求类型是script的那些项。这样一下就把范围缩小了很多很多。
最后我们找到,这里的请求url是:https://cdn.weather.hao.360.cn/sed_api_weather_info.php?code=101180201&app=hao360&_jsonp=__jsonp3__
简单说明下这个url的参数
1.code:要查询的城市编码,这个可以百度
2._jsonp:你自己定义的回调函数的名字。
3.其他的参数都无关紧要,至少对本案例来说是这样。
在浏览器里打开这个链接,你看到的结果是这样的:
当然,我只截取了一小部分。不过已经可以看出了,这是一个典型的jsonp跨域访问。
然后,我把数据copy出来,贴到sublime中,格式化之后,数据是这个样子的。
1 { 2 "pubdate": "2018-06-25", 3 "pubtime": "16:44:10", 4 "time": 1529916250, 5 "area": [ 6 ["u6cb3u5357", "18"], 7 ["u5b89u9633", "1802"], 8 ["u5b89u9633", "101180201"] 9 ], 10 "weather": [{ 11 "date": "2018-06-25", 12 "info": { 13 "dawn": ["2", "u9634", "24", "u5357u98ce", "u5faeu98ce", "19:44"], 14 "day": ["8", "u4e2du96e8", "27", "u5317u98ce", "u5faeu98ce", "05:07"], 15 "night": ["8", "u4e2du96e8", "22", "u897fu98ce", "u5faeu98ce", "19:44"] 16 } 17 }, { 18 "date": "2018-06-26", 19 "info": { 20 "dawn": ["8", "u4e2du96e8", "22", "u897fu98ce", "u5faeu98ce", "19:44"], 21 "day": ["7", "u5c0fu96e8", "28", "u5357u98ce", "u5faeu98ce", "05:07"], 22 "night": ["1", "u591au4e91", "22", "u5357u98ce", "u5faeu98ce", "19:44"] 23 } 24 }, { 25 "date": "2018-06-27", 26 "info": { 27 "dawn": ["1", "u591au4e91", "22", "u5357u98ce", "u5faeu98ce", "19:44"], 28 "day": ["0", "u6674", "37", "u5357u98ce", "u5faeu98ce", "05:08"], 29 "night": ["0", "u6674", "24", "u5317u98ce", "3-5u7ea7", "19:44"] 30 } 31 }, { 32 "date": "2018-06-28", 33 "info": { 34 "dawn": ["0", "u6674", "24", "u5317u98ce", "3-5u7ea7", "19:44"], 35 "day": ["0", "u6674", "36", "u4e1cu5317u98ce", "u5faeu98ce", "05:08"], 36 "night": ["1", "u591au4e91", "21", "u897fu98ce", "u5faeu98ce", "19:45"] 37 } 38 }, { 39 "date": "2018-06-29", 40 "info": { 41 "dawn": ["1", "u591au4e91", "21", "u897fu98ce", "u5faeu98ce", "19:45"], 42 "day": ["1", "u591au4e91", "35", "u4e1cu5357u98ce", "u5faeu98ce", "05:08"], 43 "night": ["1", "u591au4e91", "22", "u5357u98ce", "u5faeu98ce", "19:45"] 44 } 45 }], 46 。。。。。。 47 }
简单解释下数据:
1.这里只截取了数据的一部分,只保留了我们案例中需要用到的那一小部分,感兴趣的自己去研究吧。
2.显然,这个数据是js中的,json格式数据。
3.本案例中用到的气象数据,是在这个json对象的“weather”属性中。这个属性的值是一个js数组,数组一共有5个元素,每个元素又是一个json对象,每个json对象都代表了一天的天气情况。
三、案例的HTML结构
先看下页面的HTML结构
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>天气预报-hao360接口</title> <link rel="stylesheet" href="css/weather.css"> </head> <body> <div class="wt_container"> <div class="city"> <select id="selCity"> <option value="101180201">大安阳</option> <option value="101010100">北京</option> <option value="101180101">郑州</option> <option value="101250101">长沙</option> <option value="101050101">哈尔滨</option> <option value="101130101">乌鲁木齐</option> <option value="101280101">广州</option> </select> <button id="btn">查看天气</button> </div> <div class="weather"> <ul id="wtInfo"> <!-- <li> <h2>25日</h2> <div class="day"> <h3>白天天气</h3> <p>天气:</p> <p>温度</p> <p>风向</p> <p>风速</p> </div> <div class="night"> <h3>夜间天气</h3> <p>天气:</p> <p>温度</p> <p>风向</p> <p>风速</p> </div> </li> --> </ul> </div> </div> </body> </html>
大家都看得懂,简单说明下:
1.select标签中的每个选项都有一个value值,这个值对应的城市编码,这个编码是国家标准编码,不是自己随便乱写的,我是从百度出来然后写死到页面上的。当然,网上也有关于提供省市编码查询的api,你完全可以根据本案例所讲的方法,结合之前AJAX中讲的省市联动的案例,把这里城市的选择做成活的。我这里为了简单起见,随便从网上扒了几个城市,把城市的code拷贝了一下就写死到HTML了。目的只是为了让例子别太复杂。
2.由于我们拿到的数据是5天的数据,所以我们用一个<ul id = "wtInof">标签来展示所有的查询到的5天的天气,每天的天气用一个li包住。HTML中注释掉的部分就是模拟数据。
我们在js部分,只需要通过jsonp请求道数据,然后按照模拟数据的格式,填充到ul里就行了。
四、案例的js部分
直接看代码
1 <script src="js/jquery-3.3.1.js"></script> 2 <script> 3 function callback(data){ 4 //1.清空ul#wtInfo 5 $("#wtInfo").html(""); 6 //2.呈现数据 7 var wt = data.weather; 8 $.each(wt, function(index, ele){ 9 var date = ele.date; 10 var day = ele.info.day; 11 var night = ele.info.night; 12 var tag = "<li>"; 13 tag += "<h2>" + date + "</h2>"; 14 tag += "<div class='day'>"; 15 tag += "<h3>白天天气</h3>"; 16 tag += "<p>天气:" + day[1] + "</p>"; 17 tag += "<p>温度:" + day[2] + "</p>"; 18 tag += "<p>风向:" + day[3] + "</p>"; 19 tag += "<p>风速:" + day[4] + "</p>"; 20 tag += "</div>"; 21 tag += "<div class='night'>"; 22 tag += "<h3>夜间天气</h3>"; 23 tag += "<p>天气:" + night[1] + "</p>"; 24 tag += "<p>温度:" + night[2] + "</p>"; 25 tag += "<p>风向:" + night[3] + "</p>"; 26 tag += "<p>风速:" + night[4] + "</p>"; 27 tag += "</div>"; 28 tag += "</li>"; 29 $("#wtInfo").append(tag); 30 }); 31 } 32 $(function () { 33 $("#btn").on("click", function () { 34 var cityCode = $("#selCity option:selected").val(); 35 var url = 36 'https://cdn.weather.hao.360.cn/sed_api_weather_info.php?app=hao360&_jsonp=callback&code=' + 37 cityCode; 38 $("body").append($("<script src='" + url + "'><script>")); 39 }) 40 }) 41 </script>
代码解释:
1.这用到了jQuery,所以第1行代码先引入了jQuery包
2.jsonp的原理是通过<script>标签发出请求,而本例中不希望一打开网页就显示某一个城市的天气数据,而是要先选择一个,然后点击查询按钮,才发出请求,得到气象数据, 展示数据。
3.所以我们的思路是:肯定不能在页面上写死那个做jsonp请求的<script src = "......">标签。我们的做法是,当点击按钮时,我们动态的获取到所选select标签中城市的code,然后拼写出待请求的url,最后在文档(document)的body标签底部,动态添加这个做jsonp请求的<script src = "......">标签。
4.代码中定义的function callback(data)函数,就是用来做回调函数的,在这个回调函数中,主要功能就是解析json数据,然后填充到ul中。本身代码逻辑不复杂,就是拼写每个li,以及li里边的各项元素有点费事而已。
五、后记
这个案例,到这里就结束了。我再补充2点:
1.这个案例中需要大量拼写HTML标签代码,这么做是相当费时费力的,而且容易出错;一旦开发一个复杂点的页面,这么做是非常痛苦的。如何改进?我们可以使用模板技术。前端模板插件很多,最流行的前端模板就是art-template.js,大家可以从网上下载。我在这里给出使用该模板改造本例后的js代码,具体这个art-template怎么用,大家看看他官服的demo就一目了然,非常简单。
<script src="js/template.js"></script> <script id="weatherTemp" type="text/html"> <li> <h2><%= date %></h2> <div class="day"> <h3>白天天气</h3> <% for(var i=1; i < info.day.length; i++){%> <p><%= info.day[i]%></p> <% }%> </div> <div class="night"> <h3>夜间天气</h3> <% for(var i=1; i < info.night.length; i++){%> <p><%= info.night[i]%></p> <% }%> </div> </li> </script> <script> function callback(data) { //1.清空ul#wtInfo $("#wtInfo").html(""); //2.呈现数据 var wt = data.weather; $.each(wt, function (index, ele) { var html = template("weatherTemp", ele) $("#wtInfo").append(html); }); } $(function () { $("#btn").on("click", function () { var cityCode = $("#selCity option:selected").val(); var url = 'https://cdn.weather.hao.360.cn/sed_api_weather_info.php?app=hao360&_jsonp=callback&code=' + cityCode; $("body").append($("<script src='" + url + "'><script>")); }) }) </script>
2.如果我们每次都去分析别人的报文,那将是一个非常痛苦的过程。好在现在有专业的,专门提供数据服务的web api提供商,比如“聚合数据”,百度api商店等等,还有很多,大家可以去网上搜索下。其中有免费的,有付费的。比如聚合数据,申请账号是免费的,提供的服务有的免费,有的付费,不过即使是付费的,也可以免费使用1000次,对于我们学习来说1000次够玩了。