访问www.163.com,首页的栏目里有当地的天气预报。可以猜想,这里的天气预报,应该是根据来访者的ip判断其所在地给出当地的天气情况。问了一些朋友,也证实了这一点。项目里也需要天气预报这个小栏目,同事做过一个(从其他站点抓取的),不过实现不了根据IP显示当地的天气情况,需要用户自行选择,而且抓取的站点属于小站….其可靠性值得怀疑。。所以就萌生了抓取网易的天气预报的想法。。。对页面进行分析。。发现显示天气预报的区域是一个IFrameIFrame里嵌入了如下链接http://news.163.com/util/position1.html对这个地址访问直接跳转到另外一个链接http://news.163.com/weather/news/qx1/56294.html此链接显示了天气情况,

1.JPG

由此可以推测http://news.163.com/util/position1.html,是在根据来访者的IP判断所属区域,然后返回一个该地区所对应的区位码,如:56294代表成都。如何让网易来帮我们的站点来访者判断所属区域,并给出天气情况,并显示在自己的站点页面上呢?还得继续分析。。因为http://news.163.com/util/position1.html,此链接一访问就转向到天气情况的链接,而无法查看源码。便猜想。。此页面肯定有些东西。。无奈之下。。WebRequest一下,出现了如下代码:

<script language="Javascript">
var city = new Array("安徽","黑龙江","山东","北京","湖北","山西","福建","湖南","陕西","甘肃","吉林","上海","广东","江苏","四川","广西","江西","天津","贵州","辽宁","西藏","海南","内蒙古","新疆","河北","宁夏","云南","河南","青海","浙江","重庆");
var weaths = new Array('58321','50953','54823','54511','57494','53772','59134','57679','57036','52889','54172','58367','59287','58238','56294','59431','58606','54527','57816','54342','55591','52856','53463','51463','53698','53614','56778','57083','52866','58457','57516');

function getCookieVal (offset) {
  
var endstr = document.cookie.indexOf (";", offset);
  
if (endstr == -1)
  endstr 
= document.cookie.length;
  
return unescape(document.cookie.substring(offset, endstr));
}

function GetCookie (name) {
  
var arg = name + "=";
  
var alen = arg.length;
  
var clen = document.cookie.length;
  
var i = 0;
  
while (i < clen) {
    
var j = i + alen;
    
if (document.cookie.substring(i, j) == arg)
      
return getCookieVal (j);
    i 
= document.cookie.indexOf(" ", i) + 1;
    
if (i == 0)
       
break;
  }

  
return "";
}

function SetCookie(cookieName,cookieValue,nDays) {
 
var today = new Date();
 
var expire = new Date();
 
if (nDays==null || nDays==0) nDays=1;
 expire.setTime(today.getTime() 
+ 3600000*24*nDays);
 document.cookie 
= cookieName+"="+escape(cookieValue) + ";path=/;domain=.163.com;expires="+expire.toGMTString();
}

function getCityWeatherID(cityname){
    
for(i=0;i<city.length;i++){
    
if(city[i]==cityname){
        
return weaths[i];
        }

    }

    
return "54511";
}


var NTES_WeatherAddr = GetCookie("NTES_WeatherAddr");
if (!NTES_WeatherAddr){
    
var loc = GetCookie("theaddr");
    
if(!loc){
        document.write(
"<script type='text/javascript' src='http://202.108.39.152/ipquery'><" + "/script>");
    }

}

</script>
<script>
if (!NTES_WeatherAddr){
    NTES_WeatherAddr
=getCityWeatherID(loc);
}

window.location.href
="http://news.163.com/weather/news/qx1/"+NTES_WeatherAddr+".html";
</script>

 

上面的这段js实现了对来访者IP判断并给出了天气预报结果的链接。Js里的此链接: http://202.108.39.152/ipquery,起到的是判断用户所在地的作用,返回的是来访者所在地省份。分析到此,想要的结果差不多就出来了…

