AJAX(七)jsonp实战--天气预报

  一、案例

  本次要做的案例的是使用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         ["\u6cb3\u5357", "18"],
 7         ["\u5b89\u9633", "1802"],
 8         ["\u5b89\u9633", "101180201"]
 9     ],
10     "weather": [{
11         "date": "2018-06-25",
12         "info": {
13             "dawn": ["2", "\u9634", "24", "\u5357\u98ce", "\u5fae\u98ce", "19:44"],
14             "day": ["8", "\u4e2d\u96e8", "27", "\u5317\u98ce", "\u5fae\u98ce", "05:07"],
15             "night": ["8", "\u4e2d\u96e8", "22", "\u897f\u98ce", "\u5fae\u98ce", "19:44"]
16         }
17     }, {
18         "date": "2018-06-26",
19         "info": {
20             "dawn": ["8", "\u4e2d\u96e8", "22", "\u897f\u98ce", "\u5fae\u98ce", "19:44"],
21             "day": ["7", "\u5c0f\u96e8", "28", "\u5357\u98ce", "\u5fae\u98ce", "05:07"],
22             "night": ["1", "\u591a\u4e91", "22", "\u5357\u98ce", "\u5fae\u98ce", "19:44"]
23         }
24     }, {
25         "date": "2018-06-27",
26         "info": {
27             "dawn": ["1", "\u591a\u4e91", "22", "\u5357\u98ce", "\u5fae\u98ce", "19:44"],
28             "day": ["0", "\u6674", "37", "\u5357\u98ce", "\u5fae\u98ce", "05:08"],
29             "night": ["0", "\u6674", "24", "\u5317\u98ce", "3-5\u7ea7", "19:44"]
30         }
31     }, {
32         "date": "2018-06-28",
33         "info": {
34             "dawn": ["0", "\u6674", "24", "\u5317\u98ce", "3-5\u7ea7", "19:44"],
35             "day": ["0", "\u6674", "36", "\u4e1c\u5317\u98ce", "\u5fae\u98ce", "05:08"],
36             "night": ["1", "\u591a\u4e91", "21", "\u897f\u98ce", "\u5fae\u98ce", "19:45"]
37         }
38     }, {
39         "date": "2018-06-29",
40         "info": {
41             "dawn": ["1", "\u591a\u4e91", "21", "\u897f\u98ce", "\u5fae\u98ce", "19:45"],
42             "day": ["1", "\u591a\u4e91", "35", "\u4e1c\u5357\u98ce", "\u5fae\u98ce", "05:08"],
43             "night": ["1", "\u591a\u4e91", "22", "\u5357\u98ce", "\u5fae\u98ce", "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次够玩了。

posted @ 2018-10-06 22:43  天天向上吧  阅读(1026)  评论(1编辑  收藏  举报