使用VBA excel多个类名从网站提取数据

时间:2013-09-10 02:38:13

标签: excel vba excel-vba excel-2010 getelementsbyclassname

我知道这已被多次询问,但是没有看到通过div和findind标签循环使用相同类名的明确答案。

我的第一个问题:

如果我有这样的话:

<div id="carousel">
   <div id="images">

       <div class="imageElement">
          <img src="img/image1.jpg">
       </div>

       <div class="imageElement">
          <img src="img/image2.jpg">
       </div>

       <div class="imageElement">
           <img src="img/image3.jpg">
       </div>

   </div>

</div>

所以我想在div“images”中获取所有img Src以及imageElement类名中的其他内容,并将它们复制到excel中的某些单元格。

第二个问题: 我已经看到了两种使用VBA提取Web内容的方法,一种是使用IE浏览器而另一种是使用浏览器而使用其他代码。

Private Sub pullData_Click()

    Dim x As Long, y As Long
    Dim htm As Object

    Set htm = CreateObject("htmlFile")

    With CreateObject("msxml2.xmlhttp")
        .Open "GET", "http://website.html", False
        .send
        htm.body.innerHTML = .responsetext
    End With

End Sub

第二种方式:

Set ie = New InternetExplorer
    With ie
        .navigate "http://eoddata.com/stockquote/NASDAQ/AAPL.htm"
        .Visible = False
        While .Busy Or .readyState <> READYSTATE_COMPLETE
           DoEvents
        Wend
        Set objHTML = .document
        DoEvents
    End With
    Set elementONE = objHTML.getElementsByTagName("TD")
    For i = 1 To elementONE.Length
        elementTWO = elementONE.Item(i).innerText           
        If elementTWO = "08/10/12" Then
            MsgBox (elementONE.Item(i + 1).innerText)
            Exit For
        End If
    Next i
    DoEvents
    ie.Quit
    DoEvents
    Set ie = Nothing

哪一个更好,为什么?

所以,如果你能帮助我,我会很感激。

提前谢谢。

3 个答案:

答案 0 :(得分:8)

您的第一个选项通常更可取,因为它比第二个方法快得多,它会直接向Web服务器发送请求并返回响应。这比自动化Internet Explorer(第二种选择)更有效率;自动化IE非常慢,因为你实际上只是浏览网站 - 它必然会导致更多的下载,因为它必须加载页面中的所有资源 - 图像,脚本,css文件等。它还将在页面上运行任何Javascript - 所有这些通常都没有用,你必须等到它完成才能解析页面。

然而这是一把双刃剑 - 虽然慢得多,如果你不熟悉html请求,自动化Internet Explorer比第一种方法更容易,特别是当动态生成元素或页面依赖时在AJAX上。当您需要访问要求您登录的站点中的数据时,自动化IE也更容易,因为它将为您处理相关的cookie。这并不是说第一种方法无法完成网页抓取,而是需要更深入地了解网站技术和网站架构。

第一种方法的更好选择是使用不同的对象来处理请求和响应,使用WinHTTP库提供比MSXML库更多的弹性,并且通常也会自动处理任何cookie。

至于解析数据,在第一种方法中,您使用后期绑定来创建HTML对象(htmlfile),同时这减少了对引用的需求,同时也减少了功能。例如,当使用后期绑定时,如果用户安装了IE9,则会错过添加的功能,特别是在这种情况下是getElementsByClass名称函数。

作为第三种选择(以及我的首选方法):

Dim oHtml       As HTMLDocument
Dim oElement    As Object

Set oHtml = New HTMLDocument


With CreateObject("WINHTTP.WinHTTPRequest.5.1")
    .Open "GET", "http://www.someurl.com", False
    .send
    oHtml.body.innerHTML = .responseText
End With

For Each oElement In oHtml.getElementsByClassName("imageElement")
    Debug.Print oElement.Children(0).src
Next oElement

'IE 8 alternative
'For Each oElement In oHtml.getElementsByTagName("div")
'    If oElement.className = "imageElement" Then
'        Debug.Print oElement.Children(0).src
'    End If
'Next oElement

这将需要Microsoft HTML Object Library的参考设置 - 如果用户没有安装IE9,它将失败,但这可以处理并且变得越来越不相关

答案 1 :(得分:2)

要将元素打印到单元格替换:

For Each oElement In oHtml.getElementsByClassName("imageElement")
    Debug.Print oElement.Children(0).src
Next oElement

使用:

Dim wsTarget as Worksheet
dim i as Integer
i=1
set wsTarget=activeworkbook.worksheets("SomeSheet")

For Each oElement In oHtml.getElementsByClassName("imageElement")
    wstarget.range("A" & i)=oElement.Children(0).src
    i=i+1
Next

'更正了For

的语法错误

答案 2 :(得分:2)

CSS选择器:

您还可以使用#images img[src^='img/']中的CSS selector

这表示ID为images的元素包含标记名img,其属性为src,其值以'img/'开头。

#用于ID; []表示属性; ^开头; {{1}中的#images imgimg


CSS查询:

CSS query


由于将匹配多个元素,因此您将使用images的{​​{3}}方法,然后循环返回的document的长度。

VBA代码:

nodeList