在客户端调用这段js获得天气预报结果的链接地址,然后交给服务端来处理。(为什么要交给后台处理,而不是直接显示呢?)因为直接得出的链接页面上,有多余的链接,还应用了样式(如图一),不便为自己所用,所以得处理掉。客户端调用服务端的方法很多,最初使用了Ajax框架Anthem,实现了过后,觉得有点杀鸡用牛刀的感觉。。无聊之余。。就又用CallBack实现了一次。。感觉恰到好处。。后来又发现。。__doPostBack也可以实现客户端调用服务端方法。。看来实现这么一个功能还真是简单。。。

好了到此就实现了,自己想要的结果:(感觉有点遗憾的是只给出了省会城市的天气预报)

2.JPG
前台页面代码Defaul.aspx:

  1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"  ResponseEncoding="GB2312" %>
  2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3<html xmlns="http://www.w3.org/1999/xhtml">
  4<head runat="server">
  5<title></title>
  6<script>
  7var city = new Array("安徽","黑龙江","山东","北京","湖北","山西","福建","湖南","陕西","甘肃","吉林","上海","广东","江苏","四川","广西","江西","天津","贵州","辽宁","西藏","海南","内蒙古","新疆","河北","宁夏","云南","河南","青海","浙江","重庆");
  8var weaths = new Array('58321','50953','54823','54511','57494','53772','59134','57679','57036','52889','54172','58367','59287','58238','56294','59431','58606','54527','57816','54342','55591','52856','53463','51463','53698','53614','56778','57083','52866','58457','57516');
  9
 10var NTES_WeatherAddr = GetCookie("NTES_WeatherAddr");
 11if (!NTES_WeatherAddr){
 12    var loc = GetCookie("theaddr");
 13    if(!loc){
 14        document.write("<script type='text/javascript' src='http://202.108.39.152/ipquery'><" + "/script>");
 15    }

 16}

 17
 18function getCookieVal (offset) {
 19  var endstr = document.cookie.indexOf (";", offset);
 20  if (endstr == -1)
 21  endstr = document.cookie.length;
 22  return unescape(document.cookie.substring(offset, endstr));
 23}

 24
 25function GetCookie (name) {
 26  var arg = name + "=";
 27  var alen = arg.length;
 28  var clen = document.cookie.length;
 29  var i = 0;
 30  while (i < clen) {
 31    var j = i + alen;
 32    if (document.cookie.substring(i, j) == arg)
 33      return getCookieVal (j);
 34    i = document.cookie.indexOf(" ", i) + 1;
 35    if (i == 0)
 36       break;
 37  }

 38  return "";
 39}

 40
 41function SetCookie(cookieName,cookieValue,nDays) {
 42 var today = new Date();
 43 var expire = new Date();
 44 if (nDays==null || nDays==0) nDays=1;
 45 expire.setTime(today.getTime() + 3600000*24*nDays);
 46 document.cookie = cookieName+"="+escape(cookieValue) + ";path=/;domain=.163.com;expires="+expire.toGMTString();
 47}

 48
 49//根据Ip服务器返回的省份名称获取对应的编号
 50function getCityWeatherID(cityname){
 51    for(i=0;i<city.length;i++){
 52    if(city[i]==cityname){
 53        return weaths[i];
 54        }

 55    }

 56    return "57816";
 57}

 58
 59//获取所在地天气预报结果的链接
 60function getWeatherUrl(){
 61if (!NTES_WeatherAddr){
 62    NTES_WeatherAddr=getCityWeatherID(loc);
 63
 64}

 65var addr="http://news.163.com/weather/news/qx1/"+NTES_WeatherAddr+".html";
 66document.form1.Text1.value=addr;
 67}

 68
 69//客户端调用服务端方法实现对天气预报结果链接的页面内容进行解析,Anthem实现方式
 70function showWeatherByAnthem() {
 71    Anthem_InvokePageMethod("ShowWeatherByAnthem", [], getServerResult);
 72}

 73
 74function getServerResult(result) {
 75    document.getElementById("result").innerHTML = result.value;
 76}

 77
 78//客户端调用服务端方法实现对天气预报结果链接的页面内容进行解析,_doPostBack实现方式
 79function showWeatherBylink()
 80{
 81    __doPostBack('LinkButton1','');
 82}

 83
 84//客户端调用服务端方法实现对天气预报结果链接的页面内容进行解析,CallBack实现方式
 85function showWeatherByCallBack()
 86{
 87    var context=document.getElementById("result");
 88    var weatherUrl=document.getElementById("Text1");
 89    var arg="ShowWeatherByCall|" + weatherUrl.value;
 90    <%= ClientScript.GetCallbackEventReference(this,"arg","outPutResult","context")%>;
 91}

 92function outPutResult(result)
 93{
 94   document.getElementById("result").innerHTML = result;
 95
 96}

 97
