在WebBrowser中打开多个页面并向所有页面发送命令

时间:2015-03-10 20:52:29

标签: c# winforms visual-studio

我有一个具有以下功能的winform应用程序:

  1. 有一个多行文本框,每行包含一个网址 - 大约30个网址(每个网址不同但网页相同(只是网址不同);
  2. 我有另一个文本框,我可以在其中编写一个命令和一个按钮,将该命令发送到来自网页的输入字段
  3. 我有一个WebBrowser控制器(我想在一个控制器中执行所有操作)
  4. 网页包含一个文本框和一个按钮,我想在该文本框中插入命令后点击该按钮。

    到目前为止我的代码:

    //get path for the text file to import the URLs to my textbox to see them
    private void button1_Click(object sender, EventArgs e)
    {
        OpenFileDialog fbd1 = new OpenFileDialog();
        fbd1.Title = "Open Dictionary(only .txt)";
        fbd1.Filter = "TXT files|*.txt";
        fbd1.InitialDirectory = @"M:\";
        if (fbd1.ShowDialog(this) == DialogResult.OK)
            path = fbd1.FileName;
    }
    
    //import the content of .txt to my textbox
    private void button2_Click(object sender, EventArgs e)
    {
        textBox1.Lines = File.ReadAllLines(path);
    }
    
    //click the button from webpage
    private void button3_Click(object sender, EventArgs e)
    {
        this.webBrowser1.Document.GetElementById("_act").InvokeMember("click");
    }
    
    //parse the value of the textbox and press the button from the webpage
    private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        newValue = textBox2.Text;
        HtmlDocument doc = this.webBrowser1.Document;
        doc.GetElementById("_cmd").SetAttribute("Value", newValue);     
    }
    

    现在,如何在同一个web控制器中添加我文本框中的所有30个URL,以便我可以将相同的命令发送到所有网页的所有文本框,然后按下所有这些文本框的按钮?


    //编辑1 所以,我改编了@Setsu方法,并且我创建了以下内容:

    public IEnumerable<string> GetUrlList()
    {
        string f = File.ReadAllText(path); ;
        List<string> lines = new List<string>();
    
        using (StreamReader r = new StreamReader(f))
        {
            string line;
            while ((line = r.ReadLine()) != null)
                lines.Add(line);
        }
        return lines;
    }
    

    现在,为了解析每个URL,这会返回它应返回的内容吗?

1 个答案:

答案 0 :(得分:1)

如果您只想继续使用1个WebBrowser控件,则必须按顺序导航到每个URL。但请注意,WebBrowser类的Navigate方法是异步的,因此您无法在循环中天真地调用它。您最好的办法是实现此答案here中详述的异步/等待模式。

或者,您可以拥有30个WebBrowser控件,并且每个控件都可以自行导航;这大致相当于在现代浏览器中打开30个选项卡。由于每个WebBrowser都在完成相同的工作,因此您可以编写一个DocumentCompleted事件来处理单个WebBrowser,然后将其他事件连接到同一事件。请注意,WebBrowser控件有一个错误,导致它逐渐泄漏内存,解决此问题的唯一方法是重新启动应用程序。因此,我建议使用async / await解决方案。

<强>更新

以下是如何使用30 WebBrowsers方式的简短代码示例(未经测试,因为我现在无法访问VS):

List<WebBrowser> myBrowsers = new List<WebBrowser>();

public void btnDoWork(object sender, EventArgs e)
{
    //This method starts navigation.
    //It will call a helper function that gives us a list 
    //of URLs to work with, and naively create as many
    //WebBrowsers as necessary to navigate all of them

    IEnumerable<string> urlList = GetUrlList();
    //note: be sure to sanitize the URLs in this method call

    foreach (string url in urlList)
    {
        WebBrowser browser = new WebBrowser();
        browser.DocumentCompleted += webBrowserDocumentCompleted;
        browser.Navigate(url);
        myBrowsers.Add(browser);
    }
}

private void webBrowserDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    //check that the full document is finished
    if (e.Url.AbsolutePath != (sender as WebBrowser).Url.AbsolutePath) 
        return;

    //get our browser reference
    WebBrowser browser = sender as WebBrowser;

    //get the string command from form TextBox
    string command = textBox2.Text;

    //enter the command string
    browser.Document.GetElementById("_cmd").SetAttribute("Value", command);

    //invoke click
    browser.Document.GetElementById("_act").InvokeMember("click");

    //detach the event handler from the browser
    //note: necessary to stop endlessly setting strings and clicking buttons
    browser.DocumentCompleted -= webBrowserDocumentCompleted;
    //attach second DocumentCompleted event handler to destroy browser
    browser.DocumentCompleted += webBrowserDestroyOnCompletion;
}

private void webBrowserDestroyOnCompletion(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    //check that the full document is finished
    if (e.Url.AbsolutePath != (sender as WebBrowser).Url.AbsolutePath) 
        return;

    //I just destroy the WebBrowser, but you might want to do something
    //with the newly navigated page

    WebBrowser browser = sender as WebBrowser;
    browser.Dispose();
    myBrowsers.Remove(browser);
}