您需要激活 WebBrowser 高级功能才能成功完成解析过程。如果未启用这些功能,则标准 IE7 模拟中的 Web 浏览器将无法完成文档。该失败是由大量脚本错误引起的。
我添加了一个带有静态方法的类(WebBrowserAdvancedFetures
) 将所需的值添加到注册表中。
WebBrowserAdvancedFetures.ActivateWBAdvancedFeatures
在 Form 的构造函数中调用。
您可以回滚调用WebBrowserAdvancedFetures.DeactivateWBAdvancedFeatures
.
该程序如何运作:
- 实例化一个网页浏览器 https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.webbrowser class (
Private browser As WebBrowser
)。我们还可以使用 WebBrowser 控件(表单容器可以托管的可见控件版本),这是同样的事情。
- 订阅它的文件已完成 https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.webbrowser.documentcompleted事件。每次其中之一都会提高它
HtmlDocuments
里面主要的WebBrowser.Document
完成了。读如何获取 Frames/IFrames 内的 HtmlElement 值? https://stackoverflow.com/a/53218064/7444103有关 HtmlDocuments 嵌套的更多详细信息。
- In the
DocumentCompleted
处理程序,验证至少一个文档已准备好进行解析,检查WebBrowser.ReadyState https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.webbrowser.readystate = WebBrowserReadyState.Complete
- 当它出现时,搜索包含我们要查找的数据的 HtmlElements。
- 收集完所有数据后,引发一个事件,以通知解析已完成(如果需要,这还允许通知其他类的订阅者。这需要自定义
EventArgs
类,虽然)并禁用进一步解析HtmlDocument
(在这里,这是通过设置布尔字段来完成的)。
- 处理新数据(这里,只是
String
and a DateTime
对象),然后重置解析过程中使用的字段/变量。
请记住删除处理程序,在Form.FormClosed
事件或自定义类中Dispose()
method:
RemoveHandler DocumentParsingComplete, AddressOf OnDocumentParsingComplete
RemoveHandler browser.DocumentCompleted, AddressOf browser_DocumentCompleted
Public Event DocumentParsingComplete As EventHandler(Of EventArgs)
Private browser As WebBrowser = Nothing
Private trackingNumberValue As String = String.Empty
Private trackingDateValue As DateTime
Private documentParsed As Boolean = False
Private userAgent As String = "User-Agent: Mozilla/5.0 (Windows NT 10; Win64; x64; rv:48.0) Gecko/20100101 Firefox/48.0"
Public Sub New()
InitializeComponent()
WebBrowserAdvancedFetures.ActivateWBAdvancedFeatures(Path.GetFileName(Application.ExecutablePath))
browser = New WebBrowser With {.ScriptErrorsSuppressed = True}
AddHandler DocumentParsingComplete, AddressOf OnDocumentParsingComplete
AddHandler browser.DocumentCompleted, AddressOf browser_DocumentCompleted
End Sub
Private Sub btnNavigate_Click(sender As Object, e As EventArgs) Handles btnNavigate.Click
browser.Navigate("")
browser.Document.OpenNew(True)
documentParsed = False
browser.Navigate("[Some URL]", "_self", Nothing, userAgent)
End Sub
Private Sub OnDocumentParsingComplete(sender As Object, e As EventArgs)
' Do whatever you need with these
Console.WriteLine(trackingNumberValue)
Console.WriteLine(trackingDateValue)
'Then reset for further use
trackingNumberValue = String.Empty
trackingDateValue = DateTime.MinValue
End Sub
Private Sub browser_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
Dim wb As WebBrowser = DirectCast(sender, WebBrowser)
If wb.ReadyState <> WebBrowserReadyState.Complete OrElse wb.Document.Forms.Count = 0 OrElse documentParsed Then Return
Dim trackingNumberClass As String = "tracking-number-value"
Dim trackingElement = wb.Document.GetElementsByTagName("SPAN").
OfType(Of HtmlElement)().FirstOrDefault(Function(elm) elm.GetAttribute("className").Contains(trackingNumberClass))
Me.trackingNumberValue = trackingElement?.InnerText
Dim trackingDateClass As String = "ng-binding ng-scope"
Dim trackingDateElement = wb.Document.GetElementsByTagName("SPAN").
OfType(Of HtmlElement)().FirstOrDefault(Function(elm) elm.GetAttribute("className").Equals(trackingDateClass))
If trackingDateElement IsNot Nothing Then
Dim deliveryDate As String = trackingDateElement.InnerText.Split().Last().TrimEnd("."c)
Me.trackingDateValue = Date.ParseExact(deliveryDate, "dd-MM-yyyy", Nothing)
If Not String.IsNullOrEmpty(trackingNumberValue) Then
documentParsed = True
RaiseEvent DocumentParsingComplete(sender, EventArgs.Empty)
End If
End If
End Sub
使用此类来激活/停用 WebBrowser 控件的高级功能:
Imports Microsoft.Win32
Imports System.Security.AccessControl
Public Class WebBrowserAdvancedFetures
Private Shared baseKeyName As String = "Software\Microsoft\Internet Explorer\Main\FeatureControl"
Private Shared featuresKey As String = baseKeyName & "\FEATURE_BROWSER_EMULATION"
Private Shared hardwareAccelKey As String = baseKeyName & "\FEATURE_GPU_RENDERING"
Public Shared Sub ActivateWBAdvancedFeatures(executableName As String)
Dim wbFeatureKey As RegistryKey = Nothing
Dim wbAccelKey As RegistryKey = Nothing
Try
wbFeatureKey = Registry.CurrentUser.OpenSubKey(featuresKey,
RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.WriteKey)
If wbFeatureKey Is Nothing Then
wbFeatureKey = Registry.CurrentUser.CreateSubKey(featuresKey, True)
End If
wbFeatureKey.SetValue(executableName, 11001, RegistryValueKind.DWord)
wbAccelKey = Registry.CurrentUser.OpenSubKey(hardwareAccelKey,
RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.WriteKey)
If wbAccelKey Is Nothing Then
wbAccelKey = Registry.CurrentUser.CreateSubKey(hardwareAccelKey, True)
End If
wbAccelKey.SetValue(executableName, 1, RegistryValueKind.DWord)
Finally
wbFeatureKey?.Dispose()
wbAccelKey?.Dispose()
End Try
End Sub
Public Shared Sub DeactivateWBAdvancedFeatures(executableName As String)
Using wbFeatureKey = Registry.CurrentUser.OpenSubKey(
featuresKey, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.WriteKey)
wbFeatureKey.DeleteValue(executableName, False)
End Using
Using wbAccelKey = Registry.CurrentUser.OpenSubKey(
hardwareAccelKey, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.WriteKey)
wbAccelKey.DeleteValue(executableName, False)
End Using
End Sub
End Class