如何用Python过滤API值?巴西政府采购API字段扩展需求
嘿,很高兴帮你解决这个扩展需求!你已经搞定了cnpj_contratada字段的处理,现在要扩展valor_inicial的处理,还想知道怎么过滤API返回的数据对吧?下面我一步步给你拆解:
1. 扩展
valor_inicial字段的处理 巴西政府采购API返回的valor_inicial通常是带格式的字符串(比如R$ 1.234,56),直接用的话不方便计算,所以我们需要把它转换成数值类型。这里推荐用Decimal来处理金额,避免浮点精度问题,同时兼容巴西的数值格式。
先看完整的代码示例:
import requests import locale from decimal import Decimal # 兼容系统是否安装巴西本地化环境,两种方式解析金额字符串 try: locale.setlocale(locale.LC_ALL, 'pt_BR.UTF-8') def parse_valor(valor_str): if not valor_str: return None # 用locale工具解析格式化的金额字符串 try: return Decimal(locale.atof(valor_str.replace('R$', '').strip())) except ValueError: print(f"警告:无法解析金额字符串 {valor_str}") return None except locale.Error: # 系统未安装pt_BR locale时,手动处理格式 def parse_valor(valor_str): if not valor_str: return None # 移除货币符号、空格,替换千分位点为空,逗号换为点 cleaned = valor_str.replace('R$', '').strip().replace('.', '').replace(',', '.') try: return Decimal(cleaned) except ValueError: print(f"警告:无法解析金额字符串 {valor_str}") return None def fetch_and_process_contratos(uasg_id): # 构造API请求URL url = f"http://compras.dados.gov.br/contratos/v1/contratos.json?uasg={uasg_id}" response = requests.get(url) response.raise_for_status() # 主动抛出请求错误,方便排查问题 data = response.json() processed_contratos = [] # 遍历返回的合同列表(注意API的嵌套结构:_embedded -> contratos) for contrato in data.get('_embedded', {}).get('contratos', []): processed_item = { # 保留你已实现的cnpj_contratada处理逻辑 'cnpj_contratada': contrato.get('cnpj_contratada'), # 新增valor_inicial的处理 'valor_inicial': parse_valor(contrato.get('valor_inicial')) # 其他需要处理的字段可以在这里继续添加 } processed_contratos.append(processed_item) return processed_contratos
这段代码的核心是:
- 兼容不同系统的本地化环境,确保金额解析正常
- 把
valor_inicial转换成Decimal类型,方便后续计算和过滤
2. 过滤API中的值
过滤数据有两种思路,优先用第一种,效率更高:
2.1 利用API参数直接过滤(推荐)
巴西政府采购API支持通过URL参数提前过滤数据,这样返回的结果已经是你需要的,不需要下载全部数据再处理。比如:
- 按金额范围过滤:如果API支持
valor_inicial_min或valor_inicial_max参数,直接加在URL里# 示例:获取uasg=153229且初始金额大于10000的合同 url = f"http://compras.dados.gov.br/contratos/v1/contratos.json?uasg=153229&valor_inicial_min=10000" - 按CNPJ过滤:如果需要特定供应商的合同,可以用
cnpj_contratada参数url = f"http://compras.dados.gov.br/contratos/v1/contratos.json?uasg=153229&cnpj_contratada=12345678000199"
具体支持哪些参数,可以参考合同模块的官方文档找“Filtros”相关说明。
2.2 在Python中过滤已获取的数据
如果API不支持你需要的过滤条件,那就先获取全部数据,再用列表推导或filter函数过滤:
示例1:过滤初始金额大于10000的合同
contratos = fetch_and_process_contratos(153229) filtered_contratos = [ item for item in contratos if item['valor_inicial'] is not None and item['valor_inicial'] > Decimal('10000') ]
示例2:多条件过滤(金额在5000-50000之间,且CNPJ不为空)
filtered_contratos = [ item for item in contratos if item['valor_inicial'] is not None and Decimal('5000') <= item['valor_inicial'] <= Decimal('50000') and item['cnpj_contratada'] is not None ]
示例3:用filter函数过滤(适合复杂逻辑)
def filter_contrato(item): if item['valor_inicial'] is None: return False # 自定义过滤逻辑:金额大于10000且CNPJ以"123"开头 return item['valor_inicial'] > Decimal('10000') and item['cnpj_contratada'].startswith('123') filtered_contratos = list(filter(filter_contrato, contratos))
额外提醒:处理分页数据
如果返回的合同很多,API会分页返回,你需要遍历所有分页才能拿到全部数据。这里给你加个分页处理的版本:
def fetch_all_contratos(uasg_id): url = f"http://compras.dados.gov.br/contratos/v1/contratos.json?uasg={uasg_id}" all_contratos = [] while url: response = requests.get(url) response.raise_for_status() data = response.json() # 添加当前页的合同 all_contratos.extend(data.get('_embedded', {}).get('contratos', [])) # 获取下一页的URL(API返回的_links.next.href) url = data.get('_links', {}).get('next', {}).get('href') # 处理所有合同的字段 processed = [] for contrato in all_contratos: processed.append({ 'cnpj_contratada': contrato.get('cnpj_contratada'), 'valor_inicial': parse_valor(contrato.get('valor_inicial')) }) return processed
这样就能拿到某个UASG的所有合同数据啦!
内容的提问来源于stack exchange,提问作者Reinaldo Chaves
相关产品推荐
相关产品推荐

