Flex实现QQ网页提取天气信息

以前用C#实现了从QQ天气网页提取天气信息显示,最近了解Flex,随便测试了一下Flex版的QQ天气抓取,效果还不错。

1、预备知识

Flex是Adobe提供的基于Flash环境的RIA展现技术,主要采用MXML+Action Script来编写程序、界面,然后通过编译器编译成flash格式的SWF文件发布到网站上。

实现该功能需要安装Flex SDK,可以从Adobe网站上面下载,或者安装Flex Builder plugin+Eclipse来开发。

同时需要具备简单的正则表达式知识。

2、界面布局、代码实现

文件:QQWeather.mxml

 

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="213" height="234"  creationComplete="initApp()" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#F6FBFC, #3FEEDC]">
    
<mx:Style>
        .myfont{font-size:12pt;font-family:'宋体';}
    
</mx:Style>
    
<mx:Script source="QQWeather.as"></mx:Script>
    
<mx:Label x="10" y="53" text="选择城市:" styleName="myfont"/>
    
<mx:ComboBox id="cmbCity" x="66" y="49" width="133" rowCount="6" change="changeHandler(event);" styleName="myfont"></mx:ComboBox>
    
<mx:Image x="10" y="10" source="@Embed('../title.gif')" width="189" />
    
<mx:Image x="10" y="106" source="@Embed('../tem1.png')" width="57" height="13"/>
    
<mx:Image x="10" y="132" source="@Embed('../tem2.png')" width="57" height="13"/>
    
<mx:Image x="10" y="178" source="@Embed('../tem3.png')" width="57" height="13"/>
    
<mx:Image x="10" y="154" source="@Embed('../tem5.png')" width="57" height="13"/>
    
<mx:Label x="75" y="103.5" text="" width="110" styleName="myfont" id="t1"/>
    
<mx:Label x="75" y="129.5" text="" width="110" styleName="myfont" id="t2"/>
    
<mx:Label x="75" y="151.5" text="" width="110" styleName="myfont" id="t3"/>
    
<mx:Label x="75" y="175.5" text="" width="110" styleName="myfont" id="t4"/>
    
<mx:Label x="34" y="202" text="Label" width="169" styleName="myfont" textAlign="right" id="lbToday"/>
    
<mx:Label x="10" y="80" width="193" id="t0" styleName="myfont" fontWeight="normal"/>
    
</mx:Application>

 

后台脚本:QQWeather.as

 

 1 // ActionScript file
 2 import flash.events.Event;
 3 import flash.events.SecurityErrorEvent;
 4 
 5 import mx.collections.ArrayCollection;
 6 import mx.controls.Alert;
 7 import mx.utils.Base64Encoder;
 8 
 9 private var loader:URLStream;
10 private var htmldata:String;
11 private var ifloaded:Boolean=false;
12 private var dataUrl:String="http://weather.qq.com/inc/ss*.htm";
13 
14 public function initApp():void
15     var t:Date=new Date();
16     lbToday.text=t.fullYear+"-"+(t.month+1)+"-"+t.date+" "+t.hours+":"+t.minutes+":"+t.seconds;
17     loadUrl("125",parseCityInfo);
18 }
19 private function loadUrl(cityno:String,callback:Function):void{
20     loader= new URLStream();
21     loader.addEventListener(Event.COMPLETE, callback);
22     loader.addEventListener("securityError",onSecurityError );
23     var addr:String=dataUrl.replace(/\*/,cityno);
24     trace("Loading",addr);
25     var request:URLRequest = new URLRequest(addr);
26     //var enc:Base64Encoder=new Base64Encoder();
27     //enc.encodeUTFBytes(addr);
28     //var request:URLRequest = new URLRequest("http://localhost/httpproxy/webservlet?data="+enc.toString());
29     try {
30         loader.load(request);
31     } catch (error:Error) {
32         Alert.show("不能连接服务器:"+addr,"Tips");
33     }
34 }
35 private function onSecurityError(event:SecurityErrorEvent):void{
36     Alert.show("安全错误:"+event.text,"Tips");
37 }
38 private function parseCityInfo(event:Event):void {
39     var sm:URLStream=event.target as URLStream;
40     htmldata= sm.readMultiByte(sm.bytesAvailable, "gb2312"); 
41     trace("completeHandler: " + htmldata );
42     if(!ifloaded){
43         var pattern:RegExp =new RegExp("value=\"(\\d{1,3})\">([^<]*)</option>","g");
44         var result:Object = pattern.exec(htmldata);
45         var data:ArrayCollection = new ArrayCollection();
46         var item:Object;
47         while (result != null) {
48              trace(result[1],result[2]);
49              item=new Object();
50              item.label=result[2];
51              item.data=result[1];
52              data.addItem(item);
53              result = pattern.exec(htmldata);
54          }
55         cmbCity.dataProvider=data;
56         ifloaded=true;
57     }
58     parseWeather();
59 }
60 private function parseWeather():void{
61     //分析天气信息
62     var item:Object=cmbCity.selectedItem;
63     var pattern:RegExp =new RegExp("align=\"center\">([^<]*)</td>","g");
64     var result:Object = pattern.exec(htmldata);
65     var data:Array=new Array();
66     while (result != null) {
67         data.push(trimString(result[1]));
68         trace(result[1]);
69         result = pattern.exec(htmldata);
70     }
71     t0.text=item.label+":  "+data[0];
72     t1.text=data[1];
73     t2.text=data[2];
74     t3.text=data[3];
75     t4.text=data[4];
76 }
77 private function changeHandler(event:Event):void{
78     var item:Object=ComboBox(event.target).selectedItem;
79     trace(item.data);
80     loadUrl(item.data,parseCityInfo);
81 }
82 private function trimString(s:String):String{
83     return s.replace(/(^\s*)|(\s*$)/g, "");
84 }

 

 

用mxmlc命令编译之后,运行效果如下:

 

 

3、注意事项

根据flash的sandbox安全模型要求,A域名下的flash文件只能从A域名中获取服务端数据,如果需要从B域名中提取数据,需要B域名配置一个crossdomain.xml的文件,允许A从B

下载数据,但是我们不可能有这样的公关能力要求腾讯在http://weather.qq.com/下面放一个xml文件,允许其他网站访问,因此只能另辟蹊径:

方案1:A域名下自己实现一个代理,从B域名网页下载数据返回,这样就回避了sandbox的安全性错误,Line 26-28注释的代码就是我用java Servlet实现的一个代理。

方案2:建立代理服务器,例如squid或者Apache代理

方案3:采用adobe提供的开源软件bladeDS,该软件采用J2EE War方式发布,可以提供RPC、HTTP Proxy的代理功能

方案4:采用Adobe的企业级解决方案Adobe LiveCycle ES ,这个东西试用版就2.5G,真是庞然大物,受不了了,没见过这样的软件,一个Oracle数据库也就几百M而已,想不通。

 

posted @ 2008-08-02 10:42  在路上...  阅读(3705)  评论(8编辑  收藏  举报