訪問www.163.com,首頁的欄目裡有當地的天氣預報。可以猜想,這裡的天氣預報,應該是根據來訪者的ip判斷其所在地給出當地的天氣情況。問了一些朋友,也證實了這一點。項目裡也需要天氣預報這個小欄目,同事做過一個(從其他站點抓取的),不過實現不了根據IP顯示當地的天氣情況,需要用戶自行選擇,而且抓取的站點屬於小站….其可靠性值得懷疑。。所以就萌生了抓取網易的天氣預報的想法。。。對頁面進行分析。。發現顯示天氣預報的區域是一個IFrame,IFrame裡嵌入了如下鏈接http://news.163.com/util/position1.html, 對這個地址訪問直接跳轉到另外一個鏈接http://news.163.com/weather/news/qx1/56294.Html,此鏈接顯示了天氣情況,如圖:

由此可以推測http://news.163.com/util/position1.html,是在根據來訪者的IP判斷所屬區域,然後返回一個該地區所對應的區位碼,如: 56294代表成都。如何讓網易來幫我們的站點來訪者判斷所屬區域,並給出天氣情況,並顯示在自己的站點頁面上呢?還得繼續分析。。因為http://news.163.com/util/position1.Html,此鏈接一訪問就轉向到天氣情況的鏈接,而無法查看源碼。便猜想。。此頁面肯定有些東西。。無奈之下。。WebRequest一下,出現了如下代碼:

以下是引用片段:

1<script language="Javascript">

2var city = new Array("安徽","黑龍江","山東","北京","湖北","山西","福建","湖南","陝西","甘肅","吉林","上海","廣東","江蘇","四川","廣西","江西","天津","貴州","遼寧","西藏","海南","內蒙古","新疆","河北","寧夏","雲南","河南","青海","浙江","重慶");

3var 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'');

4


5function getCookIEVal (offset) ...{

6 var endstr = document.cookIE.indexOf (";", offset);

7 if (endstr == -1)

8 endstr = document.cookIE.length;

9 return unescape(document.cookIE.substring(offset, endstr));

10}


11function GetCookIE (name) ...{

12 var arg = name + "=";

13 var alen = arg.length;

14 var clen = document.cookIE.length;

15 var i = 0;

16 while (i < clen) ...{

17 var j = i + alen;

18 if (document.cookIE.substring(i, j) == arg)

19 return getCookIEVal (j);

20 i = document.cookIE.indexOf(" ", i) + 1;

21 if (i == 0)

22 break;

23 }

24 return "";

25}


26function SetCookie(cookieName,cookIEValue,nDays) ...{

27 var today = new Date();

28 var expire = new Date();

29 if (nDays==null || nDays==0) nDays=1;

30 expire.setTime(today.getTime() + 3600000*24*nDays);

31 document.cookie = cookieName+"="+escape(cookIEValue) + ";path=/;domain=.163.com;expires="+expire.toGMTString();

32}


33function getCityWeatherID(cityname)...{


34 for(i=0;i<city.length;i++)...{

35 if(city[i]==cityname)...{

36 return weaths[i];

37 }

38 }

39 return "54511";

40}

41

42var NTES_WeatherAddr = GetCookIE("NTES_WeatherAddr");


43if (!NTES_WeatherAddr)...{

44 var loc = GetCookIE("theaddr");


45 if(!loc)...{

46 document.write("<script type=''text/Javascript'' src=''http://202.108.39.152/ipquery''><" + "/script>");

47 }

48}

49</script>

50<script>


51if (!NTES_WeatherAddr)...{

52 NTES_WeatherAddr=getCityWeatherID(loc);

53}

54window.location.href="http://news.163.com/weather/news/qx1/"+NTES_WeatherAddr+".Html";

55</script>

56

57
上面的這段js實現了對來訪者IP判斷並給出了天氣預報結果的鏈接。JS裡的此鏈接: http://202.108.39.152/ipquery,起到的是判斷用戶所在地的作用,返回的是來訪者所在地省份。分析到此,想要的結果差不多就出來了…
在客戶端調用這段JS獲得天氣預報結果的鏈接地址,然後交給服務端來處理。(為什麼要交給後台處理,而不是直接顯示呢?)因為直接得出的鏈接頁面上,有多余的鏈接,還應用了樣式(如圖一),不便為自己所用,所以得處理掉。客戶端調用服務端的方法很多,最初使用了AJax框架Anthem,實現了過後,覺得有點殺雞用牛刀的感覺。。無聊之余。。就又用CallBack實現了一次。。感覺恰到好處。。後來又發現。。__doPostBack也可以實現客戶端調用服務端方法。。看來實現這麼一個功能還真是簡單。。。
好了到此就實現了,自己想要的結果:(感覺有點遺憾的是只給出了省會城市的天氣預報)

前台頁面代碼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>

106

後台代碼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 回調的固定格式回調的固定格式#region 回調的固定格式

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的頁面內容的方法體#region 解析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

79}

80