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控制的问题已经解决了,搞定后才发现好简单。
非常感谢蒋晟大虾的热情解答。我现在在搞分页的问题,对于分页你有没有什么好的建议?