飞书API(3):Python 自动读取多维表所有分页数据的三种方法

上一小节介绍了怎么使用 Python 读取多维表的数据,看似可以成功获取到了所有的数据,但是在实际生产使用过程中,我们会发现,上一小节的代码并不能获取到所有的多维表数据,它只能获取一页,默认是第一页。因为我使用的测试表数据量小,第一页便可读取完,所以有一种获取到所有数据的错觉。
本文介绍如何进行分页读取飞书多维表的所有数据,主要内容介绍如下:

  • 在线测试:使用飞书 API 调试台测试
  • 本地测试:使用 Python 代码测试,介绍通过三种不同的方法自动读取所有分页数据:通过 while 循环读取、通过 for 循环读取和通过内函数递归读取。

1、如何读取所有分页数据

那么怎么获取到所有的数据呢?
查看官方文档-查询记录,在“查询参数”中(如下图),可以看到有2个和翻页相关的参数:“page_token”和“page_size”。

image.png

先说下“page_size”,和分页记录数相关,默认值为 20,最大值上图没介绍,不过在 API 开头有说明(如下图),单次最大查询 500 行记录。

image.png

而“page_token”是一个翻页参数,首页没有该参数,从第 2 页开始就必须要传递相关的参数,而相关的“page_token”参数的值需要通过上一页返回的数据(即响应体)进行获取,也就是说从第 2 页开始都依赖上一页的返回。
分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。

查看响应体说明,可以看到有两个参数和翻页相关:“has_more”和“page_token”。

  • “has_more”用于判断有没有更多的页,有则返回 True。
  • “page_token”用于传递给查询数据接口,请求下一页的数据。

image.png

1.1 调试:读取第二页数据

了解了取数逻辑之后,可以先调试一下。调试逻辑:先获取第 1 页,然后获取到第 2页的“page_token”再发起请求。

1.1.1 读取第 1 页

打开 API 调试台,准备多维表,多维表的参数说明等,参考 第 2 小节:《API(2):通过 Python 读取多维表数据节》的【1.1 获取 demo】。

  • 请求头 和 路径参数参考第 2 小节填写即可
  • 查询参数:第 2 小节只填写了必填参数,所以查询查数没有传递值(即使用默认参数值),由于我测试的数据仅有 10 条记录,所以“page_size”改为 5,以便观察翻页的参数值。

image.png
改完直接点击【开始调试】即可,结果如下,可以看到“has_more”的值为 true,“page_token”返回一个字符串。
image.png
注:数据在响应体的 data>items 中,可以展开和多维表的记录比对查看下。

1.1.2 读取第 2 页

将首次请求返回的“page_token”的值填写到路径参数中“page_token”的输入框里,再次点击【开始调试】发起请求。
image.png

结果如下,可以看到“has_more”为 false,没有“page_token”参数。10 条记录分两次取完了,所以这个结果符合预期。
image.png

1.2 调试:本地测试读取第二页数据

续上,第二次请求结果,点击示例代码,点击“Python-requests”,可以看到 API 连接多了 3 个参数,复制代码到本地测试运行。
image.png

测试结果如下,正常获取到第二页的数据。

image.png

2、使用 Python 自动读取所有分页数据

上面通过手动输入“page_token”的方式读取到了测试文档的所有数据,在实际生产过程中,不可能手动一页页处理,所以需要通过代码自动将第一次获取的“page_token”传递给第二次请求。

根据飞书提供的信息,至少我们可以有三种方法来穷尽读取任意多维表的所有数据。

  • 方法一:通过 while 循环读取
  • 方法二:通过 for 循环读取
  • 方法二:通过内函数递归读取

上一小节最后有一个获取tenant_access_token并调接口读取数据的合并代码(代码如下)。本次测试基于该代码进行迭代。

import requests
import jsondef get_tenant_access_token(app_id, app_secret):url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"payload = json.dumps({"app_id": app_id,"app_secret": app_secret})headers = {'Content-Type': 'application/json'}response = requests.request("POST", url, headers=headers, data=payload)# print(response.text)return response.json()['tenant_access_token']def get_bitable_datas(tenant_access_token, app_token, table_id):url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search"payload = json.dumps({})headers = {'Content-Type': 'application/json','Authorization': f'Bearer {tenant_access_token}'}response = requests.request("POST", url, headers=headers, data=payload)print(response.text)app_id = 'your_app_id'
app_secret = 'your_app_secret'
tenant_access_token = get_tenant_access_token(app_id, app_secret)
app_token = 'your_app_token'
table_id = 'your_table_id'
get_bitable_datas(tenant_access_token, app_token, table_id)

