提问人:Spark 提问时间:11/11/2023 最后编辑:Spark 更新时间:11/11/2023 访问量:87
在 VBA 中为 API 分页创建循环
Creating a Loop for API Pagination in VBA
问:
我正在开发一个 VBA 脚本,用于与 Excel 中的 Clockify API 进行交互。在键中,我注意到静态值被用于页面参数,将 API 响应限制为最新的 1000 条记录。detailedFilter
为了解决此限制,我想创建一个循环,该循环以迭代方式调用 API,根据给定日期范围内的记录总数 () 调整页面参数。例如,如果是 3250,我需要使用页面值 1、2 和 3 进行 API 调用。entriesCount
entriesCount
API 响应包含一个名为该字段的字段,我可以使用该字段来计算记录总数。entriesCount
下面是当前代码的片段:
Public Sub Get2223()
Set httpCaller = New MSXML2.XMLHTTP60
body = "{""dateRangeStart"": ""2022-06-01T00:00:00.000"", " & vbLf & _
" ""dateRangeEnd"": ""2023-05-30T23:59:59.000"", " & vbLf & _
" ""detailedFilter"": {""page"": 1,""pageSize"": 1000}} "
httpCaller.Open "POST", "https://reports.api.clockify.me/v1/workspaces/KEY/reports/detailed"
httpCaller.setRequestHeader "X-Api-Key", "API_KEY"
httpCaller.setRequestHeader "Content-Type", "application/json"
httpCaller.send body
Dim json As Object, t As Object
Dim Data, i As Long, N As Long
Data = httpCaller.responseText
Set json = JsonConverter.ParseJson(Data)
N = json("timeentries").Count
If N < 1 Then
MsgBox "No timeentries in JSON", vbCritical
Exit Sub
End If
Dim dataArray() As Variant
ReDim dataArray(1 To N, 1 To 6)
i = 1
For Each t In json("timeentries")
dataArray(i, 1) = t("projectName")
If Not IsNull(t("taskName")) Then
dataArray(i, 2) = t("taskName")
End If
dataArray(i, 3) = t("description")
dataArray(i, 4) = t("clientName")
dataArray(i, 5) = t("timeInterval")("start")
dataArray(i, 6) = t("timeInterval")("duration")
i = i + 1
Next
Dim ws As Worksheet
Set ws = Sheets("Year2022")
Dim col: col = Array(1, 5, 9, 10, 11, 7)
For i = 0 To UBound(col)
ws.Cells(2, col(i)).Resize(N) = WorksheetFunction.Index(dataArray, 0, i + 1)
Next
End Sub
有人可以帮我创建一个循环来处理这种情况下的分页吗?我感谢任何指导或建议。
我尝试了多种方法,但没有成功
Dim httpCaller As MSXML2.XMLHTTP60, body As String
Set httpCaller = New MSXML2.XMLHTTP60
' Set your date range and initial page size
Dim startDate As String
Dim endDate As String
Dim pageSize As Long
startDate = "2022-06-01T00:00:00.000"
endDate = "2023-05-30T23:59:59.000"
pageSize = 1000
body = "{""dateRangeStart"": """ & startDate & """, " & vbLf & _
"""dateRangeEnd"": """ & endDate & """, " & vbLf & _
"""detailedFilter"": {""page"": 1, ""pageSize"": " & pageSize & "}} "
' Parse JSON response
Dim json As Object
Dim Data
Data = ""
httpCaller.Open "POST", "https://reports.api.clockify.me/v1/workspaces/KEY/reports/detailed"
httpCaller.setRequestHeader "X-Api-Key", "API_KEY"
httpCaller.setRequestHeader "Content-Type", "application/json"
' Send the request
httpCaller.send body
' Wait for the response to complete
Do While httpCaller.readyState <> 4
DoEvents
Loop
If httpCaller.Status = 200 Then
Data = httpCaller.responseText
Set json = JsonConverter.ParseJson(Data)
Dim totalPages As Long
totalPages = Application.WorksheetFunction.Ceiling(json("totals")("entriesCount") / pageSize, 1)
' Loop through additional pages
Dim currentPage As Long
For currentPage = 2 To totalPages
' Adjust the API call with the current page value
body = Replace(body, """page"": 1", """page"": " & currentPage)
httpCaller.send body
Do While httpCaller.readyState <> 4
DoEvents
Loop
If httpCaller.Status = 200 Then
Data = httpCaller.responseText
Set json = JsonConverter.ParseJson(Data)
Else
MsgBox "Error: " & httpCaller.Status & " - " & httpCaller.statusText, vbCritical
Exit Sub
End If
Next currentPage
Else
MsgBox "Error: " & httpCaller.Status & " - " & httpCaller.statusText, vbCritical
End If
答:
1赞
artodoro
11/11/2023
#1
我没有足够的声誉来发表评论,所以我会尝试立即正确回答:)
在第一个请求中,您发送页面为 1 且页面大小为 1000 的选项。
body = "{""dateRangeStart"": ""2022-06-01T00:00:00.000"", " & vbLf & _
" ""dateRangeEnd"": ""2023-05-30T23:59:59.000"", " & vbLf & _
" ""detailedFilter"": {""page"": 1,""pageSize"": 1000}} "
如果我理解正确,您需要在循环中更改页码并每次发送新的 POST 请求并接收 responseText(并将其解析为 JSON),如下所示:
' here is your code to get the number of pages
Dim PageNumber As Long
For PageNumber = 1 To PageNumbers
body = "{""dateRangeStart"": ""2022-06-01T00:00:00.000"", " & vbLf & _
" ""dateRangeEnd"": ""2023-05-30T23:59:59.000"", " & vbLf & _
" ""detailedFilter"": {""page"": {PageNumber},""pageSize"": 1000}} "
body = Replace(body, "{PageNumber}", PageNumber)
httpCaller.Open "POST", "https://reports.api.clockify.me/v1/workspaces/KEY/reports/detailed"
httpCaller.setRequestHeader "X-Api-Key", "API_KEY"
httpCaller.setRequestHeader "Content-Type", "application/json"
httpCaller.send body
' do smth...
Next
评论
0赞
Spark
11/11/2023
它仍然无法正常工作@artodoro
2赞
Tim Williams
11/11/2023
#2
也许是这样的东西。我不能测试,所以不能花太多时间在上面。
Option Explicit
Const WKSPACE_KEY As String = "keygoeshere"
Const API_KEY As String = "xxxxxxxxxxxxxxxxxxx"
Public Sub Get2223()
Const PER_PAGE As Long = 1000
Dim result As Object, dStart As String, dEnd As String, pgNum As Long, totResults As Long
Dim entries As Object, numPages As Long
dStart = "2022-06-01T00:00:00.000"
dEnd = "2023-05-30T23:59:59.000"
pgNum = 1
Do
Set result = ReportsDetailed(dStart, dEnd, pgNum, PER_PAGE)
If result Is Nothing Then Exit Sub 'got no response
If pgNum = 1 Then
totResults = CLng(result("totals")("entriesCount"))
numPages = Application.Ceiling(totResults / PER_PAGE, 1)
End If
Set entries = result("timeentries")
'process entries
pgNum = pgNum + 1
If pgNum > numPages Then Exit Do
Loop
End Sub
Function ReportsDetailed(dStart As String, dEnd As String, pageNum As Long, perPage As Long) As Object
Dim httpCaller As Object, body As String
Set httpCaller = New MSXML2.XMLHTTP60
body = "{""dateRangeStart"": """ & dStart & """, " & vbLf & _
" ""dateRangeEnd"": """ & dEnd & """, " & vbLf & _
" ""detailedFilter"": {""page"": " & pageNum & ",""pageSize"": " & perPage & "}} "
httpCaller.Open "POST", "https://reports.api.clockify.me/v1/workspaces/" & _
WKSPACE_KEY & "/reports/detailed"
httpCaller.setRequestHeader "X-Api-Key", API_KEY
httpCaller.setRequestHeader "Content-Type", "application/json"
httpCaller.send body
If httpCaller.Status = 200 Then
Set ReportsDetailed = JsonConverter.ParseJson(httpCaller.responseText)
Else
MsgBox "Error in ReportsDetailed: " & httpCaller.Status & " - " & httpCaller.StatusText, vbCritical
End If
End Function
评论
0赞
Spark
11/14/2023
感谢您发布答案,但我在同一行上遇到了我无法修复的相同错误,我不是可以像您一样修复该代码的专家。Run time error 5 - Invalid procedure or call argument
0赞
Tim Williams
11/14/2023
失败时的价值是什么?totResults
0赞
Spark
11/14/2023
我尝试并检查了使用它的调试结果0
Debug.Print totalResults
0赞
Spark
11/14/2023
totResults
value 是0
0赞
Tim Williams
11/14/2023
好像没有记录吗?您需要添加一些代码来处理这种情况......
评论
json("totals")("entriesCount")
应该告诉您总共有多少个条目,因此您需要向 etc 发出额外的请求,直到您获取所有条目。或者,如果 pageSize 尚未达到其最大值,则增加 pageSize(编辑:看起来它的最大值为 1000,因此您需要分页)。page:2
run time error - Invalid procedure call or argument
totalPages = Application.WorksheetFunction.Ceiling(json("totals")("entriesCount") / pageSize, 1)
Ceiling Function