Power Query带参数分页获取API全页数据报错求助
问题描述
使用Power BI Desktop的Power Query Editor获取AppFollow API的所有分页响应时,调用自定义函数出现错误:Expression.Error: The parameter is expected to be of type Text.Type or Binary.Type。需求是高效获取所有页面(总页数在响应的reviews.page.total字段),且需考虑API信用计费的成本。
当前自定义函数代码:
(ext_id as text, from as text, to as text) => let BaseURL = "https://api.appfollow.io/api/v2/reviews?", token = "[redacted]", Query = "ext_id=" & ext_id & "&from=" & from & "&to=" & to, GetJson = (Url) => let Options = [Headers=[Accept="application/json", #"X-AppFollow-API-Token"= token ]], RawData = Web.Contents(Url, Options), Json = Json.Document(RawData) in Json, GetPageCount = () => let Url = BaseURL & Query, response = GetJson(Url), toJson = Json.Document(response), total = toJson[reviews]{0}[page][total] in total, GetPage = (Index) => let Page = "&page=" & (Index), Url = BaseURL & Query & Page, Json = GetJson(Url), Value = Json[reviews] in Value, PageCount = GetPageCount(), PageIndicies = {0..PageCount -1}, Pages = List.Transform(PageIndicies, each GetPage(_)), Results = List.Union(Pages), #"Converted to Table" = Table.FromRecords(Results) in #"Converted to Table"
API示例响应:
{ "query": "/api/reviews?cid=[cid-here]&ext_id=[ext-id-here&from=2023-01-01&to=2023-01-31&host=global4.appfollow.io&method=GET&real_ip=xxx.xxx.xxx.xx", "reviews": { "list": [ { "data": "[removed data]" } ], "total": 286, "page": { "current": 1, "total": 3, "next": 2, "prev": null }, "ext_id": "ext-id-here", "store": "as" } }
错误详情:
Expression.Error: The parameter is expected to be of type Text.Type or Binary.Type. Details: query=/api/reviews?ext_id=[ext-id-here]&to=2023-01-31&from=2023-01-01&dev103=1&cid=[cid-here]&host=global4.appfollow.io&method=GET&real_ip=xxx.xx.xxx.xxx reviews=[Record]
错误原因分析
- 重复解析JSON:
GetJson函数已经返回Json.Document(RawData)解析后的Record对象,但GetPageCount里又调用Json.Document(response),将已解析的Record作为参数传入,而Json.Document仅接受文本或二进制类型,这是报错的直接原因。 - 响应路径错误:示例响应中
reviews是Record而非List,代码中toJson[reviews]{0}[page][total]用{0}索引List是错误的,应直接访问reviews[page][total]。 - 页码逻辑错误:API返回的
page.current是1-based(第一页为1),但代码生成的页码是{0..PageCount-1},会触发page=0的无效请求,同时遗漏最后一页。 - 数据提取错误:
GetPage函数返回整个reviewsRecord而非评论列表reviews[list],导致List.Union无法处理非List类型的数据。
修复后的代码
(ext_id as text, from as text, to as text) => let BaseURL = "https://api.appfollow.io/api/v2/reviews?", token = "[redacted]", Query = "ext_id=" & ext_id & "&from=" & from & "&to=" & to, GetJson = (Url) => let Options = [Headers=[Accept="application/json", #"X-AppFollow-API-Token"= token ]], RawData = Web.Contents(Url, Options), Json = Json.Document(RawData) in Json, // 获取第一页数据并缓存,避免重复调用API浪费信用 FirstPageUrl = BaseURL & Query, FirstPageData = GetJson(FirstPageUrl), PageCount = FirstPageData[reviews][page][total], // 生成1到总页数的页码列表 PageIndices = {1..PageCount}, // 获取指定页码的评论列表 GetPage = (Index) => let // 第一页直接用缓存数据,无需重复调用 PageData = if Index = 1 then FirstPageData else GetJson(BaseURL & Query & "&page=" & Text.From(Index)), ReviewList = PageData[reviews][list] in ReviewList, // 获取所有页面的评论列表 AllPages = List.Transform(PageIndices, each GetPage(_)), // 合并所有列表为单列表 CombinedReviews = List.Combine(AllPages), // 转换为表格 #"Converted to Table" = Table.FromRecords(CombinedReviews) in #"Converted to Table"
优化说明
- 缓存第一页数据:首次调用获取第一页时同时拿到总页数,后续直接复用第一页数据,避免重复调用API消耗额外信用。
- 修正页码逻辑:使用1-based页码匹配API参数要求,确保请求有效。
- 正确提取评论列表:直接获取
reviews[list]作为返回值,保证List.Combine能正常合并所有页面的数据。 - 显式转换页码为文本:用
Text.From(Index)确保页码参数是文本类型,避免类型拼接错误。
内容的提问来源于stack exchange,提问作者MrSalta
相关产品推荐
相关产品推荐

