【问题标题】:I'm having trouble scraping this我很难刮这个
【发布时间】:2018-06-13 02:59:50
【问题描述】:

我试图了解为什么我的参考资料不能很好地抓取这些数据。

这里以网站为例:
http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear

并作为目标:

<div id="data_i6" class="rf_crow"><div id="Y_1" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="741131269">741</div><div id="Y_2" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="836611464">837</div><div id="Y_3" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="939841654">940</div><div id="Y_4" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="1010472512">1,010</div><div id="Y_5" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="1100344312">1,100</div><div id="Y_6" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="1115401551">1,115</div></div>

我需要提取的是 rawvalue="741131269" 中的实际值,以下是我到目前为止所做的工作。

'Cells(1, 1) = Document.getElementsByClassName("rf_crow")'returns the rows of data into one cell
'Cells(1, 1) = Document.getElementById("Y_1").innerText 'returns the text for the year
'Cells(1, 1) = Document.getElementById("data_i1").innerText 'returns to first row of data

我知道上面没有返回我想要的,因为注释告诉你它提取到 Excel 中的内容。子元素似乎不像在我构建的其他宏中那样工作。我认为这样的事情会起作用:

Cells(1, 1) = Document.getElementById("Y_1").getAttribute("rawvalue")

但这不起作用,我也试过了:

Cells(1, 1) = Document.getElementById("data_i6").getElementById("Y_1").innertext

这也不行。

