Python 如何提取非结构化数据

2019-04-07 16:25:19 +08:00
 anonymoustian

现在有一行行的文本数据( DNS 日志),是非结构化的,但是也有结构,比如

ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1 这种

如何提取出指定字段的行呢? 比如过滤出 rcode=ok 的字段行,或者如何将这些数据变成结构化的,比如对应到一个 表格里,如果有的话 就为 “=” 后面的值,如果没有就为空

5436 次点击
所在节点    Python
41 条回复
LokiSharp
2019-04-08 09:09:56 +08:00
用 pyparsing 定义语法之后解析
yuhr123
2019-04-08 09:14:12 +08:00
split 生成以空格分割的列表,迭代列表查找=号所在位置,用这个位置坐切片取封号前面的字符串,和你需要的字符串做 if 判断。
niknik
2019-04-08 09:56:16 +08:00
以空格 split 啊,然后转 json
shuax
2019-04-08 10:09:33 +08:00
直接两次 split 多简单啊
capric
2019-04-08 10:21:08 +08:00
src = 'ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1'
dst = dict(parts.split('=') for parts in src.split())
print(dst.get('ad'))
thautwarm
2019-04-08 11:00:18 +08:00
除开正则还有各种文法库。

比如我写的一个库的话,
import rbnf.zero as ze
ze_exp = ze.compile("""
import std.common.[Number Name Space]
Pair ::= keys=Name '::=' values=(~Space)*
-> (k.value, "".join(x.value for x in v))
Row ::= pairs=Pair+ -> dict(pairs)
Logs ::= (rows<<Row '\n'+)+ -> rows
"""
ze_exp.match("你的日志字符串").result
www5070504
2019-04-08 11:24:11 +08:00
两个 split 加上 字典推导式 用默认字典可以避免键可能不存在的情况
btv2bt
2019-04-08 11:49:52 +08:00
应该可以直接转 dict 吧
C0dEr
2019-04-08 13:28:29 +08:00
@lastpass 最近在搞 antlr,有啥好的资料看看吗
TheBestSivir
2019-04-08 15:39:20 +08:00
看你的场景咯。你对性能有需求么?有的话还是不要正则了。另外,这种简单场景正则真的有利于维护么???
hakono
2019-04-08 16:11:46 +08:00
噗,其实说真的,如果要搜索的字符串格式固定的话,首先想到的不应该是转为 dict,而是
for line in log_lines:
if "rcode=ok" in line:
xxxxxxxxxxxxxxxxxxx
caryqy
2019-04-08 16:15:38 +08:00
cat dns.log | awk -F ' ' '{print $3}' >> res.log
caryqy
2019-04-08 16:19:59 +08:00
cat dns.log | awk -F ' ' '{if ($3=="rcode=ok") {print $3} else {print "rcode=error"}}'
omph
2019-04-08 16:25:38 +08:00
http://pypi.python.org/pypi/parse
类似于 C 语言的 sscanf 字符串扫描
bumz
2019-04-08 17:20:15 +08:00
用 BNF 写一下文法?然后用 BNF Parser Generator 生成一下相应的解析器

(其实这种正则就行,逃
(再复杂直接用递归下降写就好
freakxx
2019-04-08 17:48:43 +08:00
content = "ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1 test test2"

1
直接字符串判断
rocde_is_ok = "rcode=ok"
rocde_is_ok in content

2

pairs = content.split(' ')

content_dict = {}
for name_value in pairs:
nv = name_value.split('=', 1)
if len(nv) != 2:
nv.append("")

key, value = nv
content_dict[key] = value
saulshao
2019-04-08 23:46:08 +08:00
上来就先 Split,然后写个函数分析 split 之后的结果,决定要不要将每个=加入最终结果。
我不建议用正则,你这个规律性太强了......
lastpass
2019-04-09 00:54:40 +08:00
@C0dEr 我看的就是 The Definitive ANTLR 4 Reference 这本书。简单易懂\(//∇//)\。
wonderay
2019-04-09 13:27:17 +08:00
https://github.com/google/textfsm/wiki

解析半结构化的的数据,满足你的一切需求
如果不是很复杂还是用正则吧
shawndev
2019-04-11 16:52:54 +08:00
空格换成换行就是 ini 格式了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/552701

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX