使用密钥中的索引号动态遍历JSON请求

时间:2018-11-07 21:57:23

标签: json excel vba web-scraping

我写了以下VBA宏:

Sub getLineUps()

Dim lastRow As Long
Dim strURL As String
Dim strJSON As String 
Dim strMatchID As String
Dim strIndex As Integer
Dim i, x As Integer
Dim Json As Object


lastRow = Range("A8").CurrentRegion.Rows.Count

For x = 9 To lastRow
   strMatchID = Cells(9, 1).Value
   strURL = "https://api.football-data.org/v2/matches/" & strMatchID
   Set MyRequest = CreateObject("WinHttp.WinHttpRequest.5.1")
   MyRequest.Open "Get", strURL
   MyRequest.setRequestHeader "X-Auth-Token", "personal_password"
   MyRequest.Send
   Set Json = JsonConverter.ParseJson(MyRequest.ResponseText)

   For Each Item In Json("match")("homeTeam")("lineup")
      Cells(9, 11).Value = Item(0)("name")
      Cells(9, 12).Value = Item(1)("name")
      Cells(9, 13).Value = Item(2)("name")
      Cells(9, 14).Value = Item(3)("name")
      Cells(9, 15).Value = Item(4)("name")
      Cells(9, 16).Value = Item(5)("name")
      Cells(9, 17).Value = Item(6)("name")
      Cells(9, 18).Value = Item(7)("name")
      Cells(9, 19).Value = Item(8)("name")
      Cells(9, 20).Value = Item(9)("name")
      Cells(9, 21).Value = Item(10)("name")
   Next
Next

End Sub

运行此宏会给我以下错误消息:运行时错误'13':在以下行上键入不匹配Cells(9, 11).Value = Item(0)("name") 我的JSON请求的输出如下所示:

{
  'head2head': {
    'numberOfMatches': 7,
    'totalGoals': 19,
    'homeTeam': {
      'wins': 1,
      'draws': 1,
      'losses': 5
    },
    'awayTeam': {
      'wins': 5,
      'draws': 1,
      'losses': 1
    }
  },
  'match': {
    'id': 233132,
    'competition': {
      'id': 2021,
      'name': 'Premier League'
    },
    'season': {
      'id': 151,
      'startDate': '2018-08-10',
      'endDate': '2019-05-12',
      'currentMatchday': 11,
      'winner': None,
      'availableStages': [
        'REGULAR_SEASON'
      ]
    },
    'utcDate': '2018-11-03T12:30:00Z',
    'status': 'FINISHED',
    'minute': None,
    'attendance': 10792,
    'venue': 'Vitality Stadium',
    'matchday': 11,
    'stage': 'REGULAR_SEASON',
    'group': 'Regular Season',
    'lastUpdated': '2018-11-05T05:03:52Z',
    'score': {
      'winner': 'AWAY_TEAM',
      'duration': 'REGULAR',
      'fullTime': {
        'homeTeam': 1,
        'awayTeam': 2
      },
      'halfTime': {
        'homeTeam': 1,
        'awayTeam': 1
      },
      'extraTime': {
        'homeTeam': None,
        'awayTeam': None
      },
      'penalties': {
        'homeTeam': None,
        'awayTeam': None
      }
    },
    'homeTeam': {
      'id': 1044,
      'name': 'AFC Bournemouth',
      'coach': {
        'id': 11594,
        'name': 'Eddie Howe',
        'countryOfBirth': 'England',
        'nationality': 'England'
      },
      'captain': {
        'id': 8232,
        'name': 'Simon Francis',
        'shirtNumber': 2
      },
      'lineup': [
        {
          'id': 8247,
          'name': 'Ryan Fraser',
          'position': 'Midfielder',
          'shirtNumber': 24
        },
        {
          'id': 3327,
          'name': 'Lewis Cook',
          'position': 'Midfielder',
          'shirtNumber': 16
        },
        {
          'id': 8229,
          'name': 'Asmir Begović',
          'position': 'Goalkeeper',
          'shirtNumber': 27
        },
        {
          'id': 3737,
          'name': 'Jefferson Lerma',
          'position': 'Midfielder',
          'shirtNumber': 8
        },
        {
          'id': 8231,
          'name': 'Adam Smith',
          'position': 'Defender',
          'shirtNumber': 15
        },
        {
          'id': 8240,
          'name': 'Nathan Aké',
          'position': 'Defender',
          'shirtNumber': 5
        },
        {
          'id': 8251,
          'name': 'Callum Wilson',
          'position': 'Attacker',
          'shirtNumber': 13
        },
        {
          'id': 4321,
          'name': 'David Brooks',
          'position': 'Attacker',
          'shirtNumber': 20
        },
        {
          'id': 8232,
          'name': 'Simon Francis',
          'position': 'Defender',
          'shirtNumber': 2
        },
        {
          'id': 8234,
          'name': 'Steve Cook',
          'position': 'Defender',
          'shirtNumber': 3
        },
        {
          'id': 8242,
          'name': 'Junior Stanislas',
          'position': 'Midfielder',
          'shirtNumber': 19
        }
      ],
      'bench': [
        {
          'id': 8227,
          'name': 'Artur Boruc',
          'position': 'Goalkeeper',
          'shirtNumber': 1
        },
        {
          'id': 8233,
          'name': 'Charlie Daniels',
          'position': 'Defender',
          'shirtNumber': 11
        },
        {
          'id': 8246,
          'name': 'Andrew Surman',
          'position': 'Midfielder',
          'shirtNumber': 6
        },
        {
          'id': 8243,
          'name': 'Dan Gosling',
          'position': 'Midfielder',
          'shirtNumber': 4
        },
        {
          'id': 8255,
          'name': 'Jermain Defoe',
          'position': 'Attacker',
          'shirtNumber': 18
        },
        {
          'id': 8254,
          'name': 'Jordon Ibe',
          'position': 'Attacker',
          'shirtNumber': 10
        },
        {
          'id': 8253,
          'name': 'Lys Mousset',
          'position': 'Attacker',
          'shirtNumber': 9
        }
      ]
    },
    'awayTeam': {
      'id': 66,
      'name': 'Manchester United FC',
      'coach': {
        'id': 11613,
        'name': 'José Mourinho',
        'countryOfBirth': 'Portugal',
        'nationality': 'Portugal'
      },
      'captain': {
        'id': 3317,
        'name': 'Ashley Young',
        'shirtNumber': 18
      },
      'lineup': [
        {
          'id': 3188,
          'name': 'David De Gea',
          'position': 'Goalkeeper',
          'shirtNumber': 1
        },
        {
          'id': 7909,
          'name': 'Mata',
          'position': 'Attacker',
          'shirtNumber': 8
        },
        {
          'id': 7896,
          'name': 'Chris Smalling',
          'position': 'Defender',
          'shirtNumber': 12
        },
        {
          'id': 7911,
          'name': 'Alexis Sánchez',
          'position': 'Attacker',
          'shirtNumber': 7
        },
        {
          'id': 3372,
          'name': 'Anthony Martial',
          'position': 'Attacker',
          'shirtNumber': 11
        },
        {
          'id': 7898,
          'name': 'Luke Shaw',
          'position': 'Defender',
          'shirtNumber': 23
        },
        {
          'id': 3492,
          'name': 'Victor Nilsson-Lindelöf',
          'position': 'Defender',
          'shirtNumber': 2
        },
        {
          'id': 3317,
          'name': 'Ashley Young',
          'position': 'Midfielder',
          'shirtNumber': 18
        },
        {
          'id': 3438,
          'name': 'Nemanja Matić',
          'position': 'Midfielder',
          'shirtNumber': 31
        },
        {
          'id': 3366,
          'name': 'Paul Pogba',
          'position': 'Midfielder',
          'shirtNumber': 6
        },
        {
          'id': 3232,
          'name': 'Fred',
          'position': 'Midfielder',
          'shirtNumber': 17
        }
      ],
      'bench': [
        {
          'id': 3202,
          'name': 'Sergio Romero',
          'position': 'Goalkeeper',
          'shirtNumber': 22
        },
        {
          'id': 7897,
          'name': 'Phil Jones',
          'position': 'Defender',
          'shirtNumber': 4
        },
        {
          'id': 7900,
          'name': 'Matteo Darmian',
          'position': 'Defender',
          'shirtNumber': 36
        },
        {
          'id': 3325,
          'name': 'Jesse Lingard',
          'position': 'Midfielder',
          'shirtNumber': 14
        },
        {
          'id': 7904,
          'name': 'Ander Herrera',
          'position': 'Midfielder',
          'shirtNumber': 21
        },
        {
          'id': 7905,
          'name': 'Scott McTominay',
          'position': 'Midfielder',
          'shirtNumber': 39
        },
        {
          'id': 3331,
          'name': 'Marcus Rashford',
          'position': 'Attacker',
          'shirtNumber': 10
        }
      ]
    },
    'goals': [
      {
        'minute': 11,
        'extraTime': None,
        'type': 'REGULAR',
        'team': {
          'id': 1044,
          'name': 'AFC Bournemouth'
        },
        'scorer': {
          'id': 8251,
          'name': 'Callum Wilson'
        },
        'assist': {
          'id': 8242,
          'name': 'Junior Stanislas'
        }
      },
      {
        'minute': 35,
        'extraTime': None,
        'type': 'REGULAR',
        'team': {
          'id': 66,
          'name': 'Manchester United FC'
        },
        'scorer': {
          'id': 3372,
          'name': 'Anthony Martial'
        },
        'assist': {
          'id': 7911,
          'name': 'Alexis Sánchez'
        }
      },
      {
        'minute': 90,
        'extraTime': 2,
        'type': 'REGULAR',
        'team': {
          'id': 66,
          'name': 'Manchester United FC'
        },
        'scorer': {
          'id': 3331,
          'name': 'Marcus Rashford'
        },
        'assist': None
      }
    ],
    'bookings': [
      {
        'minute': 54,
        'team': {
          'id': 66,
          'name': 'Manchester United FC'
        },
        'player': {
          'id': 7898,
          'name': 'Luke Shaw'
        },
        'card': 'YELLOW_CARD'
      },
      {
        'minute': 58,
        'team': {
          'id': 1044,
          'name': 'AFC Bournemouth'
        },
        'player': {
          'id': 3737,
          'name': 'Jefferson Lerma'
        },
        'card': 'YELLOW_CARD'
      },
      {
        'minute': 63,
        'team': {
          'id': 1044,
          'name': 'AFC Bournemouth'
        },
        'player': {
          'id': 8242,
          'name': 'Junior Stanislas'
        },
        'card': 'YELLOW_CARD'
      },
      {
        'minute': 64,
        'team': {
          'id': 1044,
          'name': 'AFC Bournemouth'
        },
        'player': {
          'id': 8251,
          'name': 'Callum Wilson'
        },
        'card': 'YELLOW_CARD'
      },
      {
        'minute': 82,
        'team': {
          'id': 66,
          'name': 'Manchester United FC'
        },
        'player': {
          'id': 3317,
          'name': 'Ashley Young'
        },
        'card': 'YELLOW_CARD'
      },
      {
        'minute': 83,
        'team': {
          'id': 1044,
          'name': 'AFC Bournemouth'
        },
        'player': {
          'id': 8231,
          'name': 'Adam Smith'
        },
        'card': 'YELLOW_CARD'
      },
      {
        'minute': 90,
        'team': {
          'id': 66,
          'name': 'Manchester United FC'
        },
        'player': {
          'id': 3331,
          'name': 'Marcus Rashford'
        },
        'card': 'YELLOW_CARD'
      }
    ],
    'substitutions': [
      {
        'minute': 56,
        'team': {
          'id': 66,
          'name': 'Manchester United FC'
        },
        'playerOut': {
          'id': 7909,
          'name': 'Mata'
        },
        'playerIn': {
          'id': 3331,
          'name': 'Marcus Rashford'
        }
      },
      {
        'minute': 56,
        'team': {
          'id': 66,
          'name': 'Manchester United FC'
        },
        'playerOut': {
          'id': 3232,
          'name': 'Fred'
        },
        'playerIn': {
          'id': 7904,
          'name': 'Ander Herrera'
        }
      },
      {
        'minute': 68,
        'team': {
          'id': 1044,
          'name': 'AFC Bournemouth'
        },
        'playerOut': {
          'id': 3327,
          'name': 'Lewis Cook'
        },
        'playerIn': {
          'id': 8243,
          'name': 'Dan Gosling'
        }
      },
      {
        'minute': 74,
        'team': {
          'id': 1044,
          'name': 'AFC Bournemouth'
        },
        'playerOut': {
          'id': 8247,
          'name': 'Ryan Fraser'
        },
        'playerIn': {
          'id': 8254,
          'name': 'Jordon Ibe'
        }
      },
      {
        'minute': 78,
        'team': {
          'id': 66,
          'name': 'Manchester United FC'
        },
        'playerOut': {
          'id': 7911,
          'name': 'Alexis Sánchez'
        },
        'playerIn': {
          'id': 3325,
          'name': 'Jesse Lingard'
        }
      },
      {
        'minute': 90,
        'team': {
          'id': 1044,
          'name': 'AFC Bournemouth'
        },
        'playerOut': {
          'id': 8242,
          'name': 'Junior Stanislas'
        },
        'playerIn': {
          'id': 8246,
          'name': 'Andrew Surman'
        }
      }
    ],
    'referees': [
      {
        'id': 11520,
        'name': 'Paul Tierney',
        'nationality': None
      },
      {
        'id': 11606,
        'name': 'Constantine Hatzidakis',
        'nationality': None
      },
      {
        'id': 11576,
        'name': 'Darren Cann',
        'nationality': None
      },
      {
        'id': 11487,
        'name': 'Kevin Friend',
        'nationality': None
      }
    ]
  }
}

尽管此输出未显示,但我们需要一个索引号。我通过使用Python检查输出来观察到这一点。

enter image description here

enter image description here

我的VBA宏到底出了什么问题,因为它没有显示所需的输出? 此外,我该如何通过以下方式重新编写宏:

previous code
...

Set Json = JsonConverter.ParseJson(MyRequest.ResponseText)
i = 1
For Each Item In Json("match")("homeTeam")("lineup")
  Cells(9, i).Value = Item(indexnumber??)("name")
  i = i + 1 

如何正确指定此版本中的索引号?

非常感谢您

借助QHarr解决方案

Option Explicit
Public Sub ReadValues()
Dim fso As Object, stream As Object, jsonText, jsonInput As String, item As 
Object
Dim json As Object, ws As Worksheet, i As Long
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set fso = CreateObject("Scripting.FileSystemObject")
Set stream = fso.OpenTextFile("C:\Users\HJA\Desktop\Betting\line_up.json", 
ForReading)
jsonText = stream.ReadAll

ws.Cells(1, 1).Value = jsonText
ws.Cells(7,1).Formula = "=SUBSTITUTE(SUBSTITUTE(A1,A2,A3),A5,A6)"
jsonInput = Cells(7, 1).Value
MsgBox jsonInput

Set json = JsonConverter.ParseJson(jsonInput)("match")("homeTeam")("lineup") 'collection of dictionaries
i = 1
For Each item In json
   ws.Cells(9, i).Value = item("name")
   i = i + 1
