我可以为其他网站回收使用webscraping Excel VBA脚本吗?

时间:2018-10-27 21:40:58

标签: excel vba excel-vba web-scraping

因此,在我的上一篇文章Here中,所有参与其中的人都提供了很大帮助,但不幸的是,我没有从中学到很多。是否可以回收这些脚本之一来抓取this page并将已确认/计划的阵容拉入Excel?查看html时,我发现它们位于“ lineups is-compact” div类中,然后分隔为“ lineup is-nba” div类。

我正在尝试获取团队名称,玩家名称以及期望/确认的信息。

以下是其他网站,它们提供的信息相同,因此更容易提取。

RotoGrinders <为其他代码创建的相同位置 BB Monster

这是我最终使用的代码,因为对于其他任务而言,修改起来似乎更简单。男孩,我错了。

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

请记住,我有4天的经验。菜鸟无所不在。

1 个答案:

答案 0 :(得分:2)

有关网页抓取的一种有趣且具有挑战性的事情是,每个站点通常都是不同的,并且属于同一站点的页面通常可能会有所不同。我认识到您只有很少的经验,因此恐怕以下内容会有所学习。您的其他答案的脚本非常基础,因为其中表的列先是循环的,然后是行。

所有这一切的可转移部分是学习如何阅读HTML,确定何时使用XMLHTTP(我在下面使用,这是一种更快的检索方法,但不会检索页面中的所有内容-特别是在页面中包含大量JavaScript的情况下)而不是基于浏览器的解决方案。练习使用检查/开发工具来练习选择信息。

然后是通常每次使用的通用代码位,例如,使用IE时,您几乎总是具有相同的连接代码行和等待代码行。使用xmlHttp时,您通常还会重复使用开放代码行。但是,由于网站通常大不相同,因此您每次都需要探索如何解析DOM以获得所需的信息。对于属于同一站点/主机的页面,如果其开发人员的页面设计一致,则可以重新使用更多代码。只是不要以为是这样。

以下脚本使用querySelectorAll(在这种情况下为HTMLDocument的一种方法)通过匹配class names上的元素来初始生成nodeLists

以下这些行生成您可能会想到的列表。列表中的每个元素都具有相同的类名。

Set teamsVisitors = .querySelectorAll(".lineup__team.is-visit")
Set teamsHomies = .querySelectorAll(".lineup__team.is-home")
Set nickNamesVisitors = .querySelectorAll(".lineup__mteam.is-visit")
Set nickNamesHomies = .querySelectorAll(".lineup__mteam.is-home")
Set visitors = .querySelectorAll(".lineup__list.is-visit") '  then by li
Set homies = .querySelectorAll(".lineup__list.is-home") ' then by li

因此,让我们看一下其中一个列表。与

关联的nodeList
Set teamsVisitors = .querySelectorAll(".lineup__team.is-visit")

您可以看到这是如何将4个访客团队的2个字母的名称收集到nodeList中的(您可以考虑收集,但不能For Each收集,实际上更像是数组)。

我给变量赋予了相当描述性的名称,因此您可以了解每个列表中的内容,但是如果不确定,可以进入开发人员工具(Chrome中的F12,FireFox),在“元素”标签中突出显示任何HTML然后 Ctrl + F 弹出搜索HTML框,并将""querySelectorAll之间的文本输入到该框中,例如.lineup__team.is-visit

您可以看到它在HTML中返回CSS选择器的匹配数。您可以使用enter循环浏览它们。

因此,我有一系列nodeList。每个索引,例如每个0中的索引nodeList与相同的匹配有关。因此,在索引0,我有GS v BKN i.e. Warriors v Nets

我循环搜索nodeList,将匹配信息写到表格中。为了获得确认的/玩家信息,我需要进一步细分我拥有的nodeList

Set visitors = .querySelectorAll(".lineup__list.is-visit") '  then by li
Set homies = .querySelectorAll(".lineup__list.is-home") ' then by li

0中取索引visitors nodeList,我们有:

我们需要进一步细分此信息;仅仅使用类名是不够的。如果我们看一下HTML,我们实际上可以看到,各个项目被分成li列表标记元素:

这意味着我们可以使用.getElementsByTagName方法返回这些项目。例如:

homies.item(i).getElementsByTagName("li")

然后最终看起来像这样(示例):

在循环中,我将访问者写到左列,并在右边写出家。当我遍历原始nodeList中的索引(即每个匹配项)时,我在输出列号上添加了+3,这样您就可以在每个表中写出一个空格。


示例输出:

enter image description here


VBA:

Option Explicit
Public Sub GetMatchInfo()
    Dim sResponse As String, html As HTMLDocument
    Application.ScreenUpdating = False

    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", "https://www.rotowire.com/basketball/nba-lineups.php", False
        .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
        .send
        sResponse = StrConv(.responseBody, vbUnicode)
    End With

    Set html = New HTMLDocument

    Dim visitors As Object, teamsVisitors As Object, nickNamesVisitors As Object
    Dim homies As Object, teamsHomies As Object, nickNamesHomies As Object
    Dim i As Long, r As Long, c As Long, j As Long

    With html
        .body.innerHTML = sResponse
        Set teamsVisitors = .querySelectorAll(".lineup__team.is-visit")
        Set teamsHomies = .querySelectorAll(".lineup__team.is-home")
        Set nickNamesVisitors = .querySelectorAll(".lineup__mteam.is-visit")
        Set nickNamesHomies = .querySelectorAll(".lineup__mteam.is-home")
        Set visitors = .querySelectorAll(".lineup__list.is-visit") '  then by li
        Set homies = .querySelectorAll(".lineup__list.is-home") ' then by li
    End With

    With ThisWorkbook.Worksheets("Sheet1")
        r = 1: c = 1

        For i = 0 To teamsHomies.Length - 1
            .Cells(r, c) = teamsVisitors.item(i).innerText
            .Cells(r, c + 1) = teamsHomies.item(i).innerText

            r = r + 1
            .Cells(r, c) = nickNamesVisitors.item(i).innerText
            .Cells(r, c + 1) = nickNamesHomies.item(i).innerText

            Dim numHomiesLiElements As Long, numVisitorsLiElements As Long, maxNumberofLiElements As Long

            numHomiesLiElements = homies.item(i).getElementsByTagName("li").Length - 1
            numVisitorsLiElements = visitors.item(i).getElementsByTagName("li").Length - 1

            maxNumberofLiElements = IIf(numHomiesLiElements > numVisitorsLiElements, numHomiesLiElements, numVisitorsLiElements)
            For j = 0 To maxNumberofLiElements
                r = r + 1
                On Error Resume Next
                .Cells(r, c) = visitors.item(i).getElementsByTagName("li")(j).innerText
                .Cells(r, c + 1) = homies.item(i).getElementsByTagName("li")(j).innerText
                On Error GoTo 0
            Next

            r = 1: c = c + 3
        Next

    End With

    Application.ScreenUpdating = True

End Sub

参考(VBE>工具>参考):

  1. Microsoft HTML对象库

可帮助您的资源:

  1. getElementsByTagName
  2. CSS Class selectors
  3. XMLHTTP requests

有关改进的基于python的脚本,请参见此处:

https://stackoverflow.com/a/55626217/6241235