求救!用HtmlElement来模拟事件(InvokeMember)不成功,为何???

jacksoncan 2012-08-20 10:02:58
有这样一个网页:

http://stock.finance.sina.com.cn/hkstock/finance/01398.html

现在要将“资产负债表”的“年报”数据自动抓取出来,需要先引发右边“报表类型”选择按钮的onchange事件,使得数据由原来的全部类型变成只是年报的,我用HtmlElement来模拟事件(InvokeMember),但是却不成功,也就是页面的数据没有发生任何改变,请问高手们,这是为什么呢?代码如下:



private void btn模拟事件_Click(object sender, EventArgs e)
{
string url = "http://stock.finance.sina.com.cn/hkstock/finance/01398.html";

webBrowser1.Navigate(url);
}


private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{



//避免webbroswer.DocumentCompleted被多次引发
if ((e.Url != webBrowser1.Url) || (webBrowser1.ReadyState != WebBrowserReadyState.Complete))
return;
//下面写你要在页面加载完毕后执行的代码。

getSelectedCtrl();

}

private void getSelectedCtrl()
{
System.Windows.Forms.HtmlDocument doc = this.webBrowser1.Document;
System.Windows.Forms.HtmlElementCollection selectCtrls = doc.GetElementsByTagName("select");
string attName;

foreach (System.Windows.Forms.HtmlElement selectCtrl in selectCtrls)
{
attName = selectCtrl.GetAttribute("table");
if (attName.Equals("tableGetBalanceSheet"))//如果table属性是资产负债表的话,模拟引发“报表类型”的选择控件
{
//调试过,已经成功进入了该条件语句
// 准备参数.
Object[] args = new Object[1];
args[0] = (Object)"zero"; //zero代表报表类型为“年报”
selectCtrl.InvokeMember("onchange",args);
return;

}

}

}


...全文
865 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
intken008 2012-09-05
  • 打赏
  • 举报
回复
大神啊!收我为徒吧!!

看了你的贴,解决了一个困扰我已久的问题。。。
jacksoncan 2012-08-23
  • 打赏
  • 举报
回复
大神,您真是太厉害了,真是太感谢您了!!!

[Quote=引用 9 楼 的回复:]

没有仔细看你的代码,我写了一个,是可以的。你需要找个适当的时候停止timer就可以了。


GetData基本和你的一样,除了在函数内部取得doucment
C# code

private void getData()
{
HtmlDocument doc = webBrowser1.Document;
……
[/Quote]
宝_爸 2012-08-23
  • 打赏
  • 举报
回复
没有仔细看你的代码,我写了一个,是可以的。你需要找个适当的时候停止timer就可以了。


GetData基本和你的一样,除了在函数内部取得doucment

private void getData()
{
HtmlDocument doc = webBrowser1.Document;
。。。。。


其它部分:


System.Timers.Timer timer = null;

private void Form1_Load(object sender, EventArgs e)
{
string url = "http://stock.finance.sina.com.cn/hkstock/finance/01398.html";

webBrowser1.Navigate(url);
timer = new System.Timers.Timer(1000);
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);

}

public delegate void GetDataHandler();

private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
Invoke(new GetDataHandler(getData));

timer.Start();
}


private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//避免webbroswer.DocumentCompleted被多次引发
if ((e.Url != webBrowser1.Url) || (webBrowser1.ReadyState != WebBrowserReadyState.Complete))
return;
//下面写你要在页面加载完毕后执行的代码。

getSelectedCtrl();
}

private void getSelectedCtrl()
{
System.Windows.Forms.HtmlDocument doc = this.webBrowser1.Document;
System.Windows.Forms.HtmlElementCollection selectCtrls = doc.GetElementsByTagName("select");
string attName;

foreach (System.Windows.Forms.HtmlElement selectCtrl in selectCtrls)
{
attName = selectCtrl.GetAttribute("table");
if (attName.Equals("tableGetBalanceSheet"))//如果table属性是资产负债表的话,模拟引发“报表类型”的选择控件
{
foreach(HtmlElement option in selectCtrl.Children)
{
if(option.GetAttribute("value") == "zero")
{
option.SetAttribute("selected", "selected");
break;
}
}
selectCtrl.RaiseEvent("onchange");
timer.Start();
return;

}

}

}

