PHP利用天气API获取天气信息
中国天气网提供了一些查询天气的API,访问时返回天气信息的JSON格式数据,解析就可以得到天气信息:
http://www.weather.com.cn/data/sk/101281601.html
http://www.weather.com.cn/data/cityinfo/101281601.html
http://m.weather.com.cn/data/101281601.html
后面一串数字为城市代码。
返回的utf-8字符串
{"weatherinfo":{"city":"东莞","cityid":"101281601","temp":"22","WD":"东风","WS":"1级","SD":"90%","WSE":"1","time":"08:20","isRadar":"0","Radar":""}}
所以首先要将城市名转换为城市代码,最简单的办法是通过读取一个文本文件来获取:
格式如:
101010100=北京 101010200=海淀 101010300=朝阳 101010400=顺义 101010500=怀柔 101010600=通州 101010700=昌平 101010800=延庆 101010900=丰台 101011000=石景山 101011100=大兴
文本文件和PHP文件放在同一目录下;
于是PHP代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script> <script src="http://libs.baidu.com/bootstrap/2.0.4/js/bootstrap.min.js"></script> <link href="http://libs.baidu.com/bootstrap/2.0.4/css/bootstrap.min.css" rel="stylesheet"/> <title>天气查询简单版</title> </head> <body> <form class="form-horizontal" action="" method="post"> <legend> Weather </legend> <div class="control-group"> <label class="control-label" for="idCity">城市:</label> <div class="controls"> <input name="city" type="text" name="city" id="idCity" placeholder="请输入城市名字" maxlength="64"> </div> </div> <div class="control-group"> <div class="controls"> <button type="submit" class="btn btn-primary" style="margin: 10px"> 确定 </button> <button type="reset" class="btn btn-inverse" style="margin: 10px"> 重置 </button> </div> </div> </form> <hr/> <?php header("Content-Type: text/html; charset=utf-8"); function getWeather($city) { $wcity = file_get_contents("wcity.txt"); $pattern = '/([0-9]+)=' . $city . '/'; preg_match($pattern, $wcity, $matches, PREG_OFFSET_CAPTURE); if ($matches == null) { return null; } $cityID = $matches[1][0]; $data = file_get_contents('http://www.weather.com.cn/data/sk/' . $cityID . '.html'); return json_decode($data, true); } if ($_POST != null && $_POST["city"] != null) { $weather = getWeather($_POST["city"]); if ($weather == null) {?> <div class="alert alert-block" style="margin: 20px"> <button type="button" class="close" data-dismiss="alert"> × </button> <h4>警告!</h4> 发生错误了亲,您输入的城市好像没有找到哦! </div> <?php return; } $info = $weather["weatherinfo"]; ?> <table class="table table-striped table-bordered" style="margin-left: 20px;width: 200px"> <thead> <th>实时天气信息</th> </thead> <tbody> <?php echo "<tr><td>城市:</td><td>".$info["city"]."</td></tr>"; echo "<tr><td>城市ID:</td><td>".$info["cityid"]."</td></tr>"; echo "<tr><td>气温:</td><td>".$info["temp"]."℃</td></tr>"; echo "<tr><td>风向:</td><td>".$info["WD"]."</td></tr>"; echo "<tr><td>风力:</td><td>".$info["WS"]."</td></tr>"; echo "<tr><td>湿度:</td><td>".$info["SD"]."</td></tr>"; echo "<tr><td>更新时间:</td><td>".$info["time"]."</td></tr>"; ?> </tbody> </table> <?php } ?> </body> </html>
运行结果:
方法二:
1.可以不用文件,而是从天气网服务器动态获取城市名和ID:
当访问这个地址
服务器就会返还以下代码:
01|北京,02|上海,03|天津,04|重庆,05|黑龙江,06|吉林,07|辽宁,08|内蒙古,09|河北,10|山西,11|陕西,12|山东,13|新疆,14|西藏,15|青海,16|甘肃,17|宁夏,18|河南,19|江苏,20|湖北,21|浙江,22|安徽,23|福建,24|江西,25|湖南,26|贵州,27|四川,28|广东,29|云南,30|广西,31|海南,32|香港,33|澳门,34|台湾
2. 这时,我们就知道了省份的代码;城市的代码是在省份的基础上扩展的,知道省份代码是第一步;同时我们也知道了省份名,这样,做下拉框让用户选地区也很简单:
知道了省份我们要看这个省有些什么市,就需要依据省份代码来获取不同的文件了,例如云南是05,我们要获取云南所有州市的信息就要访问:
返回文本:
2901|昆明,2902|大理,2903|红河,2904|曲靖,2905|保山,2906|文山,2907|玉溪,2908|楚雄,2909|普洱,2910|昭通,2911|临沧,2912|怒江,2913|迪庆,2914|丽江,2915|德宏,2916|西双版纳
3.但是,这样还不够,我们还需要继续缩小范围,比如我们要知道大理州有哪些县级市和县,就需要继续访问:
果然,返回结果:
290201|大理,290202|云龙,290203|漾濞,290204|永平,290205|宾川,290206|弥渡,290207|祥云,290208|巍山,290209|剑川,290210|洱源,290211|鹤庆,290212|南涧
4.这时虽然可以找到所有城市名,但这个代码还不是最终的城市代码,所以还要再来一次,不如说要找宾川的代码:
290205|101290205
至此,读了四次,城市名和城市代码已获取到。
当然,解析数据也可以用Javascript来完成,但是由于Ajax不支持跨域名访问,所以将数据从中国天气网的服务器上获取到本地还需要一个简单服务器脚本来做代理,它的功能只是完成将请求的文件以字符串返还Javascript来做动态数据显示,所以:
首先要写一个读取字符串的php
getstr.php
<?php echo file_get_contents($_GET['url']); ?>
一个使用Ajax的js文件:
ajax.js
function Ajax(recvType) { var aj = new Object(); aj.recvType = recvType ? recvType.toUpperCase() : 'HTML'//HTML XML aj.targetUrl = ''; aj.sendString = ''; aj.resultHandle = null; aj.createXMLHttpRequest = function() { var request = false; //window对象中有XMLHttpRequest存在就是非IE,包括(IE7,IE8) if (window.XMLHttpRequest) { request = new XMLHttpRequest(); if (request.overrideMimeType) { request.overrideMimeType("text/xml"); } //window对象中有ActiveXObject属性存在就是IE } else if (window.ActiveXObject) { var versions = ['Microsoft.XMLHTTP', 'MSXML.XMLHTTP', 'Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP']; for (var i = 0; i < versions.length; i++) { try { request = new ActiveXObject(versions[i]); if (request) { return request; } } catch(e) { request = false; } } } return request; } aj.XMLHttpRequest = aj.createXMLHttpRequest(); aj.processHandle = function() { if (aj.XMLHttpRequest.readyState == 4) { if (aj.XMLHttpRequest.status == 200) { if (aj.recvType == "HTML") aj.resultHandle(aj.XMLHttpRequest.responseText); else if (aj.recvType == "XML") aj.resultHandle(aj.XMLHttpRequest.responseXML); } } } aj.get = function(targetUrl, resultHandle) { aj.targetUrl = targetUrl; if (resultHandle != null) { aj.XMLHttpRequest.onreadystatechange = aj.processHandle; aj.resultHandle = resultHandle; } if (window.XMLHttpRequest) { aj.XMLHttpRequest.open("get", aj.targetUrl); aj.XMLHttpRequest.send(null); } else { aj.XMLHttpRequest.open("get", aj.targetUrl, true); aj.XMLHttpRequest.send(); } } aj.post = function(targetUrl, sendString, resultHandle) { aj.targetUrl = targetUrl; if ( typeof (sendString) == "object") { var str = ""; for (var pro in sendString) { str += pro + "=" + sendString[pro] + "&"; } aj.sendString = str.substr(0, str.length - 1); } else { aj.sendString = sendString; } if (resultHandle != null) { aj.XMLHttpRequest.onreadystatechange = aj.processHandle; aj.resultHandle = resultHandle; } aj.XMLHttpRequest.open("post", targetUrl); aj.XMLHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); aj.XMLHttpRequest.send(aj.sendString); } return aj; }
网页部分代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script> <script src="http://libs.baidu.com/bootstrap/2.0.4/js/bootstrap.min.js"></script> <link href="http://libs.baidu.com/bootstrap/2.0.4/css/bootstrap.min.css" rel="stylesheet"/> <title>实时气温信息</title> <script type="text/javascript" src="./ajax.js"></script> <script type="text/javascript"> function str2Array(data) { data = data.replace(/\|/g, "\":\""); data = data.replace(/,/g, "\",\""); data = '({\"' + data + '\"})'; return eval(data); } function getProvince() { var ajax = Ajax(); ajax.get("getstr.php?url=http://m.weather.com.cn/data5/city.xml", function(data) { var arr = str2Array(data); var prov = document.getElementById("province"); for (var p in arr) { prov.options.add(new Option(arr[p], p)); } prov.options.selectedIndex = 0; getCity(prov.value); }); } function getCity(provId) { var ajax = Ajax(); ajax.get("getstr.php?url=http://m.weather.com.cn/data5/city" + provId + ".xml", function(data) { var arr = str2Array(data); var city = document.getElementById("city"); for (var i = city.options.length; i >= 0; i--) { city.remove(i); } for (var p in arr) { city.options.add(new Option(arr[p], p)); } getTown(city.value); }); } function getTown(provId) { var ajax = Ajax(); ajax.get("getstr.php?url=http://m.weather.com.cn/data5/city" + provId + ".xml", function(data) { var arr = str2Array(data); var town = document.getElementById("town"); for (var i = town.options.length; i >= 0; i--) { town.remove(i); } for (var p in arr) { town.options.add(new Option(arr[p], p)); } getCityId(); }); } function getCityId() { var ajax = Ajax(); var index = document.getElementById("town").value; ajax.get("getstr.php?url=http://m.weather.com.cn/data5/city" + index + ".xml", function(data) { var arr = str2Array(data); cityId = arr[index]; showWeather(cityId); }); } function insertTab(tab, cel1, cel2) { var newRow = tab.insertRow(tab.rows.length); var cell = newRow.insertCell(0); cell.innerHTML = cel1; var cell = newRow.insertCell(1); cell.innerHTML = cel2; } function showWeather(cityId) { if (cityId == null) { return; } var ajax = Ajax(); ajax.get("getstr.php?url=http://www.weather.com.cn/data/sk/" + cityId + ".html", function(data) { data = '(' + data + ')'; var info = eval(data)["weatherinfo"]; var tab = document.getElementById("weather"); var len = tab.rows.length; while(len-- > 0){ tab.deleteRow(len); } insertTab(tab, "城市:", info["city"]); insertTab(tab, "城市ID:", info["cityid"]); insertTab(tab, "气温:", info["temp"] + "℃"); insertTab(tab, "风向:", info["WD"]); insertTab(tab, "风力:", info["WS"]); insertTab(tab, "湿度:", info["SD"]); insertTab(tab, "更新时间:", info["time"]); }); } getProvince(); </script> <style type="text/css"> select { width: 100px; } </style> </head> <body> <div style="margin: 20px"> <legend> Weather </legend> <br> <select id="province" onchange="getCity(this.value)" ></select> <select id="city" onchange="getTown(this.value)" ></select> <select id="town" onchange="getCityId()" ></select> <br> <table id="weather" class="table table-striped table-bordered" style="width: 310px"></table> </div> </body> </html>
运行结果:
这样做下拉框中的数据可以动态从天气网的服务器中读取过来再动态加载,因此也不用自己做转换了。