1

How would I pull the table data from Here?

I can see that each row is contained in a "team-name first" class. I would like to get the table into excel but using the from web option I can't see the table in the IE window. I think that VBA is the route that I need to take to get it. I tried some googling and youtube tutorials but I haven't had any success. Any help would be appreciated!

snip

**Edit Sorry I thought I attached my code. The problem is it is not loading the full page. So I think that is why I can't pull the data.

There should be a table showing here

Sub FetchNBADefense()

Dim IE As Object, obj As Object
Dim r As Long, c As Long, t As Long
Dim elemCollection As Object
Dim eRow As Long


Set IE = CreateObject("InternetExplorer.Application")

With IE

.Visible = True
.navigate ("https://stats.nba.com/teams/opponent/?sort=W&dir=-1")



While IE.readyState <> 4
    DoEvents
Wend

ThisWorkbook.Sheets("TeamDefenses").Range("A1:M60").ClearContents
Set elemColleciton = IE.document.getElementsByTagName("team-name first")
For t = 0 To (elemCollection.Length - 1)
    For r = 0 To (elemCollection(t).Rows.Cells.Length - 1)
        For c = 0 To (elemCollection(t).Rows(r).Cells.Length - 1)
        eRow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row

        ThisWorkbook.Worksheets(1).Cells(eRow, c + 1) = elemCollection(t).Rows(r).Cells(c).innerText
        Next c
    Next r
Next t

End With
Range("A1:M60").Columns.AutoFit
'Clear memory
Set IE = Nothing

End Sub

***New code: What am I missing? I see that it is "resultSet" instead of "resultSets" but still getting and Runt-time error '424': Object required

Option Explicit

Public Sub FetchNBAplayerpts()

Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.ClearContents

Dim json As Object
With CreateObject("MSXML2.XMLHTTP")
    .Open "GET", "https://stats.nba.com/stats/leagueLeaders?LeagueID=00&PerMode=PerGame&Scope=S&Season=2018-19&SeasonType=Regular+Season&StatCategory=PTS", False
    .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
    .send
    Set json = JsonConverter.ParseJson(.responseText)("resultSet")(1)
End With
Dim headers As Object, header As Variant, headerOutput(), i As Long, rowInfo As Object, iRow As Object
Set headers = json("headers")
Set rowInfo = json("rowSet")
ReDim headerOutput(1 To headers.Count)
For Each header In headers
    i = i + 1
    headerOutput(i) = header
Next

Dim rowData(), r As Long, c As Long, Item As Variant
ReDim rowData(1 To rowInfo.Count, 1 To UBound(headerOutput))

For Each iRow In rowInfo
    r = r + 1: c = 1
    For Each Item In iRow
        rowData(r, c) = Item
    c = c + 1
    Next
Next

With ThisWorkbook.Worksheets("PlayerPts")
    .Cells(1, 1).Resize(1, UBound(headerOutput)) = headerOutput
    .Cells(2, 1).Resize(UBound(rowData, 1), UBound(rowData, 2)) = rowData
End With