Next

结束子

1 个答案:

答案 0 :(得分:2)

通过将'交换为""并将其None包装为"None"来更正JSON之后,可以使用以下命令获取名称。注意我正在从文件中读取JSON。您可以将其删除并替换为

Set Json = JsonConverter.ParseJson(MyRequest.ResponseText)("match")("homeTeam")("lineup")

您正在处理词典的集合,因此您可以在循环中通过键访问名称(每个项目都是词典,而不是集合)。

将您的CreateObject("WinHttp.WinHttpRequest.5.1")放在循环之前。连续重新创建和销毁对象没有任何意义。只需创建一次,然后在子代码末尾超出范围即可。

如果使用currentRegion在数据区域中有任何空白行,则可能返回错误的结束行。

Option Explicit
Public Sub ReadValues()
    Dim fso As Object, stream As Object, jsonText As String, item As Object
    Dim json As Object, ws As Worksheet, i As Long
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set stream = fso.OpenTextFile("C:\Users\User\Desktop\test.json", ForReading)
    jsonText = stream.ReadAll
    stream.Close

    Set json = JsonConverter.ParseJson(jsonText)("match")("homeTeam")("lineup") 'collection of dictionaries
    i = 1
    For Each item In json
       ws.Cells(9, i).Value =  item("name")
       i = i + 1
    Next
End Sub