宝_爸 2012-08-22
  • 打赏
  • 举报
回复
另一个方法值得一试的是直接 call javascript的方法

object result = this.Browser.InvokeScript("showOverlay", false);
但是不确定是同步的还是异步的,如果是异步的,也得设个timer等。

参考
Calling JavaScript functions in the Web Browser Control
http://www.west-wind.com/weblog/posts/2008/Sep/27/Calling-JavaScript-functions-in-the-Web-Browser-Control
宝_爸 2012-08-22
  • 打赏
  • 举报
回复
今天比较忙,你自己解决下试一试

google下没有什么好办法,只能等待一会,知道刷新后,新的的element的id出来。
不能用sleep,要用个timer.
就是启动个timer. 检测某个ID是否出现,如果出现,取得数据,如果不出现,继续等下一个internal event.

参考:
http://stackoverflow.com/questions/3794522/waiting-for-webbrowser-ajax-content

牛人Sheng Jiang 蒋晟 在里面回答了:)
  • 打赏
  • 举报
回复
在点击后当然要取得最新的网页了,不然就不能获取 到现在点击后的数据的
jacksoncan 2012-08-22
  • 打赏
  • 举报
回复
非常感谢大神您的帮助啊,不过我感觉这个好像不是等待的问题,因为我用timer控件试了一下,抓出来的数据还是原来的呀。(代码如下,不知道是否写错了,我是菜鸟,汗),另外,我后来又用手动选择了“报表类型”,等网页的数据变成了年报的数据后再打开源文件查看,发现里面的数据也是原来一样的,没有变化,这是否说明这根本就不是等待的问题呢?麻烦大神您有空的话能帮我再看看吗?不着急,只要能解决就行,不胜感激啊。





private void getSelectedCtrl()
{
System.Windows.Forms.HtmlDocument doc = this.webBrowser1.Document;
System.Windows.Forms.HtmlElementCollection selectCtrls = doc.GetElementsByTagName("select");
string attName;

foreach (System.Windows.Forms.HtmlElement selectCtrl in selectCtrls)
{
attName = selectCtrl.GetAttribute("table");
if (attName.Equals("tableGetBalanceSheet"))//如果table属性是资产负债表的话,模拟引发“报表类型”的选择控件
{
//this.richTextBox1.Text = selectCtrl.InnerText;
// 准备参数.
//Object[] args = new Object[1];
//args[0] = (Object)"zero"; //zero代表报表类型为“年报”
//selectCtrl.InvokeMember("onchange",args);
//return;

foreach (HtmlElement option in selectCtrl.Children)
{
if (option.GetAttribute("value") == "zero")
{
option.SetAttribute("selected", "selected");
break;
}
}
selectCtrl.RaiseEvent("onchange");




timer1.Interval = 5000; //5秒间隔
timer1.Start(); // 计时开始


getData(selectCtrl.Document);//引发事件成功后抓取数据
return;


}

}



}

private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();

}



[Quote=引用 4 楼 的回复:]

太感谢您了,大神,引发事件成功了!!!
不过,引发事件成功后运行的getData()抓取数据抓出来的怎么还是原来未筛选的数据呢?烦请大神帮我再看一下哪里出问题了,可以吗?非常感谢啊!


C# code


