多线程处理webbrowser的相关问题,并解决触发click事件,js无响应问题。
近刚好碰上一个需求:循环遍历网页元素,找到innerText为指定的内容时,就模拟人工点击。
解决办法:使用WebBrowser将指定位置的文档加载到 WebBrowser 控件中(注:这里的webbrowser是在拉控件的方式,而不是直接在代码中new)
源码如下:
private void loadPage(object URL)
{
try
{
string url = (string)URL;
browser.Navigate(url);
while (true)
{
Application.DoEvents();
if(browser.ReadyState != WebBrowserReadyState.Complete)
{
break;
}
}
HtmlDocument document = browser.Document;
HtmlElementCollection elems = browser.Document.GetElementsByTagName("a");
foreach (HtmlElement em in elems)
{
if (em.InnerText == "测试")
{
em.InvokeMember("click");//"触发点击事件"
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
有一点没说到,上面的只适合单线程的,如果执行以上代码的是在新开辟的一个线程中的话,会碰到一系列的问题......(很遗憾,我没有将那些问题记录下来,但相信如果你跟我有着同样的需求的话,即采用多线程的方式处理webbrowser加载的网页内容的话,可以继续看下去,也许对你有所帮助)
网上一搜,关于webbrowser在多线程中的使用着实会碰到很多问题……后来,经过自己不断的Google(在这过程中你能体会到百度离Google还有多远),有找到了几篇对我有所帮助的文章:
关于线程的知识:http://www.cnblogs.com/JimmyZheng/archive/2012/06/10/2543143.html
WebBrowser多线程带来的麻烦:http://www.cnblogs.com/xjfhnsd/archive/2010/03/14/1685441.html
WebBrowser 显示Html内容3点细节技巧: http://www.cnblogs.com/cyq1162/archive/2012/03/27/2419655.html
接着,我就使用webclient配合webbrowser从而顺利的解决了问题。
WebClient:下载指定网址的源码
WebBrowser:navigate一个空白页(具体参考:)
注:这里的WebBrowser要从代码中new,如果是拉控件的方式创建的,将会报错:"指定的转换无效"
这里我就写一个以上列出的文章所没有提到的。
比如,我们要click的网页元素是通过js来触发的,而使用webclient只能下载指定的url的网页源码,无法自动加载相关的js,因此导致在使用invokeMember("click")的时候,没能见到预期效果。
解决办法:将指定的js文件也下载下来(或者将需要用到的js方法放到本地,使用webclient 载入进来也行)
我这里说的只是一个大题的思路和解决途径
后,贴上一段测试代码:
C#源码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Net;
namespace webbrowser控件
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
ParameterizedThreadStart pt;
pt = new ParameterizedThreadStart(loadPage);
Thread td = new Thread(pt);
td.Name = "主线程";
td.SetApartmentState(ApartmentState.STA);//在线程启动前设置其单元状态
td.Start("http://127.0.0.1/test.html");
}
private void loadPage(object URL)
{
try
{
string url = (string)URL;
WebBrowser browser = new WebBrowser();//当前线程不在单线程单元中,因此无法实例化 ActiveX 控件
browser.ScriptErrorsSuppressed = true;
//browser.Navigate(url);
//browser.DocumentCompleted += browser_DocumentCompleted;
browser.Navigate("about:blank");
string htmlcode = GetHtmlSource(url);
string js = GetHtmlSource("http://127.0.0.1/MY/test/js.html");//载入js
browser.Document.Write(js);
textBox1.Text = htmlcode;
//while (browser.ReadyState != WebBrowserReadyState.Complete) //报错“指定的转换无效”
// Application.DoEvents();
browser.Document.Write(htmlcode);
//MessageBox.Show(browser.DocumentText);
HtmlDocument document = browser.Document;
HtmlElementCollection elems = browser.Document.GetElementsByTagName("a");
foreach (HtmlElement em in elems)
{
if (em.InnerText == "点击")
{
em.InvokeMember("click");//alert("触发点击事件")
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
//MessageBox.Show("当前执行线程:"+Thread.CurrentThread.Name);
}
}
//WebClient取网页源码
private string GetHtmlSource(string Url)
{
string text1 = "";
try
{
WebClient wc = new WebClient();
text1 = wc.DownloadString(Url);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return text1;
}
}
}
test.html:
<html>
<head>
<title></title>
<script type="text/javascript" src="a.js"></script>
</head>
<body>
<a href="javascript:void();" onclick="t()">点击</a>
</body>
</html>
js:
<script type="text/javascript">
function t()
{
alert('ddd');
}
</script>