2.1 while 循环读取分页数据

思路:主代码使用while循环调用get_bitable_datas()函数,并处理提取page_token,在下一次循环传递给get_bitable_datas()函数。
get_bitable_datas()函数需要进行修改,以便适配任意页的读取,并返回调用接口的数据。

  • url新增三个参数:page_sizepage_tokenuser_id_type;第一页page_token=''可以正常请求数据;
  • 返回调用接口的数据:加上return response.json()

修改完参考如下:

def get_bitable_datas(tenant_access_token, app_token, table_id, page_token='', page_size=20):url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search?page_size={page_size}&page_token={page_token}&user_id_type=user_id"payload = json.dumps({})headers = {'Content-Type': 'application/json','Authorization': f'Bearer {tenant_access_token}'}response = requests.request("POST", url, headers=headers, data=payload)# print(response.text)return response.json()

主代码加上while循环,把调用get_bitable_datas()函数放到循环体中,并提取返回数据中的page_tokenhas_more,打印记录。参考如下:

app_id = 'your_app_id'
app_secret = 'your_app_secret'
tenant_access_token = get_tenant_access_token(app_id, app_secret)
app_token = 'your_app_token'
table_id = 'your_table_id'page_token = ''
page_size = 5
has_more = True
while has_more:response = get_bitable_datas(tenant_access_token, app_token, table_id, page_token, page_size)if response['code'] == 0:page_token = response['data'].get('page_token')has_more = response['data'].get('has_more')print(response['data'].get('items'))

运行代码,结果如下:成功读取并打印分页的数据。

在这里插入图片描述

将主代码封装到main()函数中,并将所有返回的结果整到一个列表中,最终参考代码如下:

import requests
import jsondef get_tenant_access_token(app_id, app_secret):url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"payload = json.dumps({"app_id": app_id,"app_secret": app_secret})headers = {'Content-Type': 'application/json'}response = requests.request("POST", url, headers=headers, data=payload)# print(response.text)return response.json()['tenant_access_token']def get_bitable_datas(tenant_access_token, app_token, table_id, page_token='', page_size=20):url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search?page_size={page_size}&page_token={page_token}&user_id_type=user_id"payload = json.dumps({})headers = {'Content-Type': 'application/json','Authorization': f'Bearer {tenant_access_token}'}response = requests.request("POST", url, headers=headers, data=payload)# print(response.text)return response.json()def main():app_id = 'your_app_id'app_secret = 'your_app_secret'tenant_access_token = get_tenant_access_token(app_id, app_secret)app_token = 'your_app_token'table_id = 'your_table_id'page_token = ''page_size = 5has_more = Truefeishu_datas = []while has_more:response = get_bitable_datas(tenant_access_token, app_token, table_id, page_token, page_size)if response['code'] == 0:page_token = response['data'].get('page_token')has_more = response['data'].get('has_more')# print(response['data'].get('items'))# print('\n--------------------------------------------------------------------\n')feishu_datas.extend(response['data'].get('items'))else:raise Exception(response['msg'])return feishu_datasif __name__ == '__main__':feishu_datas = main()print(feishu_datas)

执行结果如下:

在这里插入图片描述

2.2 for 循环读取分页数据

注:在 2.1 基础上修改。
使用 for 循环,不如 while 循环便捷。因为 for 循环有一个难点,就是需要先确认循环的次数。而确认次数,需要知道总数据量。而确认总数据量,需要通过调接口获取,每次查询请求都会返回一个记录数据量的参数:total (如下图)。
image.png

读取该值后结合每页的记录数page_size,使用公式total/size-1,然后向上取整来确定循环的次数。
关联核心代码如下:

  • 先调一次接口获取到 total 的参数值,然后根据公式计算需要循环多少次(需要使用math.ceil()方法向上取整);顺带将首次请求的page_tokenfeishu_datas处理
  • 然后根据上面得到的次数进行遍历,读取后面页数的数据,并拼接到feishu_datas中。
    # 首次请求单独处理,获取 total、page_token、has_more、itemsresponse = get_bitable_datas(tenant_access_token, app_token, table_id, page_token, page_size)if response['code'] == 0:total = math.ceil(response['data'].get('total')/page_size - 1)page_token = response['data'].get('page_token')feishu_datas = response['data'].get('items')# 非首次请求,统一处理for i in range(total):response = get_bitable_datas(tenant_access_token, app_token, table_id, page_token, page_size)if response['code'] == 0:page_token = response['data'].get('page_token')feishu_datas.extend(response['data'].get('items'))

