feishu_lib.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. # -*- coding: utf-8 -*-
  2. # @Author: wangkun
  3. # @Time: 2022/5/27
  4. import json
  5. import time
  6. import requests
  7. import urllib3
  8. from common import Common
  9. proxies = {"http": None, "https": None}
  10. class Feishu:
  11. """
  12. 编辑飞书云文档
  13. """
  14. # 看一看爬虫数据表
  15. kanyikan_url = "https://w42nne6hzg.feishu.cn/sheets/shtcngRPoDYAi24x52j2nDuHMih?"
  16. # 快手爬虫数据表
  17. kuaishou_url = "https://w42nne6hzg.feishu.cn/sheets/shtcnp4SaJt37q6OOOrYzPMjQkg?"
  18. # 微视爬虫数据表
  19. weishi_url = "https://w42nne6hzg.feishu.cn/sheets/shtcn5YSWg91JfVGzj0SFZIRRPh?"
  20. # 小年糕爬虫数据表
  21. xiaoniangao_url = "https://w42nne6hzg.feishu.cn/sheets/shtcnYxiyQ1wLklo1W5Kdqc9cGh?"
  22. # twitter 爬虫吧
  23. twitter_url = "https://whtlrai9ej.feishu.cn/sheets/shtcn6BYfYuqegIP13ORB6rI2dh?"
  24. # 飞书路径token
  25. @classmethod
  26. def spreadsheettoken(cls, crawler):
  27. """
  28. :param crawler: 哪个爬虫
  29. """
  30. if crawler == "kanyikan":
  31. return "shtcngRPoDYAi24x52j2nDuHMih"
  32. elif crawler == "kuaishou":
  33. return "shtcnp4SaJt37q6OOOrYzPMjQkg"
  34. elif crawler == "weishi":
  35. return "shtcn5YSWg91JfVGzj0SFZIRRPh"
  36. elif crawler == "xiaoniangao":
  37. return "shtcnYxiyQ1wLklo1W5Kdqc9cGh"
  38. elif crawler == "twitter":
  39. return "shtcn6BYfYuqegIP13ORB6rI2dh"
  40. # 获取飞书api token
  41. @classmethod
  42. def get_token(cls):
  43. """
  44. 获取飞书api token
  45. :return:
  46. """
  47. time.sleep(1)
  48. url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/"
  49. post_data = {"app_id": "cli_a13ad2afa438d00b", # 这里账号密码是发布应用的后台账号及密码
  50. "app_secret": "4tK9LY9VbiQlY5umhE42dclBFo6t4p5O"}
  51. try:
  52. urllib3.disable_warnings()
  53. response = requests.post(url=url, data=post_data, proxies=proxies, verify=False)
  54. tenant_access_token = response.json()["tenant_access_token"]
  55. return tenant_access_token
  56. except Exception as e:
  57. Common.logger().error("获取飞书 api token 异常:{}", e)
  58. # 获取表格元数据
  59. @classmethod
  60. def get_metainfo(cls, crawler):
  61. """
  62. 获取表格元数据
  63. :return:
  64. """
  65. get_metainfo_url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" \
  66. + cls.spreadsheettoken(crawler) + "/metainfo"
  67. headers = {
  68. "Authorization": "Bearer " + cls.get_token(),
  69. "Content-Type": "application/json; charset=utf-8"
  70. }
  71. params = {
  72. "extFields": "protectedRange", # 额外返回的字段,extFields=protectedRange时返回保护行列信息
  73. "user_id_type": "open_id" # 返回的用户id类型,可选open_id,union_id
  74. }
  75. try:
  76. urllib3.disable_warnings()
  77. r = requests.get(url=get_metainfo_url, headers=headers, params=params, proxies=proxies, verify=False)
  78. response = json.loads(r.content.decode("utf8"))
  79. return response
  80. except Exception as e:
  81. Common.logger().error("获取表格元数据异常:{}", e)
  82. # 读取工作表中所有数据
  83. @classmethod
  84. def get_values_batch(cls, crawler, sheetid):
  85. """
  86. 读取工作表中所有数据
  87. :param crawler: 哪个爬虫
  88. :param sheetid: 哪张表
  89. :return: 所有数据
  90. """
  91. get_values_batch_url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" \
  92. + cls.spreadsheettoken(crawler) + "/values_batch_get"
  93. headers = {
  94. "Authorization": "Bearer " + cls.get_token(),
  95. "Content-Type": "application/json; charset=utf-8"
  96. }
  97. params = {
  98. # 多个查询范围 如 url?ranges=range1,range2 ,其中 range 包含 sheetId 与单元格范围两部分
  99. "ranges": sheetid,
  100. # valueRenderOption=ToString 可返回纯文本的值(数值类型除外);
  101. # valueRenderOption=FormattedValue 计算并格式化单元格;
  102. # valueRenderOption=Formula单元格中含有公式时返回公式本身;
  103. # valueRenderOption=UnformattedValue计算但不对单元格进行格式化
  104. "valueRenderOption": "ToString",
  105. # dateTimeRenderOption=FormattedString 计算并将时间日期按照其格式进行格式化,但不会对数字进行格式化,返回格式化后的字符串。
  106. "dateTimeRenderOption": "",
  107. # 返回的用户id类型,可选open_id,union_id
  108. "user_id_type": "open_id"
  109. }
  110. try:
  111. urllib3.disable_warnings()
  112. r = requests.get(url=get_values_batch_url, headers=headers, params=params, proxies=proxies, verify=False)
  113. response = json.loads(r.content.decode("utf8"))
  114. values = response["data"]["valueRanges"][0]["values"]
  115. return values
  116. except Exception as e:
  117. Common.logger().error("读取工作表所有数据异常:{}", e)
  118. # 工作表,插入行或列
  119. @classmethod
  120. def insert_columns(cls, crawler, sheetid, majordimension, startindex, endindex):
  121. """
  122. 工作表插入行或列
  123. :param crawler: 哪个爬虫
  124. :param sheetid:哪张工作表
  125. :param majordimension:行或者列
  126. :param startindex:开始位置
  127. :param endindex:结束位置
  128. """
  129. insert_columns_url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" \
  130. + cls.spreadsheettoken(crawler) + "/insert_dimension_range"
  131. headers = {
  132. "Authorization": "Bearer " + cls.get_token(),
  133. "Content-Type": "application/json; charset=utf-8"
  134. }
  135. body = {
  136. "dimension": {
  137. "sheetId": sheetid,
  138. "majorDimension": majordimension, # 默认 ROWS ,可选 ROWS、COLUMNS
  139. "startIndex": startindex, # 开始的位置
  140. "endIndex": endindex # 结束的位置
  141. },
  142. "inheritStyle": "AFTER" # BEFORE 或 AFTER,不填为不继承 style
  143. }
  144. try:
  145. urllib3.disable_warnings()
  146. r = requests.post(url=insert_columns_url, headers=headers, json=body, proxies=proxies, verify=False)
  147. Common.logger().info("插入行或列:{}", r.json()["msg"])
  148. except Exception as e:
  149. Common.logger().error("插入行或列异常:{}", e)
  150. # 写入数据
  151. @classmethod
  152. def update_values(cls, crawler, sheetid, ranges, values):
  153. """
  154. 写入数据
  155. :param crawler: 哪个爬虫
  156. :param sheetid:哪张工作表
  157. :param ranges:单元格范围
  158. :param values:写入的具体数据,list
  159. """
  160. update_values_url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" \
  161. + cls.spreadsheettoken(crawler) + "/values_batch_update"
  162. headers = {
  163. "Authorization": "Bearer " + cls.get_token(),
  164. "Content-Type": "application/json; charset=utf-8"
  165. }
  166. body = {
  167. "valueRanges": [
  168. {
  169. "range": sheetid + "!" + ranges,
  170. "values": values
  171. },
  172. ],
  173. }
  174. try:
  175. urllib3.disable_warnings()
  176. r = requests.post(url=update_values_url, headers=headers, json=body, proxies=proxies, verify=False)
  177. Common.logger().info("写入数据:{}", r.json()["msg"])
  178. except Exception as e:
  179. Common.logger().error("写入数据异常:{}", e)
  180. # 合并单元格
  181. @classmethod
  182. def merge_cells(cls, crawler, sheetid, ranges):
  183. """
  184. 合并单元格
  185. :param crawler: 哪个爬虫
  186. :param sheetid:哪张工作表
  187. :param ranges:需要合并的单元格范围
  188. """
  189. merge_cells_url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" \
  190. + cls.spreadsheettoken(crawler) + "/merge_cells"
  191. headers = {
  192. "Authorization": "Bearer " + cls.get_token(),
  193. "Content-Type": "application/json; charset=utf-8"
  194. }
  195. body = {
  196. "range": sheetid + "!" + ranges,
  197. "mergeType": "MERGE_ROWS"
  198. }
  199. try:
  200. urllib3.disable_warnings()
  201. r = requests.post(url=merge_cells_url, headers=headers, json=body, proxies=proxies, verify=False)
  202. Common.logger().info("合并单元格:{}", r.json()["msg"])
  203. except Exception as e:
  204. Common.logger().error("合并单元格异常:{}", e)
  205. # 读取单元格数据
  206. @classmethod
  207. def get_range_value(cls, crawler, sheetid, cell):
  208. """
  209. 读取单元格内容
  210. :param crawler: 哪个爬虫
  211. :param sheetid: 哪张工作表
  212. :param cell: 哪个单元格
  213. :return: 单元格内容
  214. """
  215. get_range_value_url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" \
  216. + cls.spreadsheettoken(crawler) + "/values/" + sheetid + "!" + cell
  217. headers = {
  218. "Authorization": "Bearer " + cls.get_token(),
  219. "Content-Type": "application/json; charset=utf-8"
  220. }
  221. params = {
  222. # valueRenderOption=ToString 可返回纯文本的值(数值类型除外);
  223. # valueRenderOption=FormattedValue 计算并格式化单元格;
  224. # valueRenderOption=Formula 单元格中含有公式时返回公式本身;
  225. # valueRenderOption=UnformattedValue 计算但不对单元格进行格式化。
  226. "valueRenderOption": "FormattedValue",
  227. # dateTimeRenderOption=FormattedString 计算并对时间日期按照其格式进行格式化,但不会对数字进行格式化,返回格式化后的字符串。
  228. "dateTimeRenderOption": "",
  229. # 返回的用户id类型,可选open_id,union_id
  230. "user_id_type": "open_id"
  231. }
  232. try:
  233. urllib3.disable_warnings()
  234. r = requests.get(url=get_range_value_url, headers=headers, params=params, proxies=proxies, verify=False)
  235. return r.json()["data"]["valueRange"]["values"][0]
  236. except Exception as e:
  237. Common.logger().error("读取单元格数据异常:{}", e)
  238. # 删除行或列,可选 ROWS、COLUMNS
  239. @classmethod
  240. def dimension_range(cls, crawler, sheetid, major_dimension, startindex, endindex):
  241. """
  242. 删除行或列
  243. :param crawler: 哪个爬虫
  244. :param sheetid:工作表
  245. :param major_dimension:默认 ROWS ,可选 ROWS、COLUMNS
  246. :param startindex:开始的位置
  247. :param endindex:结束的位置
  248. :return:
  249. """
  250. dimension_range_url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" \
  251. + cls.spreadsheettoken(crawler) + "/dimension_range"
  252. headers = {
  253. "Authorization": "Bearer " + cls.get_token(),
  254. "Content-Type": "application/json; charset=utf-8"
  255. }
  256. body = {
  257. "dimension": {
  258. "sheetId": sheetid,
  259. "majorDimension": major_dimension,
  260. "startIndex": startindex,
  261. "endIndex": endindex
  262. }
  263. }
  264. try:
  265. urllib3.disable_warnings()
  266. r = requests.delete(url=dimension_range_url, headers=headers, json=body, proxies=proxies, verify=False)
  267. Common.logger().info("删除视频数据:{}", r.json()["msg"])
  268. except Exception as e:
  269. Common.logger().error("删除视频数据异常:{}", e)
  270. # 查找单元格
  271. @classmethod
  272. def find_cell(cls, crawler, sheetid, find_text):
  273. """
  274. 查找单元格
  275. :param crawler: 哪个爬虫
  276. :param sheetid: 哪张表
  277. # :param ranges: 单元格范围
  278. :param find_text: 查找的字符
  279. :return: 返回单元格索引
  280. """
  281. find_cell_url = "https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/" \
  282. + cls.spreadsheettoken(crawler) + "/sheets/" \
  283. + sheetid + "/find"
  284. headers = {
  285. "Authorization": "Bearer " + cls.get_token(),
  286. "Content-Type": "application/json; charset=utf-8"
  287. }
  288. rows_count = len(cls.get_values_batch("twitter", "db114c"))
  289. body = {
  290. "find_condition": {
  291. "range": sheetid + "!A1:A" + str(rows_count),
  292. "match_case": True, # 是否忽略大小写
  293. "match_entire_cell": False, # 是否匹配整个单元格
  294. "search_by_regex": False, # 是否为正则匹配
  295. "include_formulas": False # 是否搜索公式内容
  296. },
  297. "find": find_text # 搜索内容
  298. }
  299. try:
  300. urllib3.disable_warnings()
  301. r = requests.post(url=find_cell_url, headers=headers, json=body, proxies=proxies, verify=False)
  302. Common.logger().info("查找单元格:{}", r.json()["msg"])
  303. matched_cell = r.json()["data"]["find_result"]["matched_cells"][0].split("A")[-1]
  304. return matched_cell
  305. except Exception as e:
  306. Common.logger().error("查找单元格异常:{}", e)
  307. # 筛选:filter
  308. @classmethod
  309. def filter_created_at(cls):
  310. filter_created_at_url = "https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/" \
  311. "shtcn8fFzDhCFHpB6vzf51s2xbf/sheets/48cfb0/filter"
  312. headers = {
  313. "Authorization": "Bearer " + cls.get_token(),
  314. "Content-Type": "application/json; charset=utf-8"
  315. }
  316. body = {
  317. "col": "A",
  318. "condition": {
  319. "filter_type": "number",
  320. "compare_type": "less",
  321. "expected": [
  322. "6"
  323. ]
  324. }
  325. }
  326. try:
  327. urllib3.disable_warnings()
  328. r = requests.put(url=filter_created_at_url, headers=headers, json=body, proxies=proxies, verify=False)
  329. print(r.json())
  330. except Exception as e:
  331. Common.logger().error("查找单元格异常:{}", e)
  332. class Bitable:
  333. """
  334. 多维表格 API
  335. 文档地址:https://w42nne6hzg.feishu.cn/base/bascnpAYvIA0B1hBtNJlriZceUV?table=tblqMbXrpqFbDLNE&view=vewsMtek0O
  336. app_token:bascnpAYvIA0B1hBtNJlriZceUV
  337. """
  338. app_token = "bascnpAYvIA0B1hBtNJlriZceUV"
  339. table_id = "tblqMbXrpqFbDLNE"
  340. page_token = "" # 列出记录时,翻页参数
  341. # 获取飞书api token
  342. @classmethod
  343. def tenant_access_token(cls):
  344. """
  345. 获取飞书api token
  346. :return:
  347. """
  348. time.sleep(1)
  349. url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/"
  350. post_data = {"app_id": "cli_a13ad2afa438d00b", # 这里账号密码是发布应用的后台账号及密码
  351. "app_secret": "4tK9LY9VbiQlY5umhE42dclBFo6t4p5O"}
  352. try:
  353. urllib3.disable_warnings()
  354. response = requests.post(url=url, data=post_data, proxies=proxies, verify=False)
  355. tenant_access_token = response.json()["tenant_access_token"]
  356. return tenant_access_token
  357. except Exception as e:
  358. Common.logger().error("获取tenant_access_token异常:{}", e)
  359. # 获取多维表格元数据
  360. @classmethod
  361. def get_apps(cls):
  362. """
  363. 获取多维表格元数据
  364. 该接口支持调用频率上限为 20 QPS
  365. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app/get
  366. """
  367. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" + cls.app_token
  368. headers = {
  369. "Authorization": "Bearer " + cls.tenant_access_token(),
  370. "Content-Type": "application/json; charset=utf-8"
  371. }
  372. try:
  373. urllib3.disable_warnings()
  374. r = requests.get(url=url, headers=headers, proxies=proxies, verify=False)
  375. Common.logger().info("获取多维表格元数据,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  376. except Exception as e:
  377. Common.logger().error("获取多维表格元数据异常:{}", e)
  378. # 列出数据表
  379. @classmethod
  380. def get_tables(cls):
  381. """
  382. 列出数据表
  383. 该接口支持调用频率上限为 20 QPS
  384. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table/list
  385. """
  386. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" + cls.app_token + "/tables"
  387. headers = {
  388. "Authorization": "Bearer " + cls.tenant_access_token(),
  389. "Content-Type": "application/json; charset=utf-8"
  390. }
  391. params = {
  392. "page_token": "",
  393. "page_size": ""
  394. }
  395. try:
  396. urllib3.disable_warnings()
  397. r = requests.get(url=url, headers=headers, params=params, proxies=proxies, verify=False)
  398. Common.logger().info("列出数据表,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  399. except Exception as e:
  400. Common.logger().error("列出数据表异常:{}", e)
  401. # 列出记录
  402. @classmethod
  403. def list_records(cls, count):
  404. """
  405. 该接口用于列出数据表中的现有记录,单次最多列出 100 行记录,支持分页获取。
  406. 该接口支持调用频率上限为 1000 次/分钟
  407. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/list
  408. """
  409. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" \
  410. + cls.app_token + "/tables/" + cls.table_id + "/records"
  411. headers = {
  412. "Authorization": "Bearer " + cls.tenant_access_token(),
  413. "Content-Type": "application/json; charset=utf-8"
  414. }
  415. params = {
  416. "view_id": "", # 视图 id; 注意:
  417. # 如 filter 或 sort 有值,view_id 会被忽略。
  418. # 示例值: "vewqhz51lk"
  419. "filter": "", # 筛选参数; 注意:
  420. # 1.筛选记录的表达式不超过2000个字符。
  421. # 2.不支持对“人员”以及“关联字段”的属性进行过滤筛选,如人员的 OpenID。
  422. # 3.仅支持字段在页面展示字符值进行筛选。
  423. # 详细参考:https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/filter
  424. # 示例值:"示例表达式:AND(CurrentValue.[身高]>180, CurrentValue.[体重]>150)"
  425. "sort": "", # 排序参数。注意:
  426. # 1.表达式需要不超过1000字符。
  427. # 2.不支持对带“公式”和“关联字段”的表的使用。
  428. # 示例值:"["字段1 DESC","字段2 ASC"]
  429. # 注意:使用引号将字段名称和顺序逆序连接起来。"
  430. "field_names": "[]", # 字段名称。示例值:"["字段1"]"
  431. "text_field_as_array": True, # 控制多行文本字段数据的返回格式,true 表示以数组形式返回。注意:
  432. # 1.多行文本中如果有超链接部分,则会返回链接的 URL。
  433. # 2.目前可以返回多行文本中 URL 类型为多维表格链接、飞书 doc、飞书 sheet的URL类型以及@人员的数据结构。
  434. # 示例值:true
  435. # "user_id_type": "", # 用户 ID 类型
  436. # 示例值:"open_id"
  437. # 可选值有:
  438. # open_id:用户的 open id
  439. # union_id:用户的 union id
  440. # user_id:用户的 user id
  441. # 默认值:open_id
  442. "display_formula_ref": "", # 控制公式、查找引用是否显示完整的原样返回结果。示例值:true
  443. "automatic_fields": "", # 控制是否返回自动计算的字段
  444. # 例如 created_by/created_time/last_modified_by/last_modified_time,true 表示返回
  445. # 示例值:true
  446. "page_token": "", # 分页标记
  447. # 第一次请求不填,表示从头开始遍历;
  448. # 分页查询结果还有更多项时会同时返回新的 page_token
  449. # 下次遍历可采用该 page_token 获取查询结果
  450. # 示例值:"recn0hoyXL"
  451. "page_size": count # 分页大小。示例值:10。数据校验规则:最大值 100
  452. }
  453. try:
  454. urllib3.disable_warnings()
  455. r = requests.get(url=url, headers=headers, params=params, proxies=proxies, verify=False)
  456. cls.page_token = r.json()["data"]["page_token"]
  457. items = r.json()["data"]["items"]
  458. for item in items:
  459. print(item)
  460. Common.logger().info("列出记录,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  461. except Exception as e:
  462. Common.logger().error("列出记录异常:{}", e)
  463. # 检索记录
  464. @classmethod
  465. def search_records(cls, record_id):
  466. """
  467. 该接口用于根据 record_id 的值检索现有记录
  468. 该接口支持调用频率上限为 20 QPS
  469. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/get
  470. """
  471. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" \
  472. + cls.app_token + "/tables/" + cls.table_id + "/records/" + record_id
  473. headers = {
  474. "Authorization": "Bearer " + cls.tenant_access_token(),
  475. "Content-Type": "application/json; charset=utf-8"
  476. }
  477. params = {
  478. "text_field_as_array": True, # 控制多行文本字段数据的返回格式, true 表示以数组形式返回。示例值:true
  479. # "user_id_type": "", # 用户 ID 类型
  480. # 示例值:"open_id"
  481. # 可选值有:
  482. # open_id:用户的 open id
  483. # union_id:用户的 union id
  484. # user_id:用户的 user id
  485. # 默认值:open_id
  486. "display_formula_ref": True, # 控制公式、查找引用是否显示完整的原样返回结果。示例值:true
  487. "automatic_fields": True, # 控制是否返回自动计算的字段
  488. # 例如 created_by/created_time/last_modified_by/last_modified_time,true 表示返回。示例值:true
  489. }
  490. try:
  491. urllib3.disable_warnings()
  492. r = requests.get(url=url, headers=headers, params=params, proxies=proxies, verify=False)
  493. Common.logger().info("检索记录,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  494. except Exception as e:
  495. Common.logger().error("检索记录异常:{}", e)
  496. # 新增记录
  497. @classmethod
  498. def create_record(cls, fields):
  499. """
  500. 该接口用于在数据表中新增一条记录
  501. 该接口支持调用频率上限为 10 QPS
  502. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/create
  503. """
  504. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" \
  505. + cls.app_token + "/tables/" + cls.table_id + "/records"
  506. headers = {
  507. "Authorization": "Bearer " + cls.tenant_access_token(),
  508. "Content-Type": "application/json; charset=utf-8"
  509. }
  510. body = fields
  511. try:
  512. urllib3.disable_warnings()
  513. r = requests.post(url=url, headers=headers, json=body, proxies=proxies, verify=False)
  514. Common.logger().info("新增记录,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  515. except Exception as e:
  516. Common.logger().error("新增记录异常:{}", e)
  517. # 新增多条记录
  518. @classmethod
  519. def create_records(cls, records):
  520. """
  521. 该接口用于在数据表中新增多条记录
  522. 该接口支持调用频率上限为 10 QPS
  523. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/batch_create
  524. """
  525. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" \
  526. + cls.app_token + "/tables/" + cls.table_id + "/records/batch_create"
  527. headers = {
  528. "Authorization": "Bearer " + cls.tenant_access_token(),
  529. "Content-Type": "application/json; charset=utf-8"
  530. }
  531. body = {
  532. "records": records
  533. }
  534. try:
  535. urllib3.disable_warnings()
  536. r = requests.post(url=url, headers=headers, json=body, proxies=proxies, verify=False)
  537. Common.logger().info("新增多条记录,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  538. except Exception as e:
  539. Common.logger().error("新增多条记录异常:{}", e)
  540. # 更新记录
  541. @classmethod
  542. def update_record(cls, record_id, fields):
  543. """
  544. 该接口用于更新数据表中的一条记录
  545. 该接口支持调用频率上限为 10 QPS
  546. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/update
  547. """
  548. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" \
  549. + cls.app_token + "/tables/" + cls.table_id + "/records/" + record_id
  550. headers = {
  551. "Authorization": "Bearer " + cls.tenant_access_token(),
  552. "Content-Type": "application/json; charset=utf-8"
  553. }
  554. body = fields
  555. try:
  556. urllib3.disable_warnings()
  557. r = requests.put(url=url, headers=headers, json=body, proxies=proxies, verify=False)
  558. Common.logger().info("更新记录,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  559. except Exception as e:
  560. Common.logger().error("更新记录异常:{}", e)
  561. # 更新多条记录
  562. @classmethod
  563. def update_records(cls, records):
  564. """
  565. 该接口用于更新数据表中的多条记录
  566. 该接口支持调用频率上限为 10 QPS
  567. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/batch_update
  568. """
  569. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" \
  570. + cls.app_token + "/tables/" + cls.table_id + "/records/batch_update"
  571. headers = {
  572. "Authorization": "Bearer " + cls.tenant_access_token(),
  573. "Content-Type": "application/json; charset=utf-8"
  574. }
  575. body = records
  576. try:
  577. urllib3.disable_warnings()
  578. r = requests.post(url=url, headers=headers, json=body, proxies=proxies, verify=False)
  579. Common.logger().info("更新多条记录,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  580. except Exception as e:
  581. Common.logger().error("更新多条记录异常:{}", e)
  582. # 删除记录
  583. @classmethod
  584. def del_record(cls, record_id):
  585. """
  586. 该接口用于删除数据表中的一条记录
  587. 该接口支持调用频率上限为 10 QPS
  588. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/delete
  589. """
  590. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" \
  591. + cls.app_token + "/tables/" + cls.table_id + "/records/" + record_id
  592. headers = {
  593. "Authorization": "Bearer " + cls.tenant_access_token(),
  594. "Content-Type": "application/json; charset=utf-8"
  595. }
  596. try:
  597. urllib3.disable_warnings()
  598. r = requests.delete(url=url, headers=headers, proxies=proxies, verify=False)
  599. Common.logger().info("删除记录,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  600. except Exception as e:
  601. Common.logger().error("删除记录异常:{}", e)
  602. # 删除多条记录
  603. @classmethod
  604. def del_records(cls, record_ids):
  605. """
  606. 该接口用于删除数据表中现有的多条记录
  607. 该接口支持调用频率上限为 10 QPS
  608. https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/batch_delete
  609. """
  610. url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" \
  611. + cls.app_token + "/tables/" + cls.table_id + "/records/batch_delete"
  612. headers = {
  613. "Authorization": "Bearer " + cls.tenant_access_token(),
  614. "Content-Type": "application/json; charset=utf-8"
  615. }
  616. body = {
  617. "records": record_ids # 删除的多条记录id列表。示例值:["recIcJBbvC","recvmiCORa"]
  618. }
  619. try:
  620. urllib3.disable_warnings()
  621. r = requests.post(url=url, headers=headers, json=body, proxies=proxies, verify=False)
  622. Common.logger().info("删除多条记录,code:{},msg:{}", r.json()["code"], r.json()["msg"])
  623. except Exception as e:
  624. Common.logger().error("删除多条记录异常:{}", e)
  625. if __name__ == "__main__":
  626. # feishu = Feishu()
  627. # print(feishu.get_bitable_token())
  628. 'reck6nLiZV'
  629. 'recHcfJZnG'
  630. 'recxdSMhzE'
  631. # 实例化多维表格
  632. bitable = Bitable()
  633. # # 获取多维表格元数据
  634. # bitable.get_apps()
  635. #
  636. # # 列出数据表
  637. # bitable.get_tables()
  638. #
  639. # # 列出记录
  640. # bitable.list_records(3)
  641. #
  642. # # 检索记录
  643. # bitable.search_records("recHcfJZnG")
  644. # # 新增一条记录
  645. # create_value = {
  646. # "fields": {
  647. # "uid": "0000000000",
  648. # "key_words": "0000000000",
  649. # "name": "功能开发🥕",
  650. # "screen_name": "功能开发🥕",
  651. # "person_url": {
  652. # "link": "https://bytedance.feishu.cn/drive/home/", "text": "https://bytedance.feishu.cn/drive/home/"
  653. # },
  654. # "description": "功能开发🥕",
  655. # "location": "null",
  656. # "friends_count": 9999999999,
  657. # "followers_count": 9999999999,
  658. # "favourites_count": 9999999999,
  659. # "listed_count": 9999999999,
  660. # "statuses_count": 9999999999,
  661. # "media_count": 9999999999,
  662. # "display_url": {
  663. # "link": "https://bytedance.feishu.cn/drive/home/",
  664. # "text": "https://bytedance.feishu.cn/drive/home/"
  665. # },
  666. # "created_at": 1656053209000,
  667. # "profile_image_url": {
  668. # "link": "https://bytedance.feishu.cn/drive/home/",
  669. # "text": "https://bytedance.feishu.cn/drive/home/"
  670. # },
  671. # "profile_banner_url": {
  672. # "link": "null",
  673. # "text": "null"
  674. # },
  675. # "ext_has_nft_avatar": "False",
  676. # "verified": "False",
  677. # "记录创建时间": 1656053209000,
  678. # # "记录修改时间": ""
  679. # }
  680. # }
  681. # bitable.create_record(create_value)
  682. # 新增多条记录
  683. # create_values = {
  684. # "fields": {
  685. # "uid": "0000000000",
  686. # "key_words": "0000000000",
  687. # "name": "功能开发🥕",
  688. # "screen_name": "功能开发🥕",
  689. # "person_url": {
  690. # "link": "https://bytedance.feishu.cn/drive/home/", "text": "https://bytedance.feishu.cn/drive/home/"
  691. # },
  692. # "description": "功能开发🥕",
  693. # "location": "null",
  694. # "friends_count": 9999999999,
  695. # "followers_count": 9999999999,
  696. # "favourites_count": 9999999999,
  697. # "listed_count": 9999999999,
  698. # "statuses_count": 9999999999,
  699. # "media_count": 9999999999,
  700. # "display_url": {
  701. # "link": "https://bytedance.feishu.cn/drive/home/",
  702. # "text": "https://bytedance.feishu.cn/drive/home/"
  703. # },
  704. # "created_at": 1656053209000,
  705. # "profile_image_url": {
  706. # "link": "https://bytedance.feishu.cn/drive/home/",
  707. # "text": "https://bytedance.feishu.cn/drive/home/"
  708. # },
  709. # "profile_banner_url": {
  710. # "link": "null",
  711. # "text": "null"
  712. # },
  713. # "ext_has_nft_avatar": "False",
  714. # "verified": "False",
  715. # "记录创建时间": 1656053209000,
  716. # # "记录修改时间": ""
  717. # }
  718. # }
  719. # values_list = [create_values, create_values]
  720. # bitable.create_records(values_list)
  721. # # 更新一条记录
  722. # use_record_id = "recxdSMhzE"
  723. # use_fields = {
  724. # "fields": {
  725. # "uid": "1111111111",
  726. # "key_words": "1111111111",
  727. # "name": "功能开发🥕",
  728. # "screen_name": "功能开发🥕",
  729. # "person_url": {
  730. # "link": "https://bytedance.feishu.cn/drive/home/", "text": "https://bytedance.feishu.cn/drive/home/"
  731. # },
  732. # "description": "功能开发🥕",
  733. # "location": "null",
  734. # "friends_count": 9999999999,
  735. # "followers_count": 9999999999,
  736. # "favourites_count": 9999999999,
  737. # "listed_count": 9999999999,
  738. # "statuses_count": 9999999999,
  739. # "media_count": 9999999999,
  740. # "display_url": {
  741. # "link": "https://bytedance.feishu.cn/drive/home/",
  742. # "text": "https://bytedance.feishu.cn/drive/home/"
  743. # },
  744. # "created_at": 1656053209000,
  745. # "profile_image_url": {
  746. # "link": "https://bytedance.feishu.cn/drive/home/",
  747. # "text": "https://bytedance.feishu.cn/drive/home/"
  748. # },
  749. # "profile_banner_url": {
  750. # "link": "null",
  751. # "text": "null"
  752. # },
  753. # "ext_has_nft_avatar": "False",
  754. # "verified": "False",
  755. # "记录创建时间": 1656053209000,
  756. # # "记录修改时间": ""
  757. # }
  758. # }
  759. # bitable.update_record(use_record_id, use_fields)
  760. # # 更新多条记录
  761. # "recxdSMhzE"
  762. # "recHcfJZnG"
  763. # use_records = {
  764. # "records": [
  765. # {
  766. # "record_id": "recxdSMhzE",
  767. # "fields": {
  768. # "uid": "3333333333",
  769. # "key_words": "3333333333",
  770. # "name": "功能开发🥕",
  771. # "screen_name": "功能开发🥕",
  772. # "person_url": {
  773. # "link": "https://bytedance.feishu.cn/drive/home/",
  774. # "text": "https://bytedance.feishu.cn/drive/home/"
  775. # },
  776. # "description": "功能开发🥕",
  777. # "location": "null",
  778. # "friends_count": 9999999999,
  779. # "followers_count": 9999999999,
  780. # "favourites_count": 9999999999,
  781. # "listed_count": 9999999999,
  782. # "statuses_count": 9999999999,
  783. # "media_count": 9999999999,
  784. # "display_url": {
  785. # "link": "https://bytedance.feishu.cn/drive/home/",
  786. # "text": "https://bytedance.feishu.cn/drive/home/"
  787. # },
  788. # "created_at": 1656053209000,
  789. # "profile_image_url": {
  790. # "link": "https://bytedance.feishu.cn/drive/home/",
  791. # "text": "https://bytedance.feishu.cn/drive/home/"
  792. # },
  793. # "profile_banner_url": {
  794. # "link": "null",
  795. # "text": "null"
  796. # },
  797. # "ext_has_nft_avatar": "False",
  798. # "verified": "False",
  799. # "记录创建时间": 1656053209000,
  800. # # "记录修改时间": ""
  801. # }
  802. # },
  803. # {
  804. # "record_id": "recHcfJZnG",
  805. # "fields": {
  806. # "uid": "3333333333",
  807. # "key_words": "3333333333",
  808. # "name": "功能开发🥕",
  809. # "screen_name": "功能开发🥕",
  810. # "person_url": {
  811. # "link": "https://bytedance.feishu.cn/drive/home/",
  812. # "text": "https://bytedance.feishu.cn/drive/home/"
  813. # },
  814. # "description": "功能开发🥕",
  815. # "location": "null",
  816. # "friends_count": 9999999999,
  817. # "followers_count": 9999999999,
  818. # "favourites_count": 9999999999,
  819. # "listed_count": 9999999999,
  820. # "statuses_count": 9999999999,
  821. # "media_count": 9999999999,
  822. # "display_url": {
  823. # "link": "https://bytedance.feishu.cn/drive/home/",
  824. # "text": "https://bytedance.feishu.cn/drive/home/"
  825. # },
  826. # "created_at": 1656053209000,
  827. # "profile_image_url": {
  828. # "link": "https://bytedance.feishu.cn/drive/home/",
  829. # "text": "https://bytedance.feishu.cn/drive/home/"
  830. # },
  831. # "profile_banner_url": {
  832. # "link": "null",
  833. # "text": "null"
  834. # },
  835. # "ext_has_nft_avatar": "False",
  836. # "verified": "False",
  837. # "记录创建时间": 1656053209000,
  838. # # "记录修改时间": ""
  839. # }
  840. # }
  841. # ]
  842. # }
  843. # bitable.update_records(use_records)
  844. # # 删除一条记录
  845. # bitable.del_record("reck6nLiZV")
  846. # # 删除多条记录
  847. # bitable.del_records(['recHcfJZnG', 'recxdSMhzE'])