private void getSelectedCtrl()
{
System.Windows.Forms.HtmlDocument do……
[/Quote]
宝_爸 2012-08-21
  • 打赏
  • 举报
回复
我修改后的版本,测试过了


private void getSelectedCtrl()
{
System.Windows.Forms.HtmlDocument doc = this.webBrowser1.Document;
System.Windows.Forms.HtmlElementCollection selectCtrls = doc.GetElementsByTagName("select");
string attName;

foreach (System.Windows.Forms.HtmlElement selectCtrl in selectCtrls)
{
attName = selectCtrl.GetAttribute("table");
if (attName.Equals("tableGetBalanceSheet"))//如果table属性是资产负债表的话,模拟引发“报表类型”的选择控件
{
//调试过,已经成功进入了该条件语句
// 准备参数.
//Object[] args = new Object[1];
//args[0] = (Object)"zero"; //zero代表报表类型为“年报”
//selectCtrl.InvokeMember("onchange", args);
foreach(HtmlElement option in selectCtrl.Children)
{
if(option.GetAttribute("value") == "zero")
{
option.SetAttribute("selected", "selected");
break;
}
}
selectCtrl.RaiseEvent("onchange");
return;

}

}

}
jacksoncan 2012-08-21
  • 打赏
  • 举报
回复
太感谢您了,大神,引发事件成功了!!!
不过,引发事件成功后运行的getData()抓取数据抓出来的怎么还是原来未筛选的数据呢?烦请大神帮我再看一下哪里出问题了,可以吗?非常感谢啊!




private void getSelectedCtrl()
{
System.Windows.Forms.HtmlDocument doc = this.webBrowser1.Document;
System.Windows.Forms.HtmlElementCollection selectCtrls = doc.GetElementsByTagName("select");
string attName;

foreach (System.Windows.Forms.HtmlElement selectCtrl in selectCtrls)
{
attName = selectCtrl.GetAttribute("table");
if (attName.Equals("tableGetBalanceSheet"))//如果table属性是资产负债表的话,模拟引发“报表类型”的选择控件
{
//this.richTextBox1.Text = selectCtrl.InnerText;
// 准备参数.
//Object[] args = new Object[1];
//args[0] = (Object)"zero"; //zero代表报表类型为“年报”
//selectCtrl.InvokeMember("onchange",args);
//return;

foreach (HtmlElement option in selectCtrl.Children)
{
if (option.GetAttribute("value") == "zero")
{
option.SetAttribute("selected", "selected");
break;
}
}
selectCtrl.RaiseEvent("onchange");
getData(doc);//引发事件成功后抓取数据
return;


}

}



}


private void getData(HtmlDocument doc)
{


StringBuilder str = new StringBuilder();


//System.Windows.Forms.HtmlDocument doc = this.webBrowser1.Document;
System.Windows.Forms.HtmlElement table = doc.GetElementById("tableGetBalanceSheet");//获取资产负债表
System.Windows.Forms.HtmlElementCollection trs;//行的集合
System.Windows.Forms.HtmlElementCollection ths;//项目的集合
System.Windows.Forms.HtmlElementCollection tds;//单元格的集合
int i = 0;//用于行的计数
int j = 0;//用于单元格的计数
int k = 0;//用于年报单元格的计数
this.dataGridView1.Rows.Clear();//清除表的所有行
this.dataGridView1.Columns.Clear();//清除表的列

//获取行集合并遍历之
trs = table.GetElementsByTagName("tr");
foreach (System.Windows.Forms.HtmlElement tr in trs)
{
i++;

//获取项目列的单元格集合并遍历之
ths = tr.GetElementsByTagName("th");
foreach (System.Windows.Forms.HtmlElement th in ths)
{
k++;
if (i == 1)
{
this.dataGridView1.Columns.Add(th.InnerText, th.InnerText);//添加项目列

}

this.dataGridView1.Rows.Add();
this.dataGridView1.Rows[this.dataGridView1.Rows.Count-2].Cells[0].Value=th.InnerText;//填充项目数据


}

//获取普通数据列的单元格并遍历之
tds = tr.GetElementsByTagName("td");
j = 0;
foreach (System.Windows.Forms.HtmlElement td in tds)
{
j++;

str.Append(td.InnerText + " ");

if (i == 1)
{
this.dataGridView1.Columns.Add(td.InnerText, td.InnerText);//添加普通列

}
this.dataGridView1.Rows[this.dataGridView1.Rows.Count - 2].Cells[j].Value = td.InnerText;//填充财务数据


}
str.Append("\n");



}



this.richTextBox1.Text = str.ToString();





}


jacksoncan 2012-08-21
  • 打赏
  • 举报
回复
没有人会吗?
jacksoncan 2012-08-20
  • 打赏
  • 举报
回复
有没有人知道?应该是个挺简单的问题呀,高手们

111,098

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