2013-03-03 54 views
11

我一直在玩弄使用VBS/VBA從網頁上抓取數據。在HTMLElement上使用getElementById而不是HTMLDocument

如果是Javascript,我會遠離它,但它在VBS/VBA中看起來並不那麼直截了當。

這是我爲一個答案做的一個例子,它的工作原理,但我曾計劃使用getElementByTagName訪問子節點,但我無法弄清楚如何使用它們! HTMLElement對象沒有這些方法。

Sub Scrape() 
Dim Browser As InternetExplorer 
Dim Document As HTMLDocument 
Dim Elements As IHTMLElementCollection 
Dim Element As IHTMLElement 

Set Browser = New InternetExplorer 

Browser.navigate "http://www.hsbc.com/about-hsbc/leadership" 

Do While Browser.Busy And Not Browser.readyState = READYSTATE_COMPLETE 
    DoEvents 
Loop 

Set Document = Browser.Document 

Set Elements = Document.getElementsByClassName("profile-col1") 

For Each Element in Elements 
    Debug.Print "[ name] " & Trim(Element.Children(1).Children(0).innerText) 
    Debug.Print "[ title] " & Trim(Element.Children(1).Children(1).innerText) 
Next Element 

Set Document = Nothing 
Set Browser = Nothing 
End Sub 

我一直在尋找的HTMLElement.document性能,看它是否是像文件的一個片段,但其無論是困難的工作,或只是心不是我所想的

Dim Fragment As HTMLDocument 
Set Element = Document.getElementById("example") ' This works 
Set Fragment = Element.document ' This doesn't 

這也似乎是一個囉嗦的方式來做到這一點(雖然這通常是vba imo的方式)。 任何人都知道是否有一種更簡單的方法來鏈接功能?

Document.getElementById("target").getElementsByTagName("tr")將是真棒......

回答

4

我也不喜歡它。

那麼請使用javascript:

Public Function GetJavaScriptResult(doc as HTMLDocument, jsString As String) As String 

    Dim el As IHTMLElement 
    Dim nd As HTMLDOMTextNode 

    Set el = doc.createElement("INPUT") 
    Do 
     el.ID = GenerateRandomAlphaString(100) 
    Loop Until Document.getElementById(el.ID) Is Nothing 
    el.Style.display = "none" 
    Set nd = Document.appendChild(el) 

    doc.parentWindow.ExecScript "document.getElementById('" & el.ID & "').value = " & jsString 

    GetJavaScriptResult = Document.getElementById(el.ID).Value 

    Document.removeChild nd 

End Function 


Function GenerateRandomAlphaString(Length As Long) As String 

    Dim i As Long 
    Dim Result As String 

    Randomize Timer 

    For i = 1 To Length 
     Result = Result & Chr(Int(Rnd(Timer) * 26 + 65 + Round(Rnd(Timer)) * 32)) 
    Next i 

    GenerateRandomAlphaString = Result 

End Function 

讓我知道,如果您有任何與此問題;我已經將方法的上下文更改爲函數。

順便說一句,你使用的是什麼版本的IE?我懷疑你是在IE8上的<。如果您升級到IE8,我認爲它會將shdocvw.dll更新爲ieframe.dll,您將能夠使用document.querySelector/All。

編輯

評論迴應這是不是一個真正的評論: 基本上在VBA來做到這一點的方式是遍歷子節點。問題是你沒有得到正確的返回類型。你可以通過使你自己的類(單獨)實現IHTMLElement和IHTMLElementCollection來解決這個問題;但這對我來說太麻煩了,沒有得到報酬:)。如果您已確定,請閱讀VB6/VBA的Implements關鍵字。

Public Function getSubElementsByTagName(el As IHTMLElement, tagname As String) As Collection 

    Dim descendants As New Collection 
    Dim results As New Collection 
    Dim i As Long 

    getDescendants el, descendants 

    For i = 1 To descendants.Count 
     If descendants(i).tagname = tagname Then 
      results.Add descendants(i) 
     End If 
    Next i 

    getSubElementsByTagName = results 

End Function 

Public Function getDescendants(nd As IHTMLElement, ByRef descendants As Collection) 
    Dim i As Long 
    descendants.Add nd 
    For i = 1 To nd.Children.Length 
     getDescendants nd.Children.Item(i), descendants 
    Next i 
End Function 
+0

我給一個去,我想類似的東西,瀏覽到我的網頁,然後導航到一個'javascript:'url。工作,但不是很好。你知道'Document.parentWindow.ExecScript'是否阻塞嗎?或者可能我的腳本在結果設置之前沒有完成執行? (也會在一秒鐘內測試自己)。我仍然想知道是否有一種方法可以純粹用VB來完成它! – NickSlash 2013-03-03 23:49:53

+0

這並不是說querySelector不能與IE9 + dll一起工作,我只是沒有測試過那些 – mkingston 2013-03-03 23:50:44

+0

@NickSlash我編輯了我的答案以迴應您的評論。至於阻擋,我認爲是這樣,但我不確定。應該很容易測試(嵌套循環計數到2^31或JS中的最大整數)。 – mkingston 2013-03-04 00:02:05

12
Sub Scrape() 
    Dim Browser As InternetExplorer 
    Dim Document As htmlDocument 
    Dim Elements As IHTMLElementCollection 
    Dim Element As IHTMLElement 

    Set Browser = New InternetExplorer 
    Browser.Visible = True 
    Browser.navigate "http://www.stackoverflow.com" 

    Do While Browser.Busy And Not Browser.readyState = READYSTATE_COMPLETE 
     DoEvents 
    Loop 

    Set Document = Browser.Document 

    Set Elements = Document.getElementById("hmenus").getElementsByTagName("li") 
    For Each Element In Elements 
     Debug.Print Element.innerText 
     'Questions 
     'Tags 
     'Users 
     'Badges 
     'Unanswered 
     'Ask Question 
    Next Element 

    Set Document = Nothing 
    Set Browser = Nothing 
End Sub 
0

由於DEE上面與刮()子程序答案。代碼完全按照書面形式工作,然後我能夠將代碼轉換爲與我正在嘗試抓取的特定網站一起工作。

我沒有足夠的聲譽給予好評或發表評論,但我的確有一些細微的改進,添加到DEE的回答是:

  1. 你需要通過「工具\引用添加VBA參考「to」微軟HTML對象庫,以便代碼編譯。

  2. 我註釋掉了瀏覽器。可見線和添加的註釋如下

    'if you need to debug the browser page, uncomment this line: 
    'Browser.Visible = True 
    
  3. 我添加了一行瀏覽器設置之前關閉瀏覽器=無:

    Browser.Quit 
    

再次感謝D形電極!

ETA:這適用於使用IE9的機器,但不適用於使用IE8的機器。任何人都有解決辦法?

自己找到了修復,所以回到這裏來發布它。 ClassName函數在IE9中可用。對於這個在IE8的工作,您使用querySelectorAll,與對象,你的類名前面的點都在尋找:

'Set repList = doc.getElementsByClassName("reportList") 'only works in IE9, not in IE8 
Set repList = doc.querySelectorAll(".reportList")  'this works in IE8+ 
相關問題