You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何遍历键值对不规范的字典列表并提取指定字段值?

提取非结构化字典列表中的特定字段

我有一个大型字典列表,键值对没有固定模式,需要提取username、hostname、host_ip等相关值。部分字典可能完全不存在目标值,比如有的包含username,有的则没有。

示例数据

logs = [{
        '_index': '.siem-signals-default-000015', 
        '_type': '_doc', 
        '_id': '456', 
        '_score': None, 
        '_source': {
            '@timestamp': '2023-03-22T14:05:53.855Z', 
            'ecs': {'version': '1.10.0'}, 
            'host': {
                'id': '456', 
                'name': 'SRV2', 
                'ip': ['172.30.5.115', 'fe80::5efe:ac1e:573'], 
                'mac': ['00:00:00:00:00:00:00'],
                'architecture': 'x86_64', 
                'os': {'build': '14393.5717', 'type': 'windows'}
                }, 
                'log': {'level': 'warning'}, 
                'message': 'Some message', 
                'file': {
                    'directory': 'C:', 
                    'extension': 'psm1', 
                    'path': 'C:', 
                    'name': 'Heartbeat.psm1'
                    }, 
                'agent': {
                    'name': 'SRV2', 
                    'type': 'winlogbeat', 
                    'version': '7.14.1', 
                    'hostname': 'SRV2', 
                    'ephemeral_id': '456a', 
                    'id': '4567'
                    }, 
                'winlog': {
                    'user': {'name': 'SYSTEM', 'type': 'User', 'identifier': 'S-1-5-18', 'domain': 'NT AUTHORITY'}, 
                    'event_id': '4104', 
                    'opcode': 'On create calls', 
                    'provider_name': 'Microsoft-Windows-PowerShell', 
                    'channel': 'Microsoft-Windows-PowerShell/Operational'
                    }
                }}, 

    {
        '_index': '.siem-signals-default-000015', 
        '_type': '_doc', 
        '_id': '123', 
        '_score': None, 
        '_source': {
            '@timestamp': '2023-03-22T14:05:53.854Z', 
            'winlog': {
                'user': {'identifier': 'S-1-5-18', 'domain': 'NT AUTHORITY', 'name': 'SYSTEM', 'type': 'User'}, 
                'task': 'Execute a Remote Command', 
                'computer_name': 'SRV1', 
                'provider_name': 'Microsoft-Windows-PowerShell'
                }, 
            'event': {
                'provider': 'Microsoft-Windows-PowerShell', 
                'action': 'Execute a Remote Command', 
                'created': '2023-03-22T14:02:36.498Z'
                }, 
            'log': {'level': 'warning'}, 
            'powershell': {
                'sequence': 1, 
                'total': 1, 
                'file': {
                    'script_block_id': '123', 
                    'script_block_text': "Some script"
                    }
                                }, 
            'ecs': {'version': '1.10.0'}, 
            'message': "Some message", 
            'host': {
                'mac': ['00:00:00:00:00:00:00', '00:00:00:00:00:00:00'], 
                'hostname': 'SRV1', 
                'architecture': 'x86_64', 
                'os': {
                    'build': '14393.5717', 
                    'type': 'windows'
                    }, 
                'id': '456', 
                'ip': ['172.30.5.115', 'fe80::5efe:ac1e:573']
                    }, 
            'user': {'id': 'S-1-5-18'}
                    }, 
        'sort': [1679493953854]
    }]

问题说明

示例中两个字典都包含hostname,但存储位置不同:第一个字典的hostname位于['_source']['host']['name'],第二个则位于['_source']['host']['hostname']。

我尝试了以下递归打印函数,但未解决问题:

def printlogs(logs):
    for items in logs:
        for k, v in items.items():
            if isinstance(v, dict):
                pritlogs(v)
            else:
                print("{0} : {1}".format(k, v))
printlogs(logs)

解决方案

问题分析

原函数存在拼写错误(pritlogs应为printlogs),且仅能打印所有键值对,无法针对性提取目标字段。需要编写递归查找逻辑,根据目标字段的可能键名遍历字典,收集所需值。

实现代码

def find_value(data, target_keys):
    """递归查找字典/列表中匹配目标键的值,返回第一个匹配结果"""
    if isinstance(data, dict):
        for k, v in data.items():
            if k in target_keys:
                return v
            elif isinstance(v, (dict, list)):
                result = find_value(v, target_keys)
                if result is not None:
                    return result
    elif isinstance(data, list):
        for item in data:
            result = find_value(item, target_keys)
            if result is not None:
                return result
    return None

def extract_fields(logs):
    extracted_list = []
    for log_entry in logs:
        extracted = {}
        # 提取username:匹配键名包括'name'(常见于user/winlog.user节点)
        extracted['username'] = find_value(log_entry, ['name'])
        # 提取hostname:匹配键名包括'hostname'、'name'、'computer_name'
        extracted['hostname'] = find_value(log_entry, ['hostname', 'name', 'computer_name'])
        # 提取host_ip:匹配键名'ip',优先取IPv4地址
        ip_list = find_value(log_entry, ['ip'])
        if ip_list:
            # 筛选IPv4地址(含小数点)
            ipv4_addresses = [ip for ip in ip_list if '.' in ip]
            extracted['host_ip'] = ipv4_addresses[0] if ipv4_addresses else ip_list[0]
        else:
            extracted['host_ip'] = None
        extracted_list.append(extracted)
    return extracted_list

# 执行提取并打印结果
extracted_results = extract_fields(logs)
for res in extracted_results:
    print(res)

代码说明

  1. find_value函数:递归遍历字典和列表,查找匹配目标键名的值,返回第一个找到的结果,适配非结构化数据的嵌套结构。
  2. extract_fields函数:针对每个日志条目,调用find_value提取指定字段,同时处理IP的特殊情况(从列表中优先选取IPv4地址)。
  3. 可根据实际需求扩展目标键名,比如若username还可能出现在其他键名下,只需添加到target_keys列表即可。

内容的提问来源于stack exchange,提问作者OverflowStack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 08:14:54