End Sub
Thad
  • 23
  • 4
  • 3
    What have you tried? There are myriad solutions for web-scraping with VBA, you might also want to search for "selenium VBA". – BruceWayne Oct 30 '18 at 15:46
  • Have a look through some of the existing solutions. This is doable. Include what you have tried and explain the problem you are having. – QHarr Oct 30 '18 at 17:19
  • When you inspect can you see SCRIPT5: Access is denied. ? – QHarr Oct 30 '18 at 17:46
  • Sorry I was on the road but I posted an edit. I rushed through the post this morning before heading out and forgot to add my script. – Thad Oct 30 '18 at 18:07
  • @QHarr No? I see all the data I want to pull in the html. ([Screenshot of Info](https://i.stack.imgur.com/rEIUY.png)) – Thad Oct 30 '18 at 18:21

1 Answers1

3

From discussion with @TylerH and @LuckyKleinschmidt it would seem that the page uses a javascript method, includes , that is not supported in IE. That may be why the page isn't fully rendering as a script isn't running. See here. The workaround would be to use indexOf method in the relevant script. I guess the developer(s) didn't worry about the small market share for IE.

Browser support:

enter image description here

If you happen to inspect in Chrome/Firefox dev tools, or using a web traffic monitoring tool such as fiddler, you will see that there is actually an XMLHTTP request sent to retrieve the data to a different source and that actually you can use that URL to issue an XMLTTP request. It is a much faster retrieval method than opening a browser so something of a win in this case. The response is a JSON response which can be handled with a JSON parser. I use JSONConverter.bas which you download and add to your project.

After adding the .bas from the above link to your project you then add a reference via VBE > Tools > References > Microsoft Scripting Runtime.

The JSON response has the following structure (Sample shown):

enter image description here

The { means a dictionary so you access by key, the [ means a collection so you access by index (or, For Each over as I do). "" means a string literal so you read as is. Test the data type and handle as required.

There is more info retrieved by this method than is visible on page.

Sample of output:

enter image description here


VBA:

Option Explicit    
Public Sub GetTable()       
    Dim json As Object
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", "https://stats.nba.com/stats/leaguedashteamstats?Conference=&DateFrom=&DateTo=&Division=&GameScope=&GameSegment=&LastNGames=0&LeagueID=00&Location=&MeasureType=Opponent&Month=0&OpponentTeamID=0&Outcome=&PORound=0&PaceAdjust=N&PerMode=PerGame&Period=0&PlayerExperience=&PlayerPosition=&PlusMinus=N&Rank=N&Season=2018-19&SeasonSegment=&SeasonType=Regular+Season&ShotClockRange=&StarterBench=&TeamID=0&VsConference=&VsDivision=", False
        .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
        .send
        Set json = JsonConverter.ParseJson(.responseText)("resultSets")(1)
    End With
    Dim headers As Object, header As Variant, headerOutput(), i As Long, rowInfo As Object, iRow As Object
    Set headers = json("headers")
    Set rowInfo = json("rowSet")
    ReDim headerOutput(1 To headers.Count)
    For Each header In headers
        i = i + 1
        headerOutput(i) = header
    Next

    Dim rowData(), r As Long, c As Long, item As Variant
    ReDim rowData(1 To rowInfo.Count, 1 To UBound(headerOutput))

    For Each iRow In rowInfo
        r = r + 1: c = 1
        For Each item In iRow
            rowData(r, c) = item
            c = c + 1
        Next
    Next

    With ThisWorkbook.Worksheets("Sheet1")
        .Cells(1, 1).Resize(1, UBound(headerOutput)) = headerOutput
        .Cells(2, 1).Resize(UBound(rowData, 1), UBound(rowData, 2)) = rowData
    End With

End Sub

The XHR request in dev tools (network tab):

enter image description here

QHarr
  • 83,427
  • 12
  • 54
  • 101
  • Whoa. That is way more advanced than I thought it was. So I would have never got there the way I was going? – Thad Oct 30 '18 at 18:54
  • would you like me to explain anything? – QHarr Oct 30 '18 at 18:57
  • I used https://www.telerik.com/fiddler You can also see in the network tab of Chrome if you press F5 whilst in network tab. – QHarr Oct 30 '18 at 19:13
  • 1
    Okay, I see. So doing the same steps I found [this](https://stats.nba.com/stats/leagueLeaders?LeagueID=00&PerMode=PerGame&Scope=S&Season=2018-19&SeasonType=Regular+Season&StatCategory=PTS) Refer to edit ^^ – Thad Oct 30 '18 at 19:59
  • I didn't have enough room in the reply so I edited the main with the code and question. – Thad Oct 30 '18 at 20:13
  • Try running just my code as posted in my answer first. – QHarr Oct 30 '18 at 20:16
  • It works flawlessly for team stats measure types (The field MeasureType must match the regular expression '^ **(Base)** | **(Advanced)** | **(Misc)** |(Four Factors)| **(Scoring)** | **(Opponent)** |(Usage)| **(Defense)** $'.) Tried on all bold. When I change the link and "resultSets" to "resultSet" it gives me that error. I cross referenced both the new link/old link and that seemed to be the only difference. – Thad Oct 30 '18 at 20:29
  • I haven't inspected the actual construction. I have merely noted I can use the captured XHR url to create my own XHR. Then parse the JSON response. – QHarr Oct 30 '18 at 20:30
  • Do you have a new question? I believe my current answer gets the results as shown in that page. Are you after a more generic approach as a new question? Would be interesting. – QHarr Oct 30 '18 at 20:31