现在的位置: 首页 > 综合 > 正文

如何自动登录网页并分析网页

2012年01月12日 ⁄ 综合 ⁄ 共 6304字 ⁄ 字号 评论关闭
如何自动登录网页并分析网页 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiNetwork/html/delphi_20061201105531222.html
带frame的php网站,利用webbrower  
   
  想实现自动登录并自动分析获取网页中的数据,该网页中的数据定时自动刷新。  
  见有利用IHTMLDocument2的方法,用Olevariant进行赋值;因为不知道网页上对应input、submit控件的名称,所以不知道可行否;我使用o:=wb.OleObject.document.all.tags('input',0);后,o.value:=xx的时侯抛异常,提示automation   object不支持value方法。  
  急~  
 

>不知道网页上对应input、submit控件的名称  
  view   source  
  o:=wb.OleObject.document.all.tags('input',0);后,o.value:=xx的时侯抛异常,提示automation   object不支持value方法。  
  document.all.tags   returns   a   collection.   you   should   locate   the   input   by   its   type,   location   or   style.  
 

还是不明白  
  如何获取带frame网页中的数据呢?是一个表单,可能有多页,php的网站

query   IHTMLWindow2   or   IWebBrowser2   from   the   frame   element

谢谢大虾的解答,但我的问题还没有解决,目前我已经实现遍历frame得到指定frame的页面源码。该页面中有一个表单,我想读取这个表单的内容,除了用字符串方法外,有没有什么用类似取element属性的方法可以得到表格中的数据?该表格有多页,有没有办法一次取得所有数据?  
  对于frame中相关页面的tagname我用以下方法进行遍历,发现取得的tagname值均为html,为什么?  
    doc:=Wb.document   as   IHtmlDocument2;    
    frameCol:=doc.frames;  
    for   i:=0   to   frameCol.Length-1   do  
    begin  
        vi:=i;  
        frame:=frameCol.Item(vi);  
        frame.QueryInterface(IID_IHTMLWindow2,framewin2);  
        if   LowerCase(framewin2.name)='frame1'   then  
        begin  
            mmo.Lines.Add(framewin2.document.body.innerHTML);  
            doc2:=framewin2.document   as   IHtmlDocument2;  
            for   j:=0   to   doc2.all.length-1   do  
            begin  
                _element:=   doc2.all.item(i,EmptyParam)   as   IHTMLElement;//估计是这句话的问题,但不知道如何改  
                mmo.Lines.Add(_element.tagname);  
            end;  
        end;

不要用IHTMLELEMENT,直播用OLEDOCUMENT,  
  我就是这样做的,   分析很畅快,而且不会出错

怎么做的,能不能给个例子?  
  我需要获取指定frame的table中的数据,最好是一次获取多页的数据  
  还有就是关于自动登录后,如何等待提交成功后页面的完成?

关注一下:)

1   query   IHTMLTable   from   IHTMLElement   if   the   tagname   is   "table"  
  2   handle   the   DocumentComplete   event

[CLSCompliant(false),   ComVisible(false)]  
  public   static   void   SaveTableByColumn(IHTMLTable   table,   StringDictionary   container)  
  {  
  if   (table   ==   null)  
  return;  
  if   (container   ==   null)  
  return;  
  foreach   (object   o   in   table.rows)  
  {  
  IHTMLTableRow   row   =   (IHTMLTableRow)o;  
  for   (int   j   =   0;   j   <   row.cells.length   /   2;   j++)  
  {  
  string   key   =   ((IHTMLElement)row.cells.item(j,   0)).innerText;  
  string   value   =   ((IHTMLElement)row.cells.item(j   +   1,   0)).innerText;  
  if   (key   !=   null   &&   value   !=   null)  
  {  
  key   =   key.Trim();  
  value   =   value.Trim();  
  if   (key.Length   >   0)  
  container.Add(key,   value);  
  }  
  }  
  }  
  }  
  [CLSCompliant(false),   ComVisible(false)]  
  public   static   List<IHTMLTable>   GetDescentsTables(IHTMLElement   htmlElement)  
  {    
  List<IHTMLTable>   tableList=new   List<IHTMLTable>();  
  if   (htmlElement==null)  
  return   tableList;  
  IHTMLElementCollection   formDescents   =   (IHTMLElementCollection)htmlElement.all;  
  foreach   (object   o   in   formDescents)  
  {  
  IHTMLElement   he   =   (IHTMLElement)o;  
  if   (he.tagName.ToLower().CompareTo("table")==0)  
  {  
  IHTMLTable   t   =   (IHTMLTable)he;  
  tableList.Add(t);  
  }  
  }  
  return   tableList;  
  }  
  [CLSCompliant(false),   ComVisible(false)]  
  public   static   List<IHTMLTable>   GetChildTables(IHTMLElement   htmlElement)  
  {  
  List<IHTMLTable>   tableList   =   new   List<IHTMLTable>();  
  if   (htmlElement   ==   null)  
  return   tableList;  
  IHTMLElementCollection   formChildren=   (IHTMLElementCollection)htmlElement.children;  
  foreach   (object   o   in   formChildren)  
  {  
  IHTMLElement   he   =   (IHTMLElement)o;  
  if   (he.tagName.ToLower().CompareTo("table")   ==   0)  
  {  
  IHTMLTable   t   =   (IHTMLTable)he;  
  tableList.Add(t);  
  }  
  }  
  return   tableList;  
  }

