【问题标题】:pull data from website using VBA excel multiple classname使用 VBA excel 多个类名从网站中提取数据
【发布时间】:2018-06-26 16:30:13
【问题描述】:

我知道这已经被问过很多次了,但是还没有看到一个明确的答案来循环遍历具有相同类名的 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“图像”中的所有 img Src 以及 imageElement 类名中的其他内容,并将它们复制到 excel 中的某些单元格中。

第二个问题: 我见过两种使用 VBA 提取网页内容的方法,一种是使用 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

哪个更好,为什么?

如果你能帮助我,我将不胜感激。

提前谢谢你。

【问题讨论】:

    标签: vba excel excel-2010 getelementsbyclassname


    【解决方案1】:

    您的第一个选项通常更可取,因为它比第二种方法快得多,它直接向 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,它将失败,但这可以处理并且变得越来越不相关

    【讨论】:

    • 凯尔!感谢您的完整回复。有一件事还不能得到。 Debug.Print 它有什么作用,以及如何将 src 内容复制到 excel 中的单元格(对不起,基本问题,但我无法正确回答)再次感谢您
    • 这就是我得到的@kyle the oHtml.body.innerHTML = "

       

      "
    • 如果没有 url,恐怕完全不可能为您解决这个问题。 Debug.Print 输出到 IDE 中的即时窗口
    【解决方案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 的语法错误

    【讨论】:

      【解决方案3】:

      CSS 选择器:

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

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

      # 用于 id; [] 用于属性; ^ 开头是; #images imgimgimages


      CSS 查询:


      由于会匹配多个元素,您将使用document.querySelectorAll 方法,然后循环返回的nodeList 的长度。

      VBA 代码:

      Option Explicit
      Public Sub test()
          Dim html As HTMLDocument
          Set html = New HTMLDocument
      
          With CreateObject("WINHTTP.WinHTTPRequest.5.1")
              .Open "GET", "http://www.someurl.com", False
              .send
              html.body.innerHTML = .responseText
          End With
      
          Dim aNodeList As Object, iItem As Long
          Set aNodeList = html.querySelectorAll("#images img[src^='img/']")
          With ActiveSheet
              For iItem = 0 To aNodeList.Length - 1
                  .Cells(iItem + 1, 1) = aNodeList.item(iItem).innerText
                  '.Cells(iItem + 1, 1) = aNodeList(iItem).innerText '<== or potentially this syntax
              Next iItem
          End With
      End Sub
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-18
        • 2018-04-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多