2014-01-24 68 views
4

我自由地承認,我對HTML對象庫不太瞭解。VBA:循環中的不一致錯誤91 w/IE.doc參考

我有一個電子表格,包含IRS僱主識別號碼,我必須將其識別爲在我的數據庫中。我只有基於Web的訪問這個數據庫,其他人已經寫了HTML並管理數據庫。我相信他們的方法過時了,他們的設計實踐很差;但我並不是最終的數據庫管理員,所以我知道什麼?因此,我最終的正常做法是在搜索頁面輸入EIN並記錄結果。

我的Excel宏是爲了

  1. 登錄到基於Web的數據庫查詢網站。

  2. 循環遍歷EIN的,注意哪些EIN的發現

不過,我有以下問題:

  • A.登錄部分工作得很好,但有一個怪癖:我必須將 保留爲驗證登錄成功(或不是) 的「If Then Else」,否則登錄失敗。鑑於登錄後發生「If Then Else」 ,這是完全令人困惑的。
  • B.判斷EIN是否在數據庫中的唯一方法是查看 innerText,並查看EIN是否發生在由 查詢得到的頁面上。這是行不通的,即我只在 (在測試中)時纔得到正面打擊,我連續查詢兩次相同的EIN。 (我碰到了 第二個EIN。)
  • C.在循環中,我得到不一致的錯誤91(對象變量不是 集)。有時循環完成;有時會掛起,但從來沒有在 的地方。

我的代碼如下所示(雖然我不得不修改URL):

Option Explicit 
Sub FillFromWorkbookTest() 

On Error GoTo ErrHandler 

Const cURL = "https://www.someURL.com/LoginPage.jsp" 
Const cUsername = "myUSERNAME" 
Const cPassword = "myPASSWORD" 
Dim IE As Object 
Dim Doc As HTMLDocument 
Dim LoginForm As HTMLFormElement 
Dim UsernameInput As HTMLInputElement 
Dim PasswordInput As HTMLInputElement 
Dim LoginButton As HTMLInputButtonElement 
Dim SearchForm As HTMLFormElement 
Dim EINInput As HTMLInputElement 
Dim SearchButton As HTMLInputButtonElement 
Dim cEIN As String 
Dim BotRow As Long 
Dim EINRange As Range 
Dim c As Variant 
Dim i As Integer 
Dim EINCheck As String 
Dim EINCount As Integer 

'## Open Browser & go to Admin Module, and Login 
Set IE = CreateObject("InternetExplorer.Application") 
IE.Visible = True 
IE.Navigate cURL 

'## Wait for Adimn Module to load 
Do Until IE.ReadyState = 4 
    DoEvents 
Loop 

'## Get the HTML Document of Admin Module login page (cURL) 
Set Doc = IE.document 

'## Get Admin Module login form 
Set LoginForm = Doc.forms("f1") 

'## Get Username input field and populate it 
'## HTML: <input id=EIN type=text tabindex=3 size=9 maxlength=9 name=EIN title="Admin Code"> 
Set UsernameInput = LoginForm.elements("EIN") 
UsernameInput.Value = cUsername 

'## Get Password input field and populate it 
'## HTML: <input id=PIN type=password tabindex=4 size=8 maxlength=8 name=PIN title="PIN"> 
Set PasswordInput = LoginForm.elements("PIN") 
PasswordInput.Value = cPassword 

'## Submit LoginForm 
'## HTML: <input type=submit value=Login tabindex=5 title="Login"> (no onClick attribute; no element) 
LoginForm.submit 

Do Until IE.ReadyState = 4 
    DoEvents 
Loop 

'## Get the HTML Document of the new page 
Set Doc = IE.document 

'## Determine if login succeeded 
If InStr(Doc.body.innerText, "Invalid Login.") = 0 Then 
    MsgBox "Login successful." 
Else 
    MsgBox "Login failed." 
End If 

Debug.Print "Current URL: " & IE.LocationURL 

'## Navigate to Global Change and reset HTML Document 
IE.Navigate "https://www.someURL.com/LOGGED_IN/SomePage.jsp" 

