【问题标题】:Accessing document elements when using Windows.Forms.WebBrowser使用 Windows.Forms.WebBrowser 时访问文档元素
【发布时间】:2018-08-26 00:14:46
【问题描述】:

我是自动化网页访问的新手,所以请原谅可能是一个补救问题。我在控制台应用程序中使用 C#/Windows.Forms。我需要以编程方式在无法修改且正在运行 javascript 的网页上输入输入值。我已成功打开页面(触发WebBrowser.DocumentCompleted). 我将浏览器仿真模式设置为 IE11(在注册表中),因此脚本运行时没有错误。当 DocumentCompleted() 触发时,如果不先通过以下方式查看文档内容,我将无法访问文档元素MessageBox.Show(),这对于我的无人值守应用来说显然是不可接受的。

我需要做什么才能在无人参与的会话中访问我的文档元素(这样我就可以从下面的代码中删除 MessageBox.Show())?详情如下。谢谢。

输入的 HTML 是:

<input class="input-class" on-keyup="handleKeyPress($key)" type="password">

我的 DocumentCompleted 事件处理程序是:

    private static void LoginPageCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        WebBrowser wb = ((WebBrowser)sender);

        var document = wb.Document;

    // I'm trying to eliminate these 3 lines
        var documentAsIHtmlDocument = (mshtml.IHTMLDocument)document.DomDocument;
        var content = documentAsIHtmlDocument.documentElement.innerHTML;
        MessageBox.Show(content);

        String classname = null;
        foreach (HtmlElement input in document.GetElementsByTagName("input"))
        {
            classname = input.GetAttribute("className");

            if (classname == "input-class")
            {
                input.SetAttribute("value", password);
                break;
            }
        }
   }

【问题讨论】:

  • 当您尝试访问该文档时,它可能只是部分完成。例如,DocumentCompleted() 事件可以由 IFrame 触发。在尝试解析之前尝试添加检查:if (webBrowser1.ReadyState == WebBrowserReadyState.Complete) { (...) };
  • @Jimi - 非常感谢您的建议。您建议的检查确认页面ReadyStateComplete;但是,在 MessageBox.Show() 语句之后,文档元素仍然无法访问。
  • 用示例中的代码试试。我刚刚用 WebForm 登录页面对其进行了测试,密码已正确插入到 Input 容器中。
  • @Jimi - 我正在尝试在 ConsoleApp 中执行此操作。 WebBrowser 控件是否可能在 ConsoleApp 中无法正常工作?如果是这样,那就有点解释了。
  • 我将在控制台项目中对此进行测试。我不记得行为上有什么不同,但重新检查并没有什么坏处。

标签: winforms webbrowser-control


【解决方案1】:

对我来说,问题是我正在访问的页面是由 javascript 创建的。即使触发了 documentComplete 事件,页面仍然没有完全呈现。通过等待文档元素可用,我已经成功处理了第一页,如果不可用,则循环执行 Application.DoEvents(); 直到它们可用,所以我现在知道我在正确的轨道上。

这个 SO 问题帮助了我:c# WebBrowser- How can I wait for javascript to finish running that runs when the document has finished loading?

请注意,检查 DocumentComplete 并不能准确指示 javascript 生成的页面上文档元素的可用性。我需要继续检查元素并运行 Application.DoEvents() 直到它们可用(在 javascript 生成它们之后)。

【讨论】:

【解决方案2】:

如果问题来自于创建 STAThread,需要实例化 WebBrowser 控件的底层 Activex 组件,这是 Hans Passant's code 的修改版本,如您链接的 SO 问题中所示。

在控制台项目中测试。

class Program
{
    static void Main(string[] args)
    {
        NavigateURI(new Uri("[SomeUri]", UriKind.Absolute), "SomePassword");
        Console.ReadLine();
    }

    private static string SomePassword = "SomePassword";

    private static void NavigateURI(Uri url)
    {
        Thread thread = new Thread(() => {
            WebBrowser browser = new WebBrowser();
            browser.DocumentCompleted += browser_DocumentCompleted;
            browser.Navigate(url);
            Application.Run();
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }

    protected static void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        WebBrowser browser = ((WebBrowser)sender);
        if (browser.Url == e.Url)
        {
            while (browser.ReadyState != WebBrowserReadyState.Complete)
            { Application.DoEvents(); }

            HtmlDocument Doc = browser.Document;
            if (Doc != null)
            {
                foreach (HtmlElement input in Doc.GetElementsByTagName("input"))
                {
                    if (input.GetAttribute("type") == "password")
                    {
                        input.InnerText = SomePassword;
                        //Or
                        //input.SetAttribute("value", SomePassword);
                        break;
                    }
                }
            }
            Application.ExitThread();
        }
    }
}

【讨论】:

  • 非常感谢您的帮助。这变得更有趣了。当我使用任何字符串(不需要是内容)调用MessageBox.Show() 时,我的代码有效。我对您建议的步骤的回复如下:
  • 我的代码几乎和你的一样,除了 MessageBox.Show() 和我设置密码值的方式发生了变化(我发现我需要设置 InnerText 而不是“值”属性)。让我确认我的工作并发布我的代码。敬请期待……
  • @Tony 我已经发布了这段代码,这样,如果你使用它,我们就可以在同一页面上了解正在发生的事情,并且可以从那里继续。设置InnerTextValue 是一回事。
  • 你现在看到的代码,就像以前的版本一样,正在工作(当我写“在控制台项目中测试”时,我是认真的)。您可以共享指向有问题的 Html 页面的链接,以便对其进行分析。如果您认为它可能有用,请编辑您的问题并发布更好地描述问题的相关代码,在定义的上下文中说明预期的内容和发生的情况。如果您想出一个可行的解决方案,请发布您自己问题的答案。
  • @Tony 好吧,我很高兴你成功了 :)
猜你喜欢
  • 1970-01-01
  • 2015-03-13
  • 2019-09-06
  • 2012-04-11
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
相关资源
最近更新 更多