循环追加Pandas Series至DataFrame失败及列表赋值后变为NoneType的问题排查
问题排查与修复方案
嘿,我一眼就瞅出问题所在了——你误用了Python列表的append()方法!
核心问题解释
Python里的列表是可变对象,append()方法是原地修改原列表,它的返回值是None。当你执行portInfo = portInfo.append([target[0],portsDF])时,相当于把None赋值给了portInfo,这就导致后续它变成了NoneType,完全没法继续存储数据。
快速修复
只需要把赋值语句改成直接调用append就行,不用重新赋值:
# 把这行 portInfo = portInfo.append([target[0],portsDF]) # 改成 portInfo.append([target[0], portsDF])
这样原列表就会被直接修改,不会丢失之前的数据。
优化后的完整代码
我还顺便给你优化了nmap结果的解析逻辑,避免因为行内多空格导致的索引越界问题:
import pandas as pd import subprocess from tabulate import tabulate def vulnScan(targets): portInfo = [] print(type(portInfo)) columnNames = ["Port","Protocol","State","Service"] for target in targets: rows = [] print("Executing: nmap -Pn "+target[1]) result = subprocess.run(['nmap','-Pn',target[1]], universal_newlines = True, stdout = subprocess.PIPE) for line in result.stdout.split("\n"): # 过滤掉无关行,只保留有效端口信息行 if "/" in line and "Starting" not in line and "Nmap done" not in line: # 先去除首尾空格再分割,避免多空格导致的列表长度异常 tableInfo = line.strip().split() # 加个长度判断,防止索引越界报错 if len(tableInfo) >= 4: port = tableInfo[0].split("/")[0] protocol = tableInfo[0].split("/")[1] status = tableInfo[1] service = tableInfo[3] print(port,protocol,status,service) newRow = pd.Series(data=[port,protocol,status,service],index=columnNames) rows.append(newRow) portsDF = pd.DataFrame(rows, columns = columnNames) print(tabulate(portsDF, headers="keys", tablefmt='psql')) # 直接追加到列表,无需赋值 portInfo.append([target[0], portsDF]) print(type(portInfo)) print(portInfo)
额外小建议
如果后续你需要通过主机名快速查找对应的端口DataFrame,用字典存储会比列表更方便:
# 初始化字典 portInfo_dict = {} # 存储时直接用主机名当键 portInfo_dict[target[0]] = portsDF # 后续查找直接用portInfo_dict["主机名"]就能拿到对应的DF
另外,手动解析nmap的文本输出容易踩坑,推荐用python-nmap库来处理扫描结果,它能直接解析nmap的输出格式,省去手动分割字符串的麻烦,你可以尝试一下~
内容的提问来源于stack exchange,提问作者Ethel Rusebottom
相关产品推荐
相关产品推荐