【问题讨论】:

    标签: vba excel web-scraping


    【解决方案1】:

    解决方案非常简单。只需使用它的 `rawvalue 属性调用它。

    你可以这样做:

    使用Hardcoded delayfor loop 来检查所需值的可用性:

    Sub GetValue()
        Dim IE As New InternetExplorer, HTML As HTMLDocument, post As Object, elem As Object
    
        With IE
            .Visible = True
            .Navigate "http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear"
            While .Busy = True Or .ReadyState < 4: DoEvents: Wend
            Set HTML = .Document
        End With
    
        ''using hardcoded delay
        Application.Wait Now + TimeValue("00:00:05")
    
        For Each elem In HTML.getElementsByTagName("div")
            If elem.innerText = "741" Then MsgBox elem.getAttribute("rawvalue"): Exit For
        Next elem
    End Sub
    

    使用Explicit Wait

    Sub GetValue()
        Dim IE As New InternetExplorer, HTML As HTMLDocument, post As Object
    
        With IE
            .Visible = True
            .Navigate "http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear"
            While .Busy = True Or .ReadyState < 4: DoEvents: Wend
            Set HTML = .Document
        End With
    
        Do: Set post = HTML.querySelector("#data_i6 #Y_1"): DoEvents: Loop While post Is Nothing
    
        MsgBox post.getAttribute("rawvalue")
    End Sub
    

    此时输出:

    741131269
    

    【讨论】:

      【解决方案2】:

      以下内容应该能说明您遇到的一些问题。


      .querySelectorAll

      您提到的确切元素是.document.querySelectorAll 方法使用CSS 选择器#Y_1 返回的第二个索引。 # 表示 ID。

      从该网页返回以下内容(示例显示 - 不是全部):

      从上面你可以看到结果中索引为2返回了你想要的字符串。

      带有 ID 的 querySelectorAll? Id 不是单个元素的唯一标识符吗?

      这个 ID 出乎意料地不是页面上的单个元素所独有的。它发生了高达 27 次:

      这意味着您可以使用 .querySelectorAll 方法返回所有匹配项的 nodeList 并获取索引 2 处的项以获得结果。

      注意:

      如果你想要rawvalue旁边的长数字,741131269,然后解析返回元素的outerHTML

      Debug.Print Replace(Split(Split(a.item(2).outerHTML, "rawvalue=")(1), ">")(0), Chr$(34), vbNullString)
      

      .querySelector

      或者,您可以使用

      定位特定于 data_i6 的 id
      .document.querySelector("#data_i6")
      

      这个 CSS 选择器 (#data_i6) 返回整个行,因为它每年都有。如果使用.querySelector,无论如何您只会得到第一个项目,即第 1 年。

      您可以更具体地使用 CSS 选择器并添加额外的年份 ID 以获得感兴趣的年份:

      #data_i6 #Y_1
      


      代码:(querySelector 方法在 querySelectorAll 旁边被注释掉)

      Option Explicit
      Public Sub Get_Information()
          Dim IE As New InternetExplorer
      
          With IE
              .Visible = True
              .navigate "http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear"
              While .Busy = True Or .readyState < 4: DoEvents: Wend
      
              Dim a As Object, exitTime As Date
              exitTime = Now + TimeSerial(0, 0, 2)
      
              Do
                  DoEvents
                  On Error Resume Next
                  Set a = .document.querySelectorAll("#Y_1") ' .document.querySelector("#data_i6 #Y_1")
                  On Error GoTo 0
                  If Now > exitTime Then Exit Do
              Loop While a Is Nothing
      
              If a Is Nothing Then Exit Sub
      
              Debug.Print Split(Split(a.item(2).innerText, "rawvalue=")(0), ">")(0) 'Split(Split(a.innerText, "rawvalue=")(0), ">")(0)
              Debug.Print Replace(Split(Split(a.item(2).outerHTML, "rawvalue=")(1), ">")(0), Chr$(34), vbNullString) 'Replace(Split(Split(a.outerHTML, "rawvalue=")(1), ">")(0), Chr$(34), vbNullString)
      
              .Quit
          End With
      End Sub
      

      【讨论】:

      • 嗨,QHarr,终于在这个项目下班后坐下来了。是的!谢谢!!!这是我正在寻找的完美细分,我认为我的主要问题是不知道“outerHTML”一词的使用,我尝试引用“原始值”,但它对我使用并没有太大帮助内部文本或值键。这就是我用来报废其他页面的内容。非常感谢你做的这些。现在我将不得不在我身边做更多的工作来刮掉整张桌子!这会很有趣!
      【解决方案3】:

      尝试将“objCollection”声明为对象,将 strValue 声明为字符串,并在下面的代码中,将第一行中您声明的 http-request 的名称替换为:

      Document.body.innerHTML = YourHTTPRequest.responseText
      Set objCollection = Document.getElementsByClassName("rf_crow")
      
       For Each objElement In objCollection
      
           If objElement.ID = "Y_1" Then
               strValue = objElement.getAttribute("rawvalue")
               Exit For
           End If
      
       Next
      
       Cells(1, 1) = strValue
      

      【讨论】:

        【解决方案4】:

        这对你有用吗?

        Sub web_table_option_two()
            Dim HTMLDoc As New HTMLDocument
            Dim objTable As Object
            Dim lRow As Long
            Dim lngTable As Long
            Dim lngRow As Long
            Dim lngCol As Long
            Dim ActRw As Long
            Dim objIE As InternetExplorer
            Set objIE = New InternetExplorer
            objIE.Navigate "http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear"
        
            Do Until objIE.ReadyState = 4 And Not objIE.Busy
                DoEvents
            Loop
            Application.Wait (Now + TimeValue("0:00:03")) 'wait for java script to load
            HTMLDoc.body.innerHTML = objIE.Document.body.innerHTML
            With HTMLDoc.body
                Set objTable = .getElementsByTagName("table")
                For lngTable = 0 To objTable.Length - 1
                    For lngRow = 0 To objTable(lngTable).Rows.Length - 1
                        For lngCol = 0 To objTable(lngTable).Rows(lngRow).Cells.Length - 1
                            ThisWorkbook.Sheets("Sheet1").Cells(ActRw + lngRow + 1, lngCol + 1) = objTable(lngTable).Rows(lngRow).Cells(lngCol).innerText
                        Next lngCol
                    Next lngRow
                    ActRw = ActRw + objTable(lngTable).Rows.Length + 1
                Next lngTable
            End With
            objIE.Quit
        End Sub
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多