最终的完整参考代码如下:

  • 首次请求和非首次请求的数据分开处理;
  • 使用 total 计算循环次数,不需要 has_more 参数。
import requests
import json, mathdef get_tenant_access_token(app_id, app_secret):url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"payload = json.dumps({"app_id": app_id,"app_secret": app_secret})headers = {'Content-Type': 'application/json'}response = requests.request("POST", url, headers=headers, data=payload)# print(response.text)return response.json()['tenant_access_token']def get_bitable_datas(tenant_access_token, app_token, table_id, page_token='', page_size=20):url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search?page_size={page_size}&page_token={page_token}&user_id_type=user_id"payload = json.dumps({})headers = {'Content-Type': 'application/json','Authorization': f'Bearer {tenant_access_token}'}response = requests.request("POST", url, headers=headers, data=payload)# print(response.text)return response.json()def main():app_id = 'your_app_id'app_secret = 'your_app_secret'tenant_access_token = get_tenant_access_token(app_id, app_secret)app_token = 'your_app_token'table_id = 'your_table_id'page_token = ''page_size = 5# 首次请求单独处理,获取 total、page_token、has_more、itemsresponse = get_bitable_datas(tenant_access_token, app_token, table_id, page_token, page_size)if response['code'] == 0:total = math.ceil(response['data'].get('total')/page_size - 1)page_token = response['data'].get('page_token')feishu_datas = response['data'].get('items')# 非首次请求,统一处理for i in range(total):response = get_bitable_datas(tenant_access_token, app_token, table_id, page_token, page_size)if response['code'] == 0:page_token = response['data'].get('page_token')feishu_datas.extend(response['data'].get('items'))else:raise Exception(response['msg'])else:raise Exception(response['msg'])return feishu_datasif __name__ == '__main__':feishu_datas = main()print(feishu_datas)

执行结果如下:
在这里插入图片描述

2.3 内函数递归读取分页数据

注:在 2.1 基础上修改。
本小节介绍使用内函数进行递归处理,相对会比较复杂。
目标是传入相关的参数,便可获取到多维表的所有数据。
实现该目标主要是在get_bitable_datas()函数中进行迭代:

  • 递归逻辑:加上内函数inner(),在内函数中调用外函数get_bitable_datas()
  • 什么时候调用内函数?has_moreTrue的时候。

数据的存储问题:将存储数据的列表feishu_datas放到函数外作为全局变量,函数get_bitable_datas()的功能是给列表feishu_datas添加元素。

直接看看最终完整的参考代码:

  • feishu_datas变量放到函数之前,使得全局可调用
  • get_bitable_datas()中新增内函数inner(),该函数功能只有一个就是调用外函数get_bitable_datas()。当has_more值为True的时候,便不断调用内函数inner(),也不断调用外函数get_bitable_datas(),直到最后一页has_more值为False时,一层层返回,最终得到记录所有数据的列表feishu_datas
  • main()函数中直接调用get_bitable_datas()函数便可得到记录所有数据的列表feishu_datas
import requests
import jsonfeishu_datas = []def get_tenant_access_token(app_id, app_secret):url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"payload = json.dumps({"app_id": app_id,"app_secret": app_secret})headers = {'Content-Type': 'application/json'}response = requests.request("POST", url, headers=headers, data=payload)# print(response.text)return response.json()['tenant_access_token']def get_bitable_datas(tenant_access_token, app_token, table_id, page_token='', page_size=20):url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search?page_size={page_size}&page_token={page_token}&user_id_type=user_id"payload = json.dumps({})headers = {'Content-Type': 'application/json','Authorization': f'Bearer {tenant_access_token}'}response = requests.request("POST", url, headers=headers, data=payload).json()def inner(tenant_access_token, app_token, table_id, page_token):# 调用外函数,递归调用get_bitable_datas(tenant_access_token, app_token, table_id, page_token)if response['code'] == 0:page_token = response['data'].get('page_token')has_more = response['data'].get('has_more')feishu_datas.extend(response['data'].get('items'))if has_more:# 调用内函数inner(tenant_access_token, app_token, table_id, page_token)else:raise Exception(response['msg'])def main():app_id = 'your_app_id'app_secret = 'your_app_secret'tenant_access_token = get_tenant_access_token(app_id, app_secret)app_token = 'your_app_token'table_id = 'your_table_id'page_token = ''page_size = 5get_bitable_datas(tenant_access_token, app_token, table_id, page_token, page_size)if __name__ == '__main__':main()print(feishu_datas)

