【问题标题】:webbrowser auto navigation event网络浏览器自动导航事件
【发布时间】:2017-11-29 19:11:30
【问题描述】:

我正在使用网络浏览器导航到一个网站,然后自动登录。一切正常,直到评论“导航事件”输入一个凭据后,它将登录并导航到另一个网站。事件发生后,任何代码都不会起作用,因为它没有选择新站点。我正在使用 waitforpageload() 函数让我知道它何时完成加载,但是当我检查 url 时它仍然指向原始站点。任何想法为什么会这样做以及如何解决它?

    Private Property pageready As Boolean = False

    webBrowser1.Navigate("https://www.lamedicaid.com/sprovweb1/provider_login/provider_login.asp")
            waitforpageload()

    Dim allelements As HtmlElementCollection = webBrowser1.Document.All
            For Each webpageelement As HtmlElement In allelements
                'NPI #
                If webpageelement.GetAttribute("name") = "Provider_Id" Then
                    webpageelement.SetAttribute("value", "xxxxxx")
                End If
                'Clicking enter to input NPI
                If webpageelement.GetAttribute("name") = "submit1" Then
                    webpageelement.InvokeMember("focus")
                    webpageelement.InvokeMember("click")
                    waitforpageload()
                End If

                'Navigation event happens here

                'Entering username
                If webpageelement.GetAttribute("name") = "Login_Id" Then
                    webpageelement.SetAttribute("value", "xxxxxxx")
                End If
                'Entering Password
                If webpageelement.GetAttribute("name") = "Password" Then
                    webpageelement.SetAttribute("value", "xxxxxxxxx")
                End If
                'logging in
                If webpageelement.GetAttribute("name") = "submit_button" Then
                    webpageelement.InvokeMember("focus")
                    webpageelement.InvokeMember("click")
                    waitforpageload()
                End If




    #Region "Page Loading Functions"
    Private Sub waitforpageload()
        AddHandler webBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
        While Not pageready
            Application.DoEvents()
        End While
        pageready = False
    End Sub

    Private Sub PageWaiter(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
        If webBrowser1.ReadyState = WebBrowserReadyState.Complete Then
            pageready = True
            RemoveHandler webBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
        End If
    End Sub
#End Region

【问题讨论】:

  • 第一件事,你有太多的waitforpageload() 方法调用。设置元素属性时无需等待任何内容。然后,一个考虑:您是否只需要对这两个站点执行此操作?如果是这样,您只需要一个用于DocumentComplete() 的事件处理程序。设置一个逻辑来区分站点,可能使用它们的页面标题(或其他一些元素),并采取相应的措施。
  • @Jimi 第二个页面有一个新的 URL,但是当我在处理第一个页面后导航到它时,它把我踢了出去。将导航视为新页面。此外,我还更新了 waitforpagetoload() 方法调用。我会考虑利用页面标题或其他元素。
  • @Jimi(和 Cole):第三件事,不要使用waitforpageload()
  • @Cole Perrault “把我踢出去”是未定义的。稍等一下:(1)导航第一个 URL(...导航...)=>DocumentComplete() 已触发 =>(2)设置登录值->InvokeMember()=>登录接受 =>(...导航...)=> DocumentComplete() 被解雇 (3) LandingPage-> New LogIn form-> SetValues-> InvokeMember => LogIn 接受 => (...navigating...)=> DocumentComplete() (4) LandingPage - > 在这里做任何你需要做的事情

标签: vb.net webbrowser-control


【解决方案1】:

看在上帝的份上,请摆脱 waitforpageload() 功能!使用Application.DoEvents()不好的做法,在这样的循环中,将使用 100% 的 CPU!

最初编写该函数的人(来自另一个 Stack Overflow 帖子)显然不知道他/她当时在做什么。使用Application.DoEvents() 产生的问题多于它解决的问题,应该永远在任何人的代码中使用(它的存在主要是因为它被内部方法使用)。

请参阅:Keeping your UI Responsive and the Dangers of Application.DoEvents 了解更多信息。

WebBrowser 有一个专用的DocumentCompleted event,每次页面(或页面的一部分,例如 iframe)完全加载时都会引发。

要确保页面确实已完全加载,请订阅DocumentCompleted 事件并检查ReadyState property 是否等于WebBrowserReadyState.Complete

为了能够在引发DocumentCompleted 事件时更“动态”地运行代码,您可以利用lambda expressions 作为创建内联方法的一种方式。

在你的情况下,它们可以这样使用:

'Second step (these must always be in descending order since the first step must be able to reference the second, and so on).
Dim credentialHandler As WebBrowserDocumentCompletedEventHandler = _
    Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
        'If the WebBrowser HASN'T finished loading, do not continue.
        If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return

        'Remove the event handler to avoid this code being called twice.
        RemoveHandler webBrowser1.DocumentCompleted, credentialHandler

        'Entering username
        If webpageelement.GetAttribute("name") = "Login_Id" Then
            webpageelement.SetAttribute("value", "xxxxxxx")
        End If

        'Entering Password
        If webpageelement.GetAttribute("name") = "Password" Then
            webpageelement.SetAttribute("value", "xxxxxxxxx")
        End If

        'logging in
        If webpageelement.GetAttribute("name") = "submit_button" Then
            webpageelement.InvokeMember("focus")
            webpageelement.InvokeMember("click")
        End If
    End Sub


'First step.
Dim loginHandler As WebBrowserDocumentCompletedEventHandler = _
    Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
        'If the WebBrowser hasn't finished loading, do not continue.
        If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return

        'Remove the event handler to avoid this code being called twice.
        RemoveHandler webBrowser1.DocumentCompleted, loginHandler

        Dim allelements As HtmlElementCollection = webBrowser1.Document.All
        For Each webpageelement As HtmlElement In allelements
            'NPI #
            If webpageelement.GetAttribute("name") = "Provider_Id" Then
                webpageelement.SetAttribute("value", "xxxxxx")
                '-- Why would you even wait in here?? There's no reason for you to wait after only changing an attribute since nothing is loaded from the internet.
            End If

            'Clicking enter to input NPI
            If webpageelement.GetAttribute("name") = "submit1" Then

                'Adding the event handler performing our next step.
                AddHandler webBrowser1.DocumentCompleted, credentialHandler

                webpageelement.InvokeMember("focus")
                webpageelement.InvokeMember("click")
            End If
        Next
    End Sub

'Add the event handler performing our first step.
AddHandler webBrowser1.DocumentCompleted, loginHandler

webBrowser1.Navigate("https://www.lamedicaid.com/sprovweb1/provider_login/provider_login.asp")

现在每次您需要等待文档/网站完全加载时,只需声明一个新的 lambda 并将其作为事件处理程序添加到 DocumentCompleted

Dim thirdStepHandler As WebBrowserDocumentCompletedEventHandler = _
    Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
        'If the WebBrowser hasn't finished loading, do not continue.
        If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return

        'Remove the event handler to avoid this code being called twice.
        RemoveHandler webBrowser1.DocumentCompleted, thirdStepHandler

        'Your goes code here...
    End Sub


'To wait until performing the next step (be sure to do this BEFORE navigating):
AddHandler webBrowser1.DocumentCompleted, thirdStepHandler

【讨论】:

  • 非常感谢您的解释,代码运行得非常好!但是,我有一页必须从下拉菜单中选择项目,然后显示某些文本框。你会知道我怎样才能捕捉到这些吗?
  • @ColePerrault :如果我的回答解决了您的问题,请按我帖子左侧的勾号/复选标记将其标记为已接受。
  • @ColePerrault :至于您的其他请求(在这个问题中是题外话):在页面中注入一些 Javascript 以响应下拉列表的 onchange event,然后调用外部VB.NET 方法。这是从 JS 调用 .NET 方法的示例(在 C# 中,但可以使用在线转换器转换为 VB.NET):stackoverflow.com/a/5434220
  • @ColePerrault:还有这个解决方案:stackoverflow.com/a/9111151——或者这个:codeproject.com/Articles/25769/…
猜你喜欢
  • 1970-01-01
  • 2011-12-18
  • 2014-05-03
  • 2012-05-14
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 2012-10-30
  • 1970-01-01
相关资源
最近更新 更多