将部分键值对格式文本导入pandas DataFrame遇KeyError问题求助
解决读取键值对文本到Pandas DataFrame时的KeyError问题
文件test的内容
costCenter: LL63238012 mail: shiva.gowni@LLp.com LLpResponsible: cn=LLf58420,ou=Personal,ou=People,ou=LLDI,o=LLP LLpHomeDirectory: nisMapName=auto.home,ou=RDC_AMEC_LL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quality=economy,NisMap=llc1002:/proj/llc1002_ziz1/q,Quota=10621 LLpHomeDirectory: nisMapName=auto.home,ou=RDC_AMEC_LL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quality=scratKG,NisMap=llc1002:/proj/llc1002_ziz1_scratKG/q,Quota=12000,Id=scratKG fullName: Tulip project ziz1 costCenter: MX61FRK604 mail: ali.pina@LLp.com LLpResponsible: cn=LLa11826,ou=Personal,ou=People,ou=LLDI,o=LLP LLpHomeDirectory: nisMapName=auto.home,ou=SAT_AMEC_MX-GDL01,ou=Locations,ou=LLDI,o=LLP#0#Quality=reference,NisMap=llc0156:/proj/llc0156_zmx28home_3/q,Quota=100,Id=3 LLpHomeDirectory: nisMapName=auto.home,ou=SAT_AMEC_MX-GDL01,ou=Locations,ou=LLDI,o=LLP#0#Quality=reference,NisMap=llc0156:/proj/llc0156_zmx28home/q,Quota=300 LLpHomeDirectory: nisMapName=auto.home,ou=SAT_AMEC_MX-GDL01,ou=Locations,ou=LLDI,o=LLP#0#Quality=reference,NisMap=llc0156:/proj/llc0156_zmx28home_2/q,Quota=100,Id=2 fullName: xFSL to LLDI migration costCenter: RU61FPD561 mail: udi.landen@LLp.com LLpResponsible: cn=LLa09278,ou=Personal,ou=People,ou=LLDI,o=LLP LLpHomeDirectory: nisMapName=auto.home,ou=RDC_AMEC_LL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quota=1,Quality=EconomyHP,NisMap=llc2002:/proj/llc2002_zru12/q LLpHomeDirectory: nisMapName=auto.home,ou=RDC_AMEC_LL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quota=2800,Quality=EconomyHP,NisMap=llc1002:/proj/llc1002_zru12_analog/q,Id=analog LLpHomeDirectory: nisMapName=auto.home,ou=RDC_AMEC_LL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quota=1100,Quality=EconomyHP,NisMap=llc1002:/proj/llc1002_zru12_home/q,Id=home LLpHomeDirectory: nisMapName=auto.home,ou=RDC_AMEC_LL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quality=EconomyHP,NisMap=llc1002:/proj/llc1002_zru12_libddk/q,Quota=2162,Id=libddk LLpHomeDirectory: nisMapName=auto.home,ou=RDC_AMEC_LL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quality=EconomyHP,NisMap=llc1002:/proj/llc1002_zru12_proj/q,Quota=1102,Id=proj fullName: zru12 costCenter: KG63010285 mail: adam.smith@LLp.com LLpHomeDirectory: nisMapName=auto.home,ou=RDC_EMEA_NL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quality=BLLinessCriticalHP,Quota=60,NisMap=llc4008:/proj/llc4008_zuriKG/q fullName: Container to store ZuriKG vault costCenter: KG63010285 mail: adam.smith@LLp.com LLpHomeDirectory: nisMapName=auto.home,ou=RDC_EMEA_NL-CDC01,ou=Locations,ou=LLDI,o=LLP#0#Quality=EconomyHP,Quota=1,NisMap=llc3008:/proj/llc3008_zuriKG_rme/q LLpHomeDirectory: nisMapName=auto.home,ou=SAT_EMEA_NL-RME01,ou=Locations,ou=LLDI,o=LLP#0#Quality=EconomyHP,Quota=30,NisMap=llc4014:/proj/llc4014_zuriKG_rme/q LLpHomeDirectory: nisMapName=auto.home,ou=SAT_EMEA_NL-RME01,ou=Locations,ou=LLDI,o=LLP#0#Quality=ScratKGHP,Quota=400,NisMap=llc4014:/proj/llc4014_zuriKG_rme_scratKG/q,Id=scratKG fullName: Project to restore project data on the RME work on HP-UX
原使用代码
def generate(data): for record in data.split("\n\n"): # Split records based on two newlines (unix) result = {} for line in record.split("\n"): # Split properties based on single newlines (unix) if line: # Skip empty lines happening for extra or trailing newlines key, *value = line.split(": ") # Tolerant to lines with more than a single ´: ´ (*values) value = ": ".join(value) # Recover original value if more than a single (`: `) if key in result: result[key] += ";" + value else: result[key] = value if result: # Don't yield empty results yield result frame = pd.DataFrame(generate("test")) print(frame) #frame["responsible"] = frame["LLpResponsible"].str.extract("cn=([\w]*)") frame["location"] = frame["LLpHomeDirectory"].str.extract("ou=([\w_\-]*)") frame["directory"] = frame["LLpHomeDirectory"].str.findall("NisMap=\w+:([\w_\-/]*)") df1 = frame[['costCenter', 'mail', 'responsible', 'location', 'directory']] #df2 = df.explode("directory")[["costCenter", "responsible", "directory", "mail", "location"]] print(df1)
报错信息
$ python ldapDataParse1 test 0 Traceback (most recent call last): File "/home/lib64/python3.6/site-packages/pandas/core/indexes/base.py", line 2898, in get_loc return self._engine.get_loc(casted_key) File "pandas/_libs/index.pyx", line 70, in pandas._libs.index.IndexEngine.get_loc File "pandas/_libs/index.pyx", line 101, in pandas._libs.index.IndexEngine.get_loc File "pandas/_libs/hashtable_class_helper.pxi", line 1675, in pandas._libs.hashtable.PyObjectHashTable.get_item File "pandas/_libs/hashtable_class_helper.pxi", line 1683, in pandas._libs.hashtable.PyObjectHashTable.get_item KeyError: 'LLpHomeDirectory' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "ldapDataParse1", line 30, in <module> frame["location"] = frame["LLpHomeDirectory"].str.extract("ou=([\w_\-]*)") File "/home/lib64/python3.6/site-packages/pandas/core/frame.py", line 2906, in __getitem__ indexer = self.columns.get_loc(key) File "/home/lib64/python3.6/site-packages/pandas/core/indexes/base.py", line 2900, in get_loc raise KeyError(key) from err KeyError: 'LLpHomeDirectory'
问题解决
核心错误点
你调用generate("test")时,传入的是字符串"test",而非test文件的实际内容,导致generate函数处理的是单个字符串,生成的DataFrame完全不符合预期,自然找不到LLpHomeDirectory列。
修正后的完整代码
import pandas as pd def generate(data): for record in data.split("\n\n"): # 按两个换行分割记录 result = {} for line in record.split("\n"): # 按单个换行分割属性行 if line.strip(): # 去除空白字符后判断是否为空,处理多余空格 key, *value = line.split(": ", 1) # 只按第一个": "分割,避免值里的冒号干扰 value = value[0] if value else "" if key in result: result[key] += ";" + value else: result[key] = value if result: # 跳过空结果 yield result # 读取文件内容,这是关键修正 with open("test", "r") as f: file_content = f.read() frame = pd.DataFrame(generate(file_content)) # 提取responsible字段,缺失时填充空值 frame["responsible"] = frame["LLpResponsible"].str.extract("cn=([\w]*)").fillna("") # 提取location字段,缺失时填充空值 frame["location"] = frame["LLpHomeDirectory"].str.extract("ou=([\w_\-]*)").fillna("") # 提取所有directory路径 frame["directory"] = frame["LLpHomeDirectory"].str.findall("NisMap=\w+:([\w_\-/]*)") # 选择需要的列 df1 = frame[['costCenter', 'mail', 'responsible', 'location', 'directory']] print(df1) # 如需展开directory列表成多行,取消下面注释 # df2 = df1.explode("directory")[["costCenter", "responsible", "directory", "mail", "location"]] # print(df2)
额外优化说明
- 用
with open读取文件,确保文件正常关闭,获取真实的文件内容。 - 分割键值对时用
split(": ", 1),只按第一个": "分割,避免值中包含的冒号导致错误分割。 - 对可能缺失的字段用
fillna("")处理,避免后续操作报错。 - 用
line.strip()判断空行,处理文件中可能存在的空白行(比如多个连续空格的行)。
内容的提问来源于stack exchange,提问作者user2023
相关产品推荐
相关产品推荐