执行结果如下:

在这里插入图片描述

3、小结

使用 Python 读取多维表分页,需要传递“page_token”参数。
第一页“page_token”参数为空字符串,第二页开始从上一页的响应体提取“page_token”的值。
使用 Python 实现,可以通过三种方式读取所有分页的数据:while 循环读取、for 循环读取和内函数递归读取。

  • while 循环:使用has_more参数,直到has_more=False跳出循环;
  • for 循环:使用total参数,结合page_size计算循环次数;
  • 内函数递归:使用has_more参数递归调用内函数,直到has_more=False时逐层返回结果。

while 循环 相对比较好理解,而且很简洁。for 循环通过数量进行计算,或有一定风险,就是在读取的过程中,如果新增数据,可能会出现 bug,如果新增数据涉及新的页,将读取不到新增的数据。内函数递归方法,理解难度相对较高,代码相对简洁。
个人推荐顺序:while 循环>内函数递归>for 循环。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/800062.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

棋牌室计时吧台计费收费灯控管理系统软件操作流程

棋牌室计时吧台计费收费灯控管理系统软件操作流程 一、前言 以下软件操作教程以,佳易王棋牌桌球计时计费管理系统软件灯控版V17.87为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 该计时计费软件可以是棋牌和桌球混合同时计时计费 …

JS--demo实现随机点名

逻辑就是通过点击事件得到数组里面的随机一个值&#xff0c;再把这个值给删除&#xff0c;当数组长度为1的时候&#xff0c;停止点名&#xff0c;用disabled属性让用户不能进行点击。 <!DOCTYPE html> <html lang"en"><head><meta charset&quo…

ESB总线集成方案:优劣势的深度解析

在信息化时代&#xff0c;企业面临着业务快速扩展、系统日益复杂、数据交互需求不断增加的挑战。为了有效整合各种资源&#xff0c;优化业务流程&#xff0c;提高运营效率&#xff0c;企业服务总线&#xff08;ESB&#xff09;集成方案应运而生。本文将详细探讨ESB总线集成方案…

Android匿名共享内存(Ashmem)

在Android中我们熟知的IPC方式有Socket、文件、ContentProvider、Binder、共享内存。其中共享内存的效率最高&#xff0c;可以做到0拷贝&#xff0c;在跨进程进行大数据传输&#xff0c;日志收集等场景下非常有用。共享内存是Linux自带的一种IPC机制&#xff0c;Android直接使用…

基于单片机体温心率检测仪系统设计

**单片机设计介绍&#xff0c; 基于单片机体温心率检测仪系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机体温心率检测仪系统设计是一个综合性的项目&#xff0c;旨在通过单片机及其外围电路实现对人体体温和心…

Android 11 上的文件读写无权限问题

Android 6以上需要动态申请读写权限&#xff0c;但是11以上动态申请了读写权限也是无效。并且手动给予权限没有该按钮。 如上图华为钱包有个所有文件权限、但是百度地图只有仅媒体权限&#xff0c;仅媒体权限&#xff08;动态申请读写权限&#xff09;给予后软件还是没法访问文…

DSOX3034T是德科技DSOX3034T示波器

181/2461/8938产品概述&#xff1a; 特点: 带宽:350 MHz频道:4存储深度:4 Mpts采样速率:5 GSa/s更新速率:每秒1000000个波形波形数学和FFT自动探测接口用于连接、存储设备和打印的USB主机和设备端口 触摸: 8.5英寸电容式触摸屏专为触摸界面设计 发现: 业界最快的无损波形更…

10分钟上手:MySQL8的Json格式字段使用总结干货

一、关于效率和适用范围 尽管官方承诺Json格式字段采用了空间换时间的策略&#xff0c;比Text类型来存储Json有大幅度的效率提升。但是Json格式的处理过程仍然效率不及传统关系表&#xff0c;所以什么时候用Json格式字段尤为重要。 只有我们确定系统已经能精确定位到某一行&am…

Mysql主键优化之页分裂与页合并

主键设计原则 满足业务需求的情况下&#xff0c;尽量降低主键的长度。因为如果主键太长&#xff0c;在多个二级索引中&#xff0c;主键索引值所占用的空间就会过大。 插入数据时&#xff0c;尽量选择顺序插入&#xff0c;选择使用AUTO_INCREMENT自增主键。因为乱序插入会导致页…