我试过在document   complete里判断,但不成功,第一个页面我可以用busy和ReadyState来判断(单个用好象也不很准)。我的程序第一个页面自动submit.click后,需要等待submit成功后转向的页面加载完成,这时用busy、Readystate等方法都不行,我也试过取title,但可能因为是frame的结构,也无法判断(有可能是我判断的方法不对)。  
   
  由于我不太清楚如何用post方法让网页返回所需要的指定页面(我用取到的url直接访问指定的数据页面时,网站直接跳到了登录页面,估计网站不是通过cookie来判断,有可能用session或refer方法来判断,如果有方法可以直接get或post到数据页面的话,就可以不用自动登陆的方法了,毕竟这个方法很费时间,而且受限制太多)所以我才走了这个弯路:从登陆页面开始由程序实现自动提交。网站的用户名和密码好象有加密,但加载数据的页面用的是用户名进行查询的,所以如果可以实现直接post或get,那么我只用通过登陆页面后取加密后的uid和pwd再直接get或post了(有时间抓个包研究加密过程后就可以直接get或post了)  
   
  对于你提供的代码我看不太懂,在参考一下资料后,我自己写了一个多框架中取table的方法,但在取table元素的地方写不下去了,不知道该怎么提取  
    doc:=WebBrowser.document   as   IHtmlDocument2;  
    frameCol:=doc.frames;  
    for   i:=0   to   frameCol.Length-1   do  
    begin  
        vi:=i;  
        frame:=frameCol.Item(vi);  
        frame.QueryInterface(IID_IHTMLWindow2,framewin2);  
        if   LowerCase(framewin2.name)='frametable'   then  
        begin  
            doc2:=framewin2.document   as   IHtmlDocument2;  
            _element:=doc2.get_all;  
            for   j:=0   to   doc2.all.length-1   do  
            begin  
                tbDisp:=_element.item(j,0);  
                if   SUCCEEDED(tbDisp.QueryInterface(IHTMLTable,HtmlTblEle))   then  
                with   HtmlTblEle   do  
                begin  
                    for   m:=0   to   HtmlTblEle.cols-1   do  
                    begin  
                        _element   :=HtmlTblEle.rows;  
                        for   n:=0   to   _element.length-1   do  
                        begin  
                            //如何将table内容输出?  
  //                           mmo.Lines.Add(_element.item(0,0));  
                        end;  
                    end;  
                end;  
 

取table的问题已经解决,多页的如何取呢?一定要一个个地取吗?有没有next之类的方法可用?再就是如何判断自动登陆后跳转到的页面加载完成

yes  
  you   have   to   detect   the   change   of   page   numbers  
 

table一个个地取没问题,只是不能做到实时了,如果对实时性要求较高就麻烦了  
   
  对于等待自动登陆后跳转到的页面加载完成,我实在是没什么好办法了,因为涉及到多frame,用documentcomplete不好使,目前我使用的是在这个事件中对frame进行count,到了指定的数字后就可以认为加载完了,不过虽然理论上是一个good   idea,但我还没测试成功   :(  
  不知道还有没有什么别的好方法?

check   ready   state

readystate我也试过,也不行,click之后直接就到了判断readystate,但此时,由于刚刚click,wb还没有跳转,此时的readystate还是第一个页面的,当然就认为ready了

我在click之后加了个1~1000的计数循环,然后再判断就ok了

check   ready   state   in   your   documentcomplete   handler   to   make   sure   ALL   frames   are   ready

在其它代码没有改动的情况下,我就在click之后加了个计数循环用ready和busy就可以正常判断了;而我使用documentcomplete对frames进行count时,却不管用

我用JAVA做过同样的东西.当时是为了抓取QQ天气,并可以根据提交的城市获取不同的天气情况,Delphi有同样的3rd控件,我曾经看过Demo,效果相当不错.做成论坛轰炸机都没有问题,呵呵.

3rd控件?能否详细告之

楼主使用DOM的方法来获得表格内容,我认为不是一个好办法。费时费事不说,而且效率底下。  
   
  比较高效的做法是:直接读取整个页面的HTML,然后使用规则表达式,获取页面中符合条件的代码片断。这样做比DOM高效N倍。  
   
  对于分页的问题,估计没有什么好办法。唯一可行的就是获得“下一页”的地址,然后循环读取页面。

tttk大虾所提到的dom方法的意思是什么  
  为了能和页面进行交互,目前我只能想到加载页面并用shtml的方法对页面进行控制  
  还请tttk大虾多多指点

自己分析页面获得当前页码和是否是最后一页……

我现在要做的并不只是分析网页内容,而且要在满足条件后与页面进行交互,这个交互过程是完全自动的。所以取得页面的element,然后在满足条件后对element进行控制,我想这应该是唯一可行的办法。  
   
  IHTMLTable2好象有FirstPage、LastPage的属性,但没有见到有NextPage的属性,如果有此属性或许就只用一个nextpage方法就ok了,分页功能的实现是由数据访问层来控制的吧?  
   
  目前还有个麻烦,就是控制的问题,现在我已经可以用嵌套循环取得某个特定frame中的element的属性,而对其控制的话我现在只找到了这样的方法:WB.oleobject.document.documentelement.document.frames.item(0).document.all.item('name',0),也就是说得先把该element所在的frame序数找出来,然后再套这个式子;然而,如果这个frame序数是根据条件变化的,就麻烦了。我想在用循环遍历找到特定的element之后,能够直接对该element进行交互。

用for   each循环,判断frame的URL,input的ID,Table的表头之类的特征值

循环遍历后直接对取得的element控制的问题已经解决了,搞定后才发现好简单。  
   
  非常感谢蒋晟大虾的热情解答。我现在在搞分页的问题,对于分页你有没有什么好的建议?

抱歉!评论已关闭.