【发布时间】:2021-03-16 14:03:15
【问题描述】:
我正在尝试运行两个 Internet Explorer 实例来抓取 HTML。目标是为大多数功能提供一个全局 IE。但是,我需要一个用于特定目的(身份验证)的实例,一旦完成,它就会被销毁。
第二个 IE 实例的原因是由于网站的身份验证过程会抛出一个 alert() Javascript 弹出窗口,该弹出窗口很难确认和关闭。在这种情况下,我目前正在终止整个 IE 实例。
注意我在另一篇文章中讨论了弹出窗口:Internet Explorer readyState reverts from Complete to Interactive
一旦我使用它的 PID 终止 IE 的第二个实例,它似乎也会影响 IE 的全局实例。返回IE全局实例时,得到:运行时错误'462':远程服务器机器不存在或不可用。
复制:
- 执行函数runIE1(可多次运行)
- 执行函数runIE2(可多次运行)
- 执行函数runIE1得到错误
模块代码:
Option Explicit
Public Declare Function GetWindowThreadProcessId Lib "user32" _
(ByVal lHWnd As Long, _
ByRef lProcessId As Long) As Long
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal Milliseconds As LongPtr)
Public ie_browser As New InternetExplorer
Sub runIE1()
Debug.Print "--- runIE1 ---"
Debug.Print "ie_browser PID: "; ie_browser.hwnd
With ie_browser
.Navigate "http://127.0.0.1/good.html"
.Silent = True
.Visible = False
End With
Debug.Print "ie_browser1 Navigated..."
Do Until ie_browser.readyState = 4: DoEvents: Loop
Do Until ie_browser.Busy = False: DoEvents: Loop
Debug.Print "ie_browser should have parsed and rendered the page at this time"
Debug.Print "--- runIE1 ---"
End Sub
Sub runIE2()
Debug.Print "--- runIE2 ---"
Dim ie_browser2_hwnd As Long
Dim ie_browser2 As InternetExplorer
Set ie_browser2 = CreateObject("InternetExplorer.Application")
Debug.Print "ie_browser2 PID: "; ie_browser2.hwnd
With ie_browser2
.Navigate "http://127.0.0.1:9000/ftw/bad.html"
.Silent = True
.Visible = False
End With
Debug.Print "ie_browser2 Navigated..."
Debug.Print "ie_browser2 Start wait..."
Call waitForIE(ie_browser2)
Debug.Print "ie_browser2 End wait..."
'close if found
If Not ie_browser2 Is Nothing Then
Debug.Print "ie_browser2 not null..."
ie_browser2_hwnd = ie_browser2.hwnd
ie_browser2.Quit
Set ie_browser2 = Nothing
Debug.Print "ie_browser2 quit, set to null"
Call KillHwndProcess(ie_browser2_hwnd)
Debug.Print "terminated ie_browser2 PID: " & ie_browser2_hwnd
End If
Debug.Print "--- runIE2 ---"
End Sub
Public Sub waitForIE(i As InternetExplorer)
Dim ie_hwnd As Long
'Ensure browser has completed
Do While i.readyState = 4: DoEvents: Loop
'Sleep to ensure that we let the readyState to flip back
Sleep (250)
'popup occurred!
If i.readyState = 3 Then
Debug.Print "waitForIE - Popup occurred"
ie_hwnd = i.hwnd
Debug.Print "waitForIE - ie PID: " & ie_hwnd
i.Quit
Set i = Nothing
Debug.Print "waitForIE - quit IE, set to nothing..."
Call KillHwndProcess(ie_hwnd)
Debug.Print "waitForIE - Terminated IE process: " & ie_hwnd
Else
Do Until i.readyState = 4: DoEvents: Loop
Do Until i.Busy = False: DoEvents: Loop
Debug.Print "Browser should have parsed and rendered the page at this time"
Debug.Print "IE State: " & i.readyState & " IE busy: " & i.Busy
End If
End Sub
'---------------------------------------------------------------------------------------
' Procedure : KillHwndProcess
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Terminate a process based on its Windows Handle (Hwnd)
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' lHWnd : Windows Handle number (Hwnd)
'
' Usage:
' ~~~~~~
' Call KillHwndProcess(Application.hWnd)
'
' Revision History:
' Rev Date(yyyy/mm/dd) Description
' **************************************************************************************
' 1 2018-09-09 Initial Website Release
'---------------------------------------------------------------------------------------
Public Function KillHwndProcess(lHWnd As Long)
' https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process
On Error GoTo Error_Handler
Dim oWMI As Object
Dim oProcesses As Object
Dim oProcess As Object
Dim lProcessId As Long
Dim sSQL As String
Const sComputer = "."
'Retrieve the ProcessId associated with the specified Hwnd
Call GetWindowThreadProcessId(lHWnd, lProcessId)
'Iterate through the matching ProcessId processes and terminate
' each one.
Set oWMI = GetObject("winmgmts:\\" & sComputer & "\root\cimv2")
sSQL = "SELECT * FROM Win32_Process WHERE ProcessId=" & lProcessId
Set oProcesses = oWMI.ExecQuery(sSQL)
For Each oProcess In oProcesses
oProcess.Terminate
Next
Error_Handler_Exit:
On Error Resume Next
If Not oProcess Is Nothing Then Set oProcess = Nothing
If Not oProcesses Is Nothing Then Set oProcesses = Nothing
If Not oWMI Is Nothing Then Set oWMI = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: KillHwndProcess" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
在即时窗口中输出:
ie_browser PID: 593524
--- runIE1 ---
ie_browser PID: 593524
ie_browser Navigated...
ie_browser should have parsed and rendered the page at this time
--- runIE1 ---
--- runIE1 ---
ie_browser PID: 593524
ie_browser Navigated...
ie_browser should have parsed and rendered the page at this time
--- runIE1 ---
--- runIE1 ---
ie_browser PID: 593524
ie_browser Navigated...
ie_browser should have parsed and rendered the page at this time
--- runIE1 ---
--- runIE2 ---
ie_browser2 PID: 397928
ie_browser2 Navigated...
ie_browser2 Start wait...
waitForIE - Popup occurred
waitForIE - ie PID: 397928
waitForIE - quit IE, set to nothing...
waitForIE - Terminated IE process: 397928
ie_browser2 End wait...
--- runIE2 ---
--- runIE1 ---
文件 bad.html(删除对 good.html 的警告)
<html>
<head>
<title>Bad file</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
Bad!
<script type="text/javascript">
alert("Hello World!");
</script>
</body>
</html>
【问题讨论】:
-
alert() 是从您正在与之交互的页面中抛出的,还是从刚刚加载的导航事件结果的新页面中抛出的?
-
...您是否考虑过使用 Windows API 单击警报上的“确定”按钮?
-
@TimWilliams IE 导航到的页面正在抛出警报()。不,我没有想过要点击确定的 Windows API(不知道这是一个选项)。会调查。谢谢!
-
我认为 Tim Williams 的解决方案是有道理的。你可以试试看。此外,您可以使用SendKeys 关闭警报吗?您可以尝试
SendKeys ("{ENTER}")模拟按 Enter 键关闭警报弹出窗口。 -
@YuZhou 我相信我试过了,但没有成功。我当然可以再试一次。
标签: excel vba internet-explorer