Invoke-WebRequest Canvas LMS API 分页

Invoke-WebRequest Canvas LMS API pagination

我似乎找不到关于这个主题的任何例子,我想知道如何去做。 任何人都可以给我举个例子或指出 link 如何使用调用网络请求在 powershell 中进行分页吗? 我面临的挑战是我正在制作 API 一次只调用 returns 100 行的服务器。为了获得更多行,我将不得不再次调用服务器。我不知道该怎么做。 如果有帮助,这里是 Canvas LMS 提供的 link 和我目前拥有的代码。

Pagination:

Pagination

Requests that return multiple items will be paginated to 10 items by default. You can set a custom per-page amount with the ?per_page parameter. There is an unspecified limit to how big you can set per_page to, so be sure to always check for the Link header.

To retrieve additional pages, the returned Link headers should be used. These links should be treated as opaque. They will be absolute urls that include all parameters necessary to retrieve the desired current, next, previous, first, or last page. The one exception is that if an access_token parameter is sent for authentication, it will not be included in the returned links, and must be re-appended.

Pagination information is provided in the Link header:

Link:
<https://<canvas>/api/v1/courses/:id/discussion_topics.json?opaqueA>; rel="current",
<https://<canvas>/api/v1/courses/:id/discussion_topics.json?opaqueB>;> rel="next",
<https://<canvas>/api/v1/courses/:id/discussion_topics.json?opaqueC>;> rel="first",
<https://<canvas>/api/v1/courses/:id/discussion_topics.json?opaqueD>;> rel="last" 

The possible rel values are:

current - link to the current page of results. next - link to the next page of results. prev - link to the previous page of results. first - link to the first page of results. last - link to the last page of results. These will only be included if they are relevant. For example, the first page of results will not contain a rel="prev" link. rel="last" may also be excluded if the total count is too expensive to compute on each request.

开头的产品

$curlly=""
$url_main="https://[instance].instructure.com/api/v1/accounts/1/courses?per_page=1"
$security_token="imhungry"
$header = @{"Authorization"="Bearer "+ $security_token; "rel"="last"}
$curlly=Invoke-WebRequest -Headers $header   -Method Get   -Uri $url_main   
$curlly = ConvertFrom-Json $curlly.Content
foreach($course in $curlly)
{
    $course.name
}
$curlly.Count

成品

 ##This is an example on how to use pagination in powershell
$url_main="https://[instance].instructure.com/api/v1/accounts/1/courses?per_page=100"
$security_token="boyimhungry"
$header = @{"Authorization"="Bearer "+ $security_token}
$purlly=Invoke-WebRequest -Headers $header   -Method Get   -Uri $url_main   
$curlly = ConvertFrom-Json $purlly.Content
$url_main = $purlly.Headers.Link.Split(",")[1].Replace("<","").Replace(">","") ## you can get away with just doing one replace("<","") but it looks neater this way
while( !$url_main.Contains("prev"))
{
$purlly=Invoke-WebRequest -Headers $header   -Method Get   -Uri $url_main   
$curlly += ConvertFrom-Json $purlly.Content
$url_main = $purlly.Headers.Link.Split(",")[1].Replace("<","").Replace(">","")
cls
$curlly.Count
$url_main
}
foreach($course in $curlly)
{
    $course.name
}
$curlly.Count

这看起来真的很痛苦。

在每个分页请求中,您将返回一个 Link header,其中包含他们描述的一个或多个 link。

出于您的目的(按顺序读取每个结果),您真正需要关心的只是 link rel=next link。你会一直调用那个,直到不再有 rel=next,这样你就知道你在最后一页了。

您没有提供相关部分;这不是 header。它可以让您确定要使用哪个 link,然后按原样使用 link。

所以你需要做什么的基本概述:

  1. 发出第一个请求。
  2. 通读返回的 Link header,找到与 rel=next 对应的那个(如果不存在,则完成)。
  3. 直接向您找到的 link 发出下一个请求。
  4. 再次解析 Link header,重复。

我知道您已经接受了答案,但我想我会提供我的代码示例以防万一有人需要。此示例正在获取我们所有 Canvas 用户的列表。不是一个糟糕的过程——大部分工作只用一个 4 行的 do..while 循环就完成了。

$token = "YOUR_ACCESS_TOKEN"
$headers = @{"Authorization"="Bearer "+$token}
$allCanvasUsers = New-Object System.Collections.ArrayList @()
$pageNumber = 1

Function RequestPageOfUsers($page) {
    $script:resultsPage = Invoke-WebRequest -Method GET -Headers $headers -Uri "https://$domain/api/v1/accounts/self/users?per_page=100&search_term=P00&page=$page"
    $usersPage = ConvertFrom-Json $resultsPage.Content

    foreach ($user in $usersPage) {
        $script:allCanvasUsers.Add($user)
    }
}

do {
    RequestPageOfUsers $pageNumber
    $pageNumber++
} while ($resultsPage.Headers.Link.Contains('rel="next"'))

David Baker 的回答非常棒,几乎 对我有用,但只返回一个页面。不知道为什么,但是 CONTAINS('...') 测试总是返回 FALSE。

为了让它工作,我不得不对 WHILE 条件做一个小改动。对我来说,返回的 ResultsPage 对象带有一个名为 RelationLink 的 属性,它是一个包含键值对的字典。分页结果集中的最后一页没有 'Next' 键。因此,我的 DO-WHILE 循环一直运行到发现 'Next' 值为空为止。

$Token = '<YOUR-TOKEN>'
$headers = @{"Authorization"="Bearer "+$token}
$allCanvasUsers = New-Object System.Collections.ArrayList @()
$pageNumber = 1

Function RequestPageOfUsers($page) {

    $script:resultsPage = Invoke-WebRequest `
        -Method GET `
        -Headers $headers `
        -Uri "https://<DOMAIN>:443/api/v1/accounts/self/users?per_page=100&page=$page"
    $usersPage = ConvertFrom-Json $resultsPage.Content

    foreach ($user in $usersPage) { 
        $script:allCanvasUsers.Add($user)
    }
}

do {
    RequestPageOfUsers $pageNumber
    $pageNumber++
} while ($resultsPage.RelationLink.Next -NE $NULL)