BIMFACE批量获取文件元素number of elementId should be less than or equal to 1000错误

我踩了一个坑

春节前,尝试自己用Python写代码去获取自己BIMFACE中某个文件的所有元素,踩了一个坑,然后记录了下来,就在微博里分享出来,避免踩坑。

调用BIMFACE批量获取文件元素接口:https://api.bimface.com/data/v2/files/{fileId}/elements,当文件的元素较多时,会报如下错误:

{'code': 'system.error', 'message': 'number of elementId should be less than or equal to 1000'}

从错误可以看出,一次获取的元素太多了,如果把这个看作分页,那么分页的最大条目必须小于等于1000个,这时候问题就好解决了,不得不说,BIMFACE的提示还是很给力了。

踩坑过程

访问权限获取

通过BIMFACE给的APP_KEYAPP_SECRET,调用https://api.bimface.com/oauth2/token接口,我们可以获取到访问文件需要的ACCESS_TOKEN:

import requests
import base64

url = 'https://api.bimface.com/oauth2/token'
app_key = '[你的APP_KEY]'
app_secret = '[你的APP_SECRET]'
# Access Token有效期为7天,7天内该Token不会发生改变。
# BIMFACE 要求提供的appKey:appSecret字符串
key_and_secret = f'{app_key}:{app_secret}'
# BASE64 编码后字符串
encoded_kands = base64.b64encode(key_and_secret.encode()).decode()
# 设置 Authorization属性值
auth_str = f'Basic {encoded_kands}'
# 设置请求头
headers = {'Authorization': auth_str}
# 发送请求
response = requests.post(url, headers=headers)
# 输出返回的内容
print('响应内容(JSON格式):')
# 若要求返回字节类型,如:
# b'{"code":"success","message":null,"data":{"expireTime":"2024-02-13 16:04:51","token":"cn-cb19a350-aa23-46fa-8430-6e1fd70ed5ac"}}'
# 则使用response.content
json_result = response.json()
print(json_result)
# 获取AccessToken
print('AccessToken: ')
access_token = json_result['data']['token']
print(access_token)

如把该方法写成一个专门的授权类,那么:

import base64
import requests

ACCESS_TOKEN_API = 'https://api.bimface.com/oauth2/token'

# 访问凭证类
class Authorization:
    def __init__(self, app_key, app_secret):
        self.app_key = app_key
        self.app_secret = app_secret

    def get_access_token(self):
        url = ACCESS_TOKEN_API
        # BIMFACE 要求提供的appKey:appSecret字符串
        key_and_secret = f'{self.app_key}:{self.app_secret}'
        # BASE64 编码后字符串
        encoded_kands = base64.b64encode(key_and_secret.encode()).decode()
        # 设置 Authorization属性值
        auth_str = f'Basic {encoded_kands}'
        # 设置请求头
        headers = {'Authorization': auth_str}
        # 发送请求
        response = requests.post(url, headers=headers)   
        # 获取JSON格式返回的内容
        json_res = response.json()
        # 返回AccessToken
        return json_res['data']['token']

获取所有元素ID

调用接口https://api.bimface.com/data/v2/files/{fileId}/elements我们可以获得一个文件的所有元素,我们需要先调用接口https://api.bimface.com/data/v2/files/{fileId}/elementIds获得文件中的元素ID,然后根据这些元素ID去获得元素属性。

获取元素ID代码如下:

ELEMENT_IDS_API = 'https://api.bimface.com/data/v2/files/{fileId}/elementIds'
def get_element_ids(self, file_id, query_statement=''):
    url = ELEMENT_IDS_API.format(fileId=file_id)
    url += query_statement
    jwt_auth = f'Bearer {self.access_token}'
    # 请求头
    headers = {'Authorization': jwt_auth} 
    # 发送请求
    response = requests.get(url, headers=headers)
    # 获取JSON格式返回内容
    return response.json()

拿到所有元素ID后,就可以通过以下Python函数根据ID获取元素属性:

BATCH_GET_ELEMENTS_API = 'https://api.bimface.com/data/v2/files/{fileId}/elements'
def batch_get_elements(self, file_id, element_ids, query_statement=''):
    url = BATCH_GET_ELEMENTS_API.format(fileId=file_id)
    url += query_statement
    jwt_auth = f'Bearer {self.access_token}'
    # 请求header
    headers = {'Authorization': jwt_auth}     
    # 构建body
    body = {'elementIds': element_ids}
    # 发送请求
    response = requests.post(url, json=body, headers=headers)
    # 获取JSON格式返回内容
    return response.json()