[C++][异常]详解

目录 1.C语言传统的处理错误的方式2.C异常概念3.异常的抛出和捕获4.异常的重新抛出5.异常安全6.异常规范7.自定义异常体系8.C标准库的异常体系9.异常的优缺点1.C异常的优点2.C异常的缺点3.总结 1.C语言传统的处理错误的方式 传统的错误处理机制 终止程序&#xff0c;如assert …

Linux gcc day5粘滞位

粘滞位 背景&#xff1a;一定时在一个公共目录&#xff08;root创建&#xff09;下。进行临时文件的操作 Linux系统中有很多人&#xff0c;我们需要在一个公共目录下&#xff0c;进行临时文件的操作&#xff08;增删查改&#xff09; 创建一个根目录下的dir&#xff08;mytmp…

代码随想录算法训练营day33

题目&#xff1a;1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果 参考链接&#xff1a;代码随想录 1005.K次取反后最大化的数组和 思路&#xff1a;本题还是直觉&#xff0c;想使得整体的数组和最大&#xff0c;需要每一次取反都尽可能使的全局最优。先将数组排…

与汇智知了堂共舞,HW行动开启你的网络安全新篇章!

**网安圈内一年一度的HW行动来啦&#xff01; ** 招募对象 不限&#xff0c;有HW项目经验 或持有NISP二级、CISP证书优先 HW时间 以官方正式通知为准 工作地点&#xff1a;全国 薪资待遇 带薪HW &#xff08;根据考核成绩500-4000元/天不等&#xff09; 招募流程 1.填写报名…

供应链领域主题:生产制造关键术语和系统

BOM&#xff08;Bill of Material&#xff09;物料清单 BOM&#xff08;Bill of Material&#xff09;物料清单&#xff0c;是计算机可以识别的产品结构数据文件&#xff0c;也是ERP的主导文件。BOM使系统识别产品结构&#xff0c;也是联系与沟通企业各项业务的纽带。ERP系统中…

国内通稿在海外新闻媒体如何宣发-大舍传媒

引言 在全球化的时代背景下&#xff0c;海外通稿成为了新闻媒体间交流和宣发的重要方式之一。本文将探讨海外通稿在新闻媒体中的宣发方式&#xff0c;并分析大舍传媒在这方面的成功经验。 来百度APP畅享高清图片 海外通稿的重要性 海外通稿是指由海外记者或通讯社撰写的报道…

JavaScript - 你知道数组去重都有哪些实现方案吗

难度级别:初级及以上 提问概率:70% 数组去重是一道非常经典而又高频的面试题,这里我们提出6种解决方案: 目录 1 第一种 2 第二种 3 第三种 4 第四种

Codigger Desktop:用户体验与获得收益双赢的革新之作(一)

上周&#xff0c;我们介绍了Codigger Desktop凭借其强大的功能、稳定的性能以及人性化的设计&#xff0c;成为了广大开发者的得力助手。Codigger Desktop除了是开发者的利器外&#xff0c;它以其出色的用户体验和创新的收益模式&#xff0c;为用户提供了一个全新的选择。Codigg…

基于LNMP环境上线QQ农场

目录 一.介绍 二. 环境准备 三.安装Mysql数据库 四.安装PHP 五.安装Nginx 六.测试Nginx服务于PHP服务是否能关联 七.项目上线 QQ农场源码&#xff1a;做本项目默认操作者有一定的基础知识与理解能力 链接&#xff1a;https://pan.baidu.com/s/1HF8GZ-yvNh7RbJ61nXOW-g?…

【Django开发】0到1美多商城项目md教程第6篇:账号登录,1. 用户名登录逻辑分析【附代码文档】

美多商城完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;欢迎来到美多商城&#xff01;&#xff0c;项目准备。展示用户注册页面&#xff0c;创建用户模块子应用。用户注册业务实现&#xff0c;用户注册前端逻辑。图形验证码&#xff0c;图形验证码接口设…

【漏洞复现】泰博云平台 solr SSRF漏洞

0x01 产品简介 泰博云平台,就是指以电商集群的方式,通过供应链有效连接组成“商务云”生态系统,在产品、服务、营销推广等方面实现资源共享,“物”就是线下实体店网络,以众包模式,将行业制造商、分销商、零售商,和提供本土化设计、物流、安装的优质服务商,纳入统一的云…