Verra Registry多项目Web Scraping字段适配问题求助
适配Verra Registry多项目API数据提取的解决方案
问题背景
抓取Verra Registry网站项目数据,通过https://registry.verra.org/uiapi/resource/resourceSummary/{id}接口获取信息,需处理超4000个项目,但不同项目返回的字段结构存在差异。原代码依赖固定索引提取字段,无法适配所有项目,需要更通用的解决方案。
原代码(存在固定索引依赖问题)
import json from bs4 import BeautifulSoup import requests from urllib import request api_url = "https://registry.verra.org/uiapi/resource/resourceSummary/3628" info_gathered = {'Heading': [], 'ID': [],'State' : [], 'Category': [], 'Proponent': [], 'Project Status': [], 'EAER': [], 'Project Type': [], 'Methodology': [], 'Project Validator': [], 'Project_registration': [], 'CPT': [], 'File_link': []} data = requests.get(api_url).json() html = request.urlopen(api_url).read() heading = data['resourceName'] ID = data['resourceIdentifier'] i = data['participationSummaries'][0] print(i['attributes']) Category = i['programCode'] if len(data['attributes']) == 2: State = data['attributes'][1]['values'][0]['value'] elif len(data['attributes']) == 1: State = "None" Proponent = '' for nume in range(0, len(i['attributes'][0]['values'])): if nume != (len(i['attributes'][0]['values'])-1): Proponent = Proponent + i['attributes'][0]['values'][nume]['value'] + ', ' if nume == (len(i['attributes'][0]['values'])-1): Proponent = Proponent + i['attributes'][0]['values'][nume]['value'] + '.' Project_Status = i['attributes'][1]['values'][0]['value'] EAER = i['attributes'][2]['values'][0]['value'] Project_type = i['attributes'][3]['values'][0]['value'] Methodology = i['attributes'][4]['values'][0]['value'] Project_Validator = i['attributes'][5]['values'][0]['value']
优化方案
1. 基于属性名称而非索引提取数据
不同项目的attributes数组顺序可能不同,但每个属性的name字段是固定标识(比如"Proponent"、"Project Status"),通过匹配name定位属性,替代固定索引。
2. 构建字段映射字典
定义目标字段与API返回中对应属性name的映射,统一处理逻辑:
FIELD_MAPPING = { 'Proponent': 'Proponent', 'Project Status': 'Project Status', 'EAER': 'EAER', 'Project Type': 'Project Type', 'Methodology': 'Methodology', 'Project Validator': 'Project Validator' }
3. 封装通用提取函数
编写函数处理单个项目数据,自动处理缺失字段,返回标准化结果:
def extract_project_data(project_id): api_url = f"https://registry.verra.org/uiapi/resource/resourceSummary/{project_id}" try: response = requests.get(api_url) response.raise_for_status() data = response.json() except Exception as e: print(f"获取项目{project_id}数据失败: {str(e)}") return None # 提取基础字段 result = { 'Heading': data.get('resourceName', 'None'), 'ID': data.get('resourceIdentifier', 'None'), 'Category': data.get('participationSummaries', [{}])[0].get('programCode', 'None'), 'State': 'None' } # 处理State字段 if len(data.get('attributes', [])) >= 2: result['State'] = data['attributes'][1]['values'][0].get('value', 'None') # 将participation属性转为字典,方便按名称查找 participation_attrs = data.get('participationSummaries', [{}])[0].get('attributes', []) attr_dict = {attr['name']: attr['values'] for attr in participation_attrs} # 遍历映射提取字段 for target_field, attr_name in FIELD_MAPPING.items(): values = attr_dict.get(attr_name, []) # 拼接多值字段(如Proponent可能有多个主体) if values: result[target_field] = ', '.join([v.get('value', '') for v in values]) + '.' else: result[target_field] = 'None' return result
4. 批量处理项目
循环调用函数处理所有项目ID,收集结果:
# 示例:假设project_ids是包含所有项目ID的列表 project_ids = [1, 3628, 3658] all_project_data = [] for project_id in project_ids: project_data = extract_project_data(project_id) if project_data: all_project_data.append(project_data) # 将结果保存为JSON文件 import json with open('verra_projects.json', 'w', encoding='utf-8') as f: json.dump(all_project_data, f, ensure_ascii=False, indent=2)
方案优势
- 摆脱固定索引依赖,适配不同项目的字段结构差异
- 自动处理缺失字段,避免索引越界错误
- 代码模块化,便于维护和扩展新字段
- 支持批量处理,高效完成4000+项目的数据提取
内容的提问来源于stack exchange,提问作者user15143876
相关产品推荐
相关产品推荐