Do Until IE.ReadyState = 4 
    DoEvents 
Loop 

Set Doc = IE.document 

'## Find last row in spreadsheet 
BotRow = Worksheets("Sheet1").Range("A1").End(xlDown).Row 
Set EINRange = Range("A1:A" & BotRow) 

'## Set loop counter variable 
i = 0 

'## Cycle through IRS-identified EINs 
For Each c In EINRange.Cells 

    cEIN = c.Value 
    i = i + 1 

'## Get Admin Module login form 
    Set SearchForm = Doc.forms(0) 

'## Get EIN input field and populate it 
'## HTML: <input type="text" id=EIN name=EIN title="Enter charity EIN" maxlength=9 size=9 tabindex=11 > 
    Set EINInput = SearchForm.elements("EIN") 
    EINInput.Value = cEIN 

'## Submit SearchForm 
'## HTML: <input type="submit" value="Search" tabindex=15 title="Click here to search charity application" class="black_bold" 
'##  onclick="if (btn_OnClick(EIN,CODE)) {document.f1.action='SomeOther.jsp'; document.f1.submit(); return true;} else return false;" > 
'##  (has onClick attribute) 

    Set SearchButton = Doc.body.getElementsByTagName("table")(2). _ 
     getElementsByTagName("tr")(0). _ 
     getElementsByTagName("td")(0). _ 
     getElementsByTagName("input")(2) 
    SearchButton.Click 

    Do Until IE.ReadyState = 4 
     DoEvents 
    Loop 

'## Get the HTML Document of the new page 
    Set Doc = IE.document 

'## Find EIN string on resulting page; Some number if found; Null if not 
    EINCheck = Doc.body.getElementsByTagName("table")(3).innerText 
    EINCount = InStr(1, EINCheck, cEIN, 1) 
    MsgBox EINCount 

'## Determine which EINs are CFC charities 
    If InStr(1, EINCheck, cEIN, 1) = 0 Then 
     Worksheets("Sheet1").Range("F" & i).Value = "NO" 
    Else 
     Worksheets("Sheet1").Range("F" & i).Value = "YES" 
    End If 

Next c 

ErrHandler: 
'## Cleanup 
MsgBox "Error" & Err.Number & ": " & Err.Description 
Set IE = Nothing 
Set Doc = Nothing 
Set LoginForm = Nothing 
Set UsernameInput = Nothing 
Set PasswordInput = Nothing 
Set LoginButton = Nothing 
Set SearchForm = Nothing 
Set EINInput = Nothing 
Set SearchButton = Nothing 

End Sub 

有什麼建議?

回答

9

我發現使用下面的「等待,直到IE就緒」

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 
Public Function IEWait(p_ieExp As InternetExplorer) 

    'this should go from ready-busy-ready 
    Dim initialReadyState As Integer 
    initialReadyState = p_ieExp.ReadyState 

    'wait 250 ms until it's done 
    Do While p_ieExp.Busy Or p_ieExp.ReadyState <> READYSTATE_COMPLETE 
     Sleep 250 
    Loop 

End Function 

你會這樣稱呼它

IEWait IE 'your internet explorer is named "IE" 

我也陷入了太多的古怪更好的成功僅使用「就緒」條件之一的錯誤。在修改我的「準備好」檢查方法後,這幾乎完全消失了。有時就緒狀態不能準確反映狀態。

關於你的第一個問題,使用上面提到的Sleep方法,試着在你的每個命令前加上Sleep 1000來驗證問題出在你的邏輯上,而不是IE加載太慢。或者緩慢地逐步調試。

你所描述的聲音聽起來非常類似於我在IE部分加載和我的代碼會繼續執行時遇到的一些問題。

+1

恩德蘭:你是一個美麗的人。這是frickin'真棒!像魅力一樣工作。這清除了我遇到的所有問題。謝謝! – user3232254

+0

@ user3232254很樂意幫忙! – enderland

+1

僅供參考 - 我必須添加對「Microsoft Internet控件」的引用才能使用。 –