获取所有元素属性

我一开始就想着全部获取:

def try_fetch_all_elements(access_token, file_id, element_ids):
    data_service = DataService(access_token)
    json = data_service.batch_get_elements(file_id, element_ids)
    print(json)

因我的文件有1387个元素,问题就暴露了:

{'code': 'system.error', 'message': 'number of elementId should be less than or equal to 1000'}

于是,按照错误提示,我们修改了调用方法:

def fetch_all_elements(access_token, file_id, element_ids, step=1000):
    length = len(element_ids)
    elements = []
    curr_idx = 0
    data_service = DataService(access_token)
    while curr_idx < length:
        upper = curr_idx + step
        if upper > length:
            upper = length
        json = data_service.batch_get_elements(file_id, element_ids[curr_idx:upper])
        if json['code'] == 'success':
            elements += json['data']
        curr_idx += step
    return elements

将每次获取的最大值限制在1000个及以下,问题可以解决。

最后的两个数据访问代码如下:

import base64
import requests

BATCH_GET_ELEMENTS_API = 'https://api.bimface.com/data/v2/files/{fileId}/elements'
ELEMENT_IDS_API = 'https://api.bimface.com/data/v2/files/{fileId}/elementIds'

# 数据服务类    
class DataService:
    def __init__(self, access_token):
        self.access_token = access_token

    # 每次请求小于等于1000个元素ID        
    def batch_get_elements(self, file_id, element_ids, query_statement=''):
        url = BATCH_GET_ELEMENTS_API.format(fileId=file_id)
        url += query_statement
        jwt_auth = f'Bearer {self.access_token}'
        # 请求header
        headers = {'Authorization': jwt_auth}     
        # 构建body
        body = {'elementIds': element_ids}
        # 发送请求
        response = requests.post(url, json=body, headers=headers)
        # 获取JSON格式返回内容
        return response.json()
    
    def get_element_ids(self, file_id, query_statement=''):
        url = ELEMENT_IDS_API.format(fileId=file_id)
        url += query_statement
        jwt_auth = f'Bearer {self.access_token}'
        # 请求头
        headers = {'Authorization': jwt_auth} 
        # 发送请求
        response = requests.get(url, headers=headers)
        # 获取JSON格式返回内容
        return response.json()
        

调用代码如下:

import sys, os
import time
import json
sys.path.append(os.path.abspath('.'))
from common.util import DataService

def main():
    access_token = '[你的Access_Token]'
    file_id = '[你的FILE_ID]'
    data_service = DataService(access_token)
    print('all element ids: ')
    json_ids = data_service.get_element_ids(file_id)
    print(json_ids)
    print(f'there are {len(json_ids["data"])} elements.')
    # 纳秒为单位的计时器
    start_time = time.perf_counter_ns()
    # elements = fetch_all_elements(access_token, file_id, json_ids['data'])
    elements = fetch_all_elements(access_token, file_id, json_ids['data'])
    if not elements:
        return
    finish_time = time.perf_counter_ns()
    time_span = finish_time - start_time   
    # 写入到文件
    file_name = os.path.abspath(f'./data/{file_id}_{time.strftime("%Y-%m-%d_%H%M%S", time.localtime())}.json')
    with open(file_name, 'wt') as fout:
        fout.write(json.dumps(elements))
        fout.flush()
    print('number of elements: ')
    print(len(elements))
    print(f'it costs {time_span / 1000.0}μs to get all elements.')

def fetch_all_elements(access_token, file_id, element_ids, step=1000):
    length = len(element_ids)
    elements = []
    curr_idx = 0
    data_service = DataService(access_token)
    while curr_idx < length:
        upper = curr_idx + step
        if upper > length:
            upper = length
        json = data_service.batch_get_elements(file_id, element_ids[curr_idx:upper])
        if json['code'] == 'success':
            elements += json['data']
        curr_idx += step
    return elements

if __name__ == '__main__':
    main()   

不自做轮子

这次踩坑我自己用Python来调用,实际上,BIMFACE的SDK比较成熟,使用好的SDK,能提升我们的开发效率。

[bimface-java-sdk](https://github.com/bimface/bimface-java-sdk)

[BIMFace.SDK](https://gitee.com/NAlps/BIMFace.SDK)

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Humbunklung

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值