#遇到问题的现象描述:
用python编一个程序,用于搜索指定目录下的文本文件,并将其中包含主机信息的文本内容提取出来。
这些文本文件是用批处理生成的,批处理的内容是:
ipconfig /all >d:\任意名字.txt
如:
ipconfig /all >d:\1.txt
其生成的结果类似于:
Windows IP 配置
主机名 . . . . . . . . . . . . . : MD-JK
主 DNS 后缀 . . . . . . . . . . . :
节点类型 . . . . . . . . . . . . : 混合
IP 路由已启用 . . . . . . . . . . : 否
WINS 代理已启用 . . . . . . . . . : 否
以太网适配器 以太网:
连接特定的 DNS 后缀 . . . . . . . :
描述. . . . . . . . . . . . . . . : Realtek PCIe GbE Family Controller
物理地址. . . . . . . . . . . . . : 04-DE-C4-AE-34-27
DHCP 已启用 . . . . . . . . . . . : 是
自动配置已启用. . . . . . . . . . : 是
本地链接 IPv6 地址. . . . . . . . : fe83::3143:bdfe:fc60:aea4%6(首选)
IPv4 地址 . . . . . . . . . . . . : 192.168.0.90(首选)
子网掩码 . . . . . . . . . . . . : 255.255.255.0
获得租约的时间 . . . . . . . . . : 2022年11月22日 9:31:44
租约过期的时间 . . . . . . . . . : 2159年3月25日 21:51:47
默认网关. . . . . . . . . . . . . : 192.168.0.52
DHCP 服务器 . . . . . . . . . . . : 192.168.0.52
DHCPv6 IAID . . . . . . . . . . . : 100974928
DHCPv6 客户端 DUID . . . . . . . : 00-01-00-01-25-AC-AE-0C-00-D4-C4-A1-8A-47
DNS 服务器 . . . . . . . . . . . : 218.85.107.99
218.85.102.95
TCPIP 上的 NetBIOS . . . . . . . : 已启用
用于获取各台电脑的:计算机名、IP地址及网卡号。
将收集来的文本文件统一放于d:\中,利用所编的python程序自动收集它们的如上三个参数,并逐一加入到一个字典中。以计算机名为键,IP及网卡号为值。
#问题相关代码片,运行结果,报错内容
以下是我编的代码,不好意思,我是初学者,故加了许多注释用于学习,请多包涵!
'''搜索指定目录下的文本文件,并将其中包含主机信息的文本内容提取出来'''
'''
思路:
1,先将指定目录下的文本文件含路径,加入一个列表
2,然后读取每一个文件,搜索是否包含“主机名”,
3,如果是,则将该文件(及路径)加入到另一个列表中
4,然后遍历该列表,将主机信息追加到小字典中
5,最后,以主机名为键,每个小字典为值,加入大字典中
'''
'''1,先将指定目录下的文本文件含路径,加入一个列表'''
#设置要获取文件列表的目录
import os
目录='d:\\'
#指定要获取的文件类型
文件类型='.txt'
#保存文件列表
文件列表=[]
路径文件列表=[]
for 文件名 in os.listdir(目录):
#os.listdir(路径) 方法用于
#返回指定的文件夹里包含的文件或文件夹的名字的列表
路径文件=os.path.join(目录,文件名)
#os.path.join(路径名1,路径名2,路径名n)函数用于
#连接两个或更多的路径名
#如果各路径名首字母不包含'/',则函数会自动加上
#如果有一个路径名是一个绝对路径,则在它之前的所有路径名均会被舍弃
#如果最后一个路径名为空,则生成的路径以一个'/'分隔符结尾
if (os.path.isfile(路径文件) and 路径文件[-4:].lower()==文件类型):
#os.path.isfile(路径文件):判断某一对象(需提供绝对路径)是否为文件
#os.path.isdir(路径):判断某一对象(需提供绝对路径)是否为目录
文件列表.append(文件名)
路径文件列表.append(路径文件)
print(文件列表)
print(路径文件列表)
'''2,然后读取每一个文件,搜索是否包含“主机名”'''
'''3,如果是,则将该文件(及路径)加入到另一个列表中'''
查找主机='主机名'
主机列表=[]
for 文件名 in 路径文件列表:
with open (文件名,'r',encoding='gbk',errors='ignore') as 文件:
#r:只读
#encoding='gbk':用gbk扩展码打开,以防乱码
#errors='ignore':如果出错(连GBK都无法搞定的代码)就忽略
for 行数 in 文件:
行=文件.readline()
#逐行读取文本文件
if 查找主机 in 行:
#如果在本行中找到关键字“主机名”
主机列表.append(文件名)
#则将路径文件追加到“主机列表”中
print(主机列表)
'''4,然后遍历该列表,将主机信息追加到小字典中'''
查找IP='IPv4 地址'
查找网卡='物理地址'
电脑字典={}
电脑字典汇总={}
for 主机文件 in 主机列表:
with open (主机文件) as 主机信息:
for 行数 in 主机信息:
行=主机信息.readline()
#逐行读取主机信息文件
if 查找主机 in 行:
索引=行.find(': ')+2
#变量‘行’的内容其实是一个字符串,可以当作列表来处理
#----------
#find()方法:
#find(要查找的字符串,开始索引默认0,结束索引默认-1末尾)
#检测字符串中是否包含'要查找的字符串',
#如果指定'开始索引'和'结束索引'范围,
#则检查是否包含在指定范围内;
#如果包含子字符串返回开始的索引值,否则返回-1
#----------
#由于搜索的关键词': '后有空格,故索引号+2
主机=行[索引:-1]
#将结果写入小字典,键=值
#从“索引”号到本行末尾,都是主机名,例如:
#主机名 . . . . . . . . . . . . . : JCDF
elif 查找IP in 行:
前索引=行.find(': ')+2
后索引=行.find('(首选)')
#因为这回要截取的是字符串的中间部分,而不是到末尾,例:
#IPv4 地址 . . . . . . . . . . . . : 192.168.0.71(首选)
IP=行[前索引:后索引]
电脑字典[查找IP]=IP
elif 查找网卡 in 行:
索引=行.find(': ')+2
网卡=行[索引:-1]
电脑字典[查找网卡]=网卡
#例:
#物理地址. . . . . . . . . . . . . : E0-D3-5D-DE-7B-AB
#读完一个文件
'''5,最后,以主机名为键,每个小字典为值,加入大字典中'''
#将小字典追加到大字典中
电脑字典汇总[主机]=电脑字典
print (f'退出for循环时的小字典:{电脑字典}')
print (f'退出for循环时的大字典:{电脑字典汇总}')
print (f'退出with open时的小字典:{电脑字典}')
print (f'退出with open时的大字典:{电脑字典汇总}')
print (f'退出遍历文件时的小字典:{电脑字典}')
print (f'退出遍历文件时的大字典:{电脑字典汇总}')
运行的结果是:
>>>
=============== RESTART: E:\python\文件_搜索并提取文件内容.py ===============
['1.txt', '2.txt', '3.txt', '4.txt', '5.txt', 'LogFile_Tcard.txt', 'ROBOCOPY_HELP.TXT']
['d:\\1.txt', 'd:\\2.txt', 'd:\\3.txt', 'd:\\4.txt', 'd:\\5.txt', 'd:\\LogFile_Tcard.txt', 'd:\\ROBOCOPY_HELP.TXT']
['d:\\1.txt', 'd:\\5.txt']
退出for循环时的小字典:{'物理地址': 'E0-D3-5D-DE-7B-AB', 'IPv4 地址': '192.168.0.71'}
退出for循环时的大字典:{'JCDF': {'物理地址': 'E0-D3-5D-DE-7B-AB', 'IPv4 地址': '192.168.0.71'}}
退出with open时的小字典:{'物理地址': 'E0-D3-5D-DE-7B-AB', 'IPv4 地址': '192.168.0.71'}
退出with open时的大字典:{'JCDF': {'物理地址': 'E0-D3-5D-DE-7B-AB', 'IPv4 地址': '192.168.0.71'}}
退出for循环时的小字典:{'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}
退出for循环时的大字典:{'JCDF': {'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}, 'MD-JK': {'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}}
退出with open时的小字典:{'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}
退出with open时的大字典:{'JCDF': {'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}, 'MD-JK': {'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}}
退出遍历文件时的小字典:{'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}
退出遍历文件时的大字典:{'JCDF': {'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}, 'MD-JK': {'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}}
可以看出,从第二个文本文件读取的内容覆盖到了第一个文件的分析结果中({'物理地址': 'E0-D3-5D-DE-7B-AB', 'IPv4 地址': '192.168.0.71'}被{'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}覆盖了。并且这个BUG是在退出里层for循环时就出现的。
#我期待的结果是:
退出遍历文件时的大字典:{'JCDF': {'物理地址': 'E0-D3-5D-DE-7B-AB', 'IPv4 地址': '192.168.0.71'}, 'MD-JK': {'物理地址': '04-D4-C4-AE-8A-47', 'IPv4 地址': '192.168.0.90'}}
请教各位,如何修改代码?不胜感激!