【问题标题】:I'm trying to scrape website data with Excel VBA我正在尝试使用 Excel VBA 抓取网站数据
【发布时间】:2018-10-27 04:37:57
【问题描述】:

所以我首先要说我对 VBA 很陌生。我正在尝试从this page 上的表中提取数据。就代码而言,我还没有完成太多,所以请放轻松。我正在寻找一些关于如何处理它以及是否可以完成的方向,我相信它可以。如果有人能够帮助指导我朝着正确的方向前进,将不胜感激。

Sub rgnbateamstats()

Dim appIE As Object
Set appIE = CreateObject("internetexplorer.application")


With appIE
.navigate "https://rotogrinders.com/team-stats/nba-earned?site=draftkings"
.Visible = True
End With

Do While appIE.Busy
DoEvents
Loop

Set allRowOfData = appIE.document.getElementById("proj-stats")

不确定从这里往哪里走,或者我是否走在正确的轨道上。

【问题讨论】:

  • 你应该看看at my post为什么单独使用ieObj.Busy是个坏主意。
  • 很好,我会把它添加进去。谢谢!

标签: excel vba web-scraping


【解决方案1】:

这将抓取该页面上的整个表格。

这个项目使用early-binding。您需要设置引用到:

  • Microsoft Internet 控件
  • Microsoft HTML 对象库

您可以在 VBE > 工具 > 参考中完成此操作。

我会说,这个网站在设置他们的表格时使用了一种非常奇怪的方法,找到一种体面的方法来完成这一点很有趣。

另外,您可能会或可能不会接受的另一件事是,此表中有 隐藏 列不会显示在网站上,但会显示在您的 Excel 文档中。如果您对此不满意,您可以在执行此代码后简单地删除或隐藏它们 - 或者如果您要修改它以防止在执行期间发生这种情况,那么您将获得更多权力。

Option Explicit

Sub rgnbateamstats()

    Const url$ = "https://rotogrinders.com/team-stats/nba-earned?site=draftkings"

    Dim IE As New InternetExplorer, doc As HTMLDocument
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets(1)
    
    With IE
        .Navigate url
        .Visible = True
        ieBusy IE
        Set doc = .Document
    End With
    
    Dim r As Long, c As Long, tCol As HTMLDivELement
    Dim subTbls(): subTbls = Array("rgt-bdy left", "rgt-bdy mid", "rgt-bdy right")
    
    Dim subTbl As Long        
    For subTbl = 0 To 2
        For Each tCol In getSubTblCols(doc, subTbls(subTbl)).getElementsByClassName("rgt-col")
            c = c + 1
            For r = 1 To tCol.getElementsByTagName("div").Length
                ws.Cells(r, c) = tCol.getElementsByTagName("div")(r - 1).innerText
            Next
        Next tCol
    Next subTbl

End Sub
Private Function getSubTblCols(doc As HTMLDocument, ByVal className$) As HTMLDivElement
    Dim tbl As HTMLTable
    Set tbl = doc.getElementById("proj-stats")
    Set getSubTblCols = tbl.getElementsByClassName(className)(0).Children(0). _
            Children(1)
End Function
Private Sub ieBusy(ieObj As InternetExplorer)
    With ieObj
        Do While .Busy Or .ReadyState < READYSTATE_COMPLETE
            DoEvents
        Loop
    End With
End Sub

好的,是时候试试这里发生了什么。

您的表格中有三个子表格。这是解释它的最佳方式,但这意味着您将首先使用以下行遍历每个子表:

For subTbl = 0 To 2

在该循环中,您将使用该行循环该子表的列:

For Each tCol In getSubTblCols(doc, subTbls(subTbl)).getElementsByClassName("rgt-col")

rgt-col 是每个表中列的类名 - 所以至少那部分很容易。函数getSubTblCols抓取数组subTbls()中子表的三个名称之一的主子表元素类名。

c 是您的 Excel 列号,r 是行号。您还为 HTML 的每个行号使用 r,但它使用 base 0,因此您必须减去 1。

然后使用单元格的innerText 属性获取单元格的值,将其放入电子表格中,然后冲洗并重复。

我已将您繁忙的网页功能移至新的子目录ieBusy。我还添加了.readyState 属性,因为正如我在my comment 中所述,.busy 本身充其量是不可靠的。

【讨论】:

  • 编辑 - 谢谢!这似乎工作得很好。我错过了黄色框中的参考资料。哎呀。
【解决方案2】:

虽然表格布局可能看起来有点奇怪,但实际上只需要 180 分即可。您可以按类名获取列,然后简单地循环行;而不是通常的行然后列的循环。

我使用CSS class selector 来抓取带有querySelectorAll 的列,即我通过它们的类名来定位列。这将返回一个包含每一列的nodeList。下面是前两列的示例(诚然,abbr 不可见)。列中的每一行都在div 中,所以如果我循环列,我会通过抓取关联的div 标记集合来获取每列中的行。然后我简单地循环那些写出来。

Option Explicit
Public Sub GetInfo()
    Dim IE As New InternetExplorer, iColumns As Object, iRow As Object, i As Long, j As Long, r As Long, c As Long
    Application.ScreenUpdating = False
    With IE
        .Visible = True
        .navigate "https://rotogrinders.com/team-stats/nba-earned?site=draftkings"

        While .Busy Or .readyState < 4: DoEvents: Wend

        Set iColumns = .document.querySelectorAll(".rgt-col")

        With ThisWorkbook.Worksheets("Sheet1")
            For i = 0 To iColumns.Length - 1
                c = c + 1: r = 0
                Set iRow = iColumns.item(i).getElementsByTagName("div")
                For j = 0 To iRow.Length - 1
                    r = r + 1
                    .Cells(r, c) = iRow(j).innerText
                Next
            Next
        End With
        Application.ScreenUpdating = True
        .Quit
    End With
End Sub

参考资料:

VBA > 工具 > 参考 > Microsoft Internet 控件

或更改为后期绑定:

Dim ie As Object
Set ie = CreateObject("InternetExplorer.Application")

【讨论】:

  • Tbh 我一直期待看到您的抓取方法。做得很好。
  • 所以我尝试了这个,但在“Dim IE As New InternetExplorer”上不断收到“编译错误” - 未定义用户定义的类型。我该如何克服这个问题?
  • 你需要去 VBA > Tools > References 并添加对 Microsoft Internet Controls 的引用。
  • 是的!我错过了那部分。试图编辑我的 cmets,但它不会让我。完美运行!
  • 不用担心。我应该添加它。我在 :-) 中编辑了参考
【解决方案3】:

尝试这部分提取第一列

Set allrowofdata = appIE.document.getElementById("proj-stats")

Set newobj = allrowofdata.getElementsByClassName("rgt-col")(0)

For Each x In newobj.Children
r = r + 1
Cells(r, 1).value = x.innerText
Next x

【讨论】:

  • 添加这个对第一列有效!看到它开始工作真是令人兴奋!现在要弄清楚如何修改以拉动其余部分。感谢您抢先一步!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 2020-03-12
相关资源
最近更新 更多