我想用 webbrowser 寫一個簡單的抓資料程式
流程如下,按一個按鈕後
程式碼如下:
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.Collections;
using System.Threading;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//等待網頁讀取完成
public void loading()
{
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
}
//按鍵定義
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("http://localhost/member/index.php");
loading();
login();
Thread.Sleep(100);
webBrowser1.Navigate("http://localhost/member/member-search.php");
loading();
fill_data();
//試抓 2個 搜尋到的員工連結(這樣子寫,會造成搜尋結果出不來,上一行的 fill_data() 後會導到 simple_reulst.php
//如果將下面4行註解,simple_result.php 就會出來了,但是如果想要針對搜尋結果再去抓各個員工的細部資料不就沒辦法抓??
//webBrowser1.Navigate("http://localhost/member/data.php?iii=123456");
//loading();
//webBrowser1.Navigate("http://localhost/member/data.php?iii=654321");
//loading();
}
//自動登入
private void login()
{
HtmlDocument doc = webBrowser1.Document;
for (int i = 0; i < doc.All.Count; i++)
{
if (doc.All[i].TagName.ToUpper().Equals("INPUT"))
{
switch (doc.All[i].Name)
{
case "username":
doc.All[i].InnerText = "username";
break;
case "password":
doc.All[i].InnerText = "password";
//doc.All[i].Focus();
//SendKeys.SendWait("{Enter}");
break;
case "Submit":
doc.All[i].InvokeMember("click");
break;
}
}
}
}
//填寫資料
private void fill_data()
{
HtmlDocument doc = webBrowser1.Document;
for (int i = 0; i < doc.All.Count; i++)
{
if (doc.All[i].TagName.ToUpper().Equals("SELECT"))
{
switch (doc.All[i].Name)
{
case "searchcol":
doc.All[i].SetAttribute("value", "unit");
break;
}
}
else if (doc.All[i].TagName.ToUpper().Equals("INPUT"))
{
switch (doc.All[i].Name)
{
case "searchkeyword":
doc.All[i].InnerText = "07";
doc.All[i].Focus();
SendKeys.SendWait("{Enter}");
break;
}
}
}
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
richTextBox1.AppendText(webBrowser1.Url.ToString()+"\n");
}
}
}
目前遇到問題是
1.我只要在程式中寫成
webBrowser1.Navigate("http://localhost/member/index.php");
loading();
login();
Thread.Sleep(100);
webBrowser1.Navigate("http://localhost/member/member-search.php");
loading();
fill_data();
就可以看到最後的結果是正確的(有搜尋結果頁面)
simple_result.php
2.但是如果寫成下面這樣(我先模擬抓2個用戶的連結)
webBrowser1.Navigate("http://localhost/member/index.php");
loading();
login();
Thread.Sleep(100);
webBrowser1.Navigate("http://localhost/member/member-search.php");
loading();
fill_data();
webBrowser1.Navigate("http://localhost/member/data.php?iii=123456");
loading();
webBrowser1.Navigate("http://localhost/member/data.php?iii=654321");
loading();
會造成執行結果會跳過
simple_result.php
這個問題困擾多天
也請教過各路好漢解決過
目前還是沒有解決
還請各位幫忙了
謝謝大家
嗯...
webBrowser1.Navigate("http://localhost/member/data.php?iii=123456");
這個動作並不會等fill_data()在內嵌瀏覽器觸發的動作完成才執行阿...fill_data()觸發的動作是在內嵌的瀏覽器中跑,需要花一些時間,你的程式是在另外一個Thread跑,結果沒等瀏覽器的結果出來,你就跑下一行了阿。
你先插一個Thread.Sleep()進來測試一下看看,是否可以看到畫面。(最好設長一點,透過網路傳資料,時間比較難說)
回 fillano 大
我把 Thread.Sleep(10000);
插入到
fill_data();
的下一行
結果一樣沒有執行到這個 simple_result.php
_<
試了一下,發現WebBrowser內容運行跟form上其他元件都是在同一個Thread,所以在這裡使用Thread沒意義,只會暫停WebBrowser的運行。
在網路上看到有人實作簡單的SetTimeout方法,你可以用SetTimeout來設定幾秒之後才進行下一個動作。
「在這裡使用Thread沒意義」->應該是「在這裡使用Thread.Sleep()沒意義」
Thread只會暫停你現在的Webbrowser, 且在Form Application使用thread會使所有GUI介面元件暫停, 你 需要的是Task Wait, delay之類的function
private async void Form1_Shown(Object sender, EventArgs e){
deleteFiles();
writeTolog("Campgin Performance Report Operation on " + DateTime.Now);
Task<bool> UStask = getUSReport();
bool v = await UStask;
Environment.Exit(0);
writeTolog("");
}
private async Task<bool> getUSReport()
{
try
{
webBrowser1.Document.GetElementById("username").SetAttribute("value", "");
webBrowser1.Document.GetElementById("password").SetAttribute("value", "");
await Task.Delay(6000);
//webBrowser1.Document.GetElementById("sign-in-button").InvokeMember("click");
}