Facebook Graph API 分页如何工作以及如何使用它迭代 facebook 用户提要?

How does Facebook Graph API Pagination works and how to iterate facebook user feed with it?

我有一个 facebook Graph API 调用来获取 facebook 用户提要:

dynamic myFeed = await fb.GetTaskAsync(
                    ("me/feed?fields=id,from {{id, name, picture{{url}} }},story,picture,link,name,description," +
                    "message,type,created_time,likes,comments")
                    .GraphAPICall(appsecret_proof));

上面 return 是一些最新的用户帖子,说是 21 或 22 个帖子,但不是完整的用户帖子列表。 我搜索了一种使用 facebook 分页遍历用户提要的方法,最终找到了适用于 facebook Offset 分页的解决方案。

dynamic myFeed = await fb.GetTaskAsync(
                    ("me/feed?fields=id,from {{id, name, picture{{url}} }},story,picture,link,name,description," +
                    "message,type,created_time,likes,comments")
                    .GraphAPICall(appsecret_proof), new {limit = "1000", offset = "21" });

这让我离我想要实现的目标又近了一步,但我认为这不是实现它的理想方式,而且它并不是 return 所有用户的帖子。 有什么解决方法吗?请帮忙。

P.S: 我正在使用 Facebook C# SDK。

更新 1: 根据杰里米的回答。看来 facebook 光标分页是满足我的要求的唯一正确选择。我想知道 C# facebook sdk 是否提供任何功能来迭代 Next Edges 以便我可以在一次调用中获取所有提要帖子,是否有任何可能的解决方案? P.S:我看过 facebook API 文档很多次,我知道节点、边和字段到底是什么,唯一不幸的是 facebook 还不支持 C# SDK,我也无法在 Facebook C# SDK 上找到合适的文档。

首先介绍一些术语:

节点 - 基本上"things" 例如用户、照片、页面、评论
edges - "things" 之间的联系,例如主页的照片或照片的评论
字段 - 有关这些 "things" 的信息,例如个人生日或主页名称

当您向节点或边缘发出 API 请求时,您通常不会在单个响应中收到该请求的所有结果。这是因为某些响应可能包含数千个对象,因此默认情况下大多数响应都是分页的。

要获取用户的所有帖子,您有 3 个选项:


基于光标的分页

基于光标的分页是最有效的分页方法,应尽可能使用。游标是指随机字符串,它标记数据列表中的特定项目。除非删除此项,否则光标将始终指向列表的同一部分,但如果删除了一项,则光标将失效。因此,您的应用不应存储任何旧游标或假设它们仍然有效。

读取支持游标分页的边缘时,您将看到以下JSON响应:

{
  "data": [
     ... Endpoint data is here
  ],
  "paging": {
    "cursors": {
      "after": "MTAxNTExOTQ1MjAwNzI5NDE=",
      "before": "NDMyNzQyODI3OTQw"
    },
    "previous": "https://graph.facebook.com/me/albums?limit=25&before=NDMyNzQyODI3OTQw"
    "next": "https://graph.facebook.com/me/albums?limit=25&after=MTAxNTExOTQ1MjAwNzI5NDE="
  }
}

To get all posts by a user you keep surfing the "next" edges (upserting new items). This is how I do it when I dump entire groups into RDBMS's for statistical analysis. Often you will see edges with nodes you have already encountered, that's why I mention to UPSERT (update if it exists otherwise insert).

基于时间的分页

时间分页用于使用指向数据列表中特定时间的 Unix 时间戳来浏览结果数据。

使用基于时间的分页端点时,您将看到以下 JSON 响应:

{
  "data": [
     ... Endpoint data is here
  ],
  "paging": {
    "previous": "https://graph.facebook.com/me/feed?limit=25&since=1364849754",
    "next": "https://graph.facebook.com/me/feed?limit=25&until=1364587774"
  }
}

要获取所有用户的帖子,您需要及时迭代。此方法将使您按顺序获得帖子,尽管可能希望它们 return 按 FaceBooks 边缘算法的顺序排列。

基于偏移的分页

当您不关心时间顺序而只想要特定数量的对象时,可以使用偏移分页 returned。仅当边缘不支持光标或基于时间的分页时才应使用此方法。

因此,您发现 Offset 最接近您想要的标准分页。然而:

并非所有 API 调用都支持基于偏移量的分页。为了获得一致的结果,我们建议您使用我们在响应中 return 的 previous/next 链接进行分页。

您可以在 FB API 文档中阅读所有这些内容。

https://developers.facebook.com/docs/graph-api/overview/
https://developers.facebook.com/docs/graph-api/using-graph-api/

最后,在做了一些研究并阅读了一些博客之后,我发现没有直接从 facebook API CAlls 一次获取所有用户供稿器 post 的方法。 要实现该功能,要么必须按照 Jeremy Thomson 的建议进行无限滚动,要么遍历不同的 facebook 数据页面,而不管 edge 支持哪种 facebook pagination 类型。就我想要一个没有用户 interference/actions 的进程而言,我肯定会选择第二个选项,即使用 while 循环遍历 facebook 数据页面。 为此,我们首先需要两个最重要的参数 (facebook access_token + (facebook appsecret_proof),如下所述:

var appsecret_proof = access_token.GenerateAppSecretProof();
var fb = new FacebookClient(access_token);

Point to be remembered: facebook access_token is generated by HttpContext class.

facebook API 呼叫将获得用户前 25 个馈线 post 如下:

dynamic myFeed = await fb.GetTaskAsync(
                    ("me/feed?fields=id,from {{id, name, picture{{url}} }},story,picture,link,name,description," +
                    "message,type,created_time,likes,comments")
                    .GraphAPICall(appsecret_proof));

上面的 API 调用 return 产生了一个 Json 数组,应该通过 Model View 属性对其进行水化,如下所示:

var postList = new List<FacebookPostViewModel>();
    foreach (dynamic post in myFeed.data)
       {
         postList.Add(DynamicExtension.ToStatic<FacebookPostViewModel>(post));
       }

到这里之前一切都很清楚,最重要的部分肯定是获取所有 facebook 用户 post 现在正在运行。为此,我们需要将 string NextPageUri 设置为空,如下所示:

string NextPageURI = string.Empty;

最后一部分是检查数据是否有另一个页面,如果是,应该迭代并将数据添加到 View Model 直到没有页面提升,如下所示:

while (myFeed.paging != null && myFeed.paging.next != null)
                {
                    NextPageURI = myFeed.paging.next;
                    var nextURL = GetNextPageQuery(NextPageURI, access_token);
                    dynamic nextPagedResult = await fb.GetTaskAsync(nextURL.GraphAPICall(appsecret_proof));
                    foreach (dynamic post in nextPagedResult.data)
                    {
                        postList.Add(DynamicExtension.ToStatic<FacebookPostViewModel>(post));
                    }
                }

这帮助我摆脱了面临的问题。但我还有另一项任务要处理。这是获取 posts 的速度,如果 posts 超过 30k,则需要 10 分钟,这至少对我来说并不理想。