多線程處理webbrowser的相關(guān)問(wèn)題,并解決觸發(fā)click事件,js無(wú)響應(yīng)問(wèn)題。
近剛好碰上一個(gè)需求:循環(huán)遍歷網(wǎng)頁(yè)元素,找到innerText為指定的內(nèi)容時(shí),就模擬人工點(diǎn)擊。
解決辦法:使用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 == "測(cè)試")
{
em.InvokeMember("click");//"觸發(fā)點(diǎn)擊事件"
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
有一點(diǎn)沒(méi)說(shuō)到,上面的只適合單線程的,如果執(zhí)行以上代碼的是在新開辟的一個(gè)線程中的話,會(huì)碰到一系列的問(wèn)題......(很遺憾,我沒(méi)有將那些問(wèn)題記錄下來(lái),但相信如果你跟我有著同樣的需求的話,即采用多線程的方式處理webbrowser加載的網(wǎng)頁(yè)內(nèi)容的話,可以繼續(xù)看下去,也許對(duì)你有所幫助)
網(wǎng)上一搜,關(guān)于webbrowser在多線程中的使用著實(shí)會(huì)碰到很多問(wèn)題……后來(lái),經(jīng)過(guò)自己不斷的Google(在這過(guò)程中你能體會(huì)到百度離Google還有多遠(yuǎn)),有找到了幾篇對(duì)我有所幫助的文章:
關(guān)于線程的知識(shí):http://www.cnblogs.com/JimmyZheng/archive/2012/06/10/2543143.html
WebBrowser多線程帶來(lái)的麻煩:http://www.cnblogs.com/xjfhnsd/archive/2010/03/14/1685441.html
WebBrowser 顯示Html內(nèi)容3點(diǎn)細(xì)節(jié)技巧: http://www.cnblogs.com/cyq1162/archive/2012/03/27/2419655.html
接著,我就使用webclient配合webbrowser從而順利的解決了問(wèn)題。
WebClient:下載指定網(wǎng)址的源碼
WebBrowser:navigate一個(gè)空白頁(yè)(具體參考:)
注:這里的WebBrowser要從代碼中new,如果是拉控件的方式創(chuàng)建的,將會(huì)報(bào)錯(cuò):"指定的轉(zhuǎn)換無(wú)效"
這里我就寫一個(gè)以上列出的文章所沒(méi)有提到的。
比如,我們要click的網(wǎng)頁(yè)元素是通過(guò)js來(lái)觸發(fā)的,而使用webclient只能下載指定的url的網(wǎng)頁(yè)源碼,無(wú)法自動(dòng)加載相關(guān)的js,因此導(dǎo)致在使用invokeMember("click")的時(shí)候,沒(méi)能見(jiàn)到預(yù)期效果。
解決辦法:將指定的js文件也下載下來(lái)(或者將需要用到的js方法放到本地,使用webclient 載入進(jìn)來(lái)也行)
我這里說(shuō)的只是一個(gè)大題的思路和解決途徑
后,貼上一段測(cè)試代碼:
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);//在線程啟動(dòng)前設(shè)置其單元狀態(tài)
td.Start("http://127.0.0.1/test.html");
}
private void loadPage(object URL)
{
try
{
string url = (string)URL;
WebBrowser browser = new WebBrowser();//當(dāng)前線程不在單線程單元中,因此無(wú)法實(shí)例化 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) //報(bào)錯(cuò)“指定的轉(zhuǎn)換無(wú)效”
// 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 == "點(diǎn)擊")
{
em.InvokeMember("click");//alert("觸發(fā)點(diǎn)擊事件")
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
//MessageBox.Show("當(dāng)前執(zhí)行線程:"+Thread.CurrentThread.Name);
}
}
//WebClient取網(wǎng)頁(yè)源碼
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()">點(diǎn)擊</a>
</body>
</html>
js:
<script type="text/javascript">
function t()
{
alert('ddd');
}
</script>