</script>
 98</head>
 99<body onload="getWeatherUrl(),showWeatherByCallBack()">
100    <form id="form1" runat="server">
101        <span id="result"></span>
102        <input id="Text1" type="hidden" runat="server" />
103    </form>
104</body>
105</html>

后台代码Default.cs:

 1using System;
 2using System.Data;
 3using System.Configuration;
 4using System.Web;
 5using System.Web.Security;
 6using System.Web.UI;
 7using System.Web.UI.WebControls;
 8using System.IO;
 9using System.Net;
10using Anthem;
11
12public partial class _Default : System.Web.UI.Page, ICallbackEventHandler
13{
14    protected void Page_Load(object sender, EventArgs e)
15    {
16        Anthem.Manager.Register(this);
17
18    }

19
20    回调的固定格式回调的固定格式 回调的固定格式
21    public string str_content;
22
23    public void RaiseCallbackEvent(string the_string)
24    {
25        str_content = the_string;
26    }

27
28    /**//// <summary>
29    /// 回调,解析客户端的参数
30    /// </summary>
31    /// <returns></returns>

32    public string GetCallbackResult()
33    {
34
35        string[] parts = str_content.Split('|');
36        object[] theArgList = new object[parts.Length - 1];
37        for (int int_index = 1; int_index < parts.Length; int_index++)
38            theArgList[int_index - 1= parts[int_index];
39        return (string)GetType().GetMethod(parts[0]).Invoke(this, theArgList);
40    }

41    #endregion

42
43    解析url的页面内容的方法体解析url的页面内容的方法体 解析url的页面内容的方法体
44    /**//// <summary>
45    /// Anthem方式,解析获取的url的页面内容
46    /// </summary>
47    /// <param name="url">url</param>
48    /// <returns>解析结果</returns>

49    [Anthem.Method]
50    public string ShowWeatherByAnthem()
51    {
52
53        WebRequest request = WebRequest.Create(Text1.Value);
54        request.Credentials = CredentialCache.DefaultCredentials;
55        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
56        Stream dataStream = response.GetResponseStream();
57        StreamReader reader = new StreamReader(dataStream, System.Text.Encoding.Default);
58        string str = reader.ReadToEnd();
59        return str.Substring(220);
60
61    }

62     //<summary>
63     //回调方式,解析获取的url的页面内容
64     //</summary>
65     //<param name="url"></param>
66     //<returns></returns>
67    public string ShowWeatherByCall(string url)
68    {
69        WebRequest request = WebRequest.Create(url);
70        request.Credentials = CredentialCache.DefaultCredentials;
71        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
72        Stream dataStream = response.GetResponseStream();
73        StreamReader reader = new StreamReader(dataStream, System.Text.Encoding.Default);
74        string str = reader.ReadToEnd();
75        return str.Substring(220);
76
77    }

78    #endregion


      客户端调用服务端的方法,__doPostBack方式,没有实现服务端的方法体,跟其余两种方式大致一样。当前是采用的CallBack方式调用服务端方法,如果想使用Anthem方式 ,更换onload里第二个function就可以了。