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 的字段行,或者如何将这些数据变成结构化的,比如对应到一个 表格里,如果有的话 就为 “=” 后面的值,如果没有就为空

5200 次点击
所在节点    Python
41 条回复
matsuz
2019-04-07 16:29:50 +08:00
正则表达式
lastpass
2019-04-07 16:30:57 +08:00
py 不知道。
antlr 倒是非常简单。
anonymoustian
2019-04-07 16:34:04 +08:00
@matsuz 谢谢老哥,除了正则还有什么方便的库么
zjsxwc
2019-04-07 16:35:11 +08:00
C 语言可以 sscanf

Python 可以 正则
recall704
2019-04-07 16:37:10 +08:00
如果只是这种,不是可以按空格分割吗?
anonymoustian
2019-04-07 16:39:09 +08:00
@recall704 是可以按照空格分割,但是比如说我想提 src=232.190.252.222 后面的 ip 地址,我在想有没有这种方法可以直接 getline('src') 这种 好像也不麻烦哈~ 而且字段不一定存在
matsuz
2019-04-07 16:44:34 +08:00
@lastpass 你这种结构的最合适的就是正则

```python
import re

match = re.match(
r'ad=([^ ]+)\W+cd=([^ ]+)\W+rcode=([^ ]+)\W+qdcount=([^ ]+)\W+ancount=([^ ]+)\W+nscount=([^ ]+)\W+arcount=([^ ]+)\W+src=([^ ]+)\W+dst=([^ ]+)',
'ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1',
)

for i in range(1, 10):
print(match.group(i))
```
e2c
2019-04-07 16:47:10 +08:00
这么简单的文本,可以自己解析了
CEBBCAT
2019-04-07 16:58:17 +08:00
为什么我想到的是两个 spilt ?我思维太初级了?
Kilerd
2019-04-07 17:07:15 +08:00
这么简单的处理都写不出来吗?
Kylin30
2019-04-07 17:17:28 +08:00
要我这外行来搞的话,那就直接先 split 空格然后 split 等号,2 个循环就变成了一个 dict,之后处理就很随便了。每行格式固定的话,不计较什么性能代码好看的还是非常简单的。
希望有大佬来说说,看看有什么高级搞法学习一下。
westoy
2019-04-07 17:19:07 +08:00
from collections import defaultdict
import re

ini = defaultdict(lambda: None, re.findall('(?:^|\s+)([^\=]+)\=([\S]+)','''ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1'''))

print(ini['helloworld'], ini['src'])


如果结构复杂一点, 比如 xx=xx xx="yy" xx='yy' xx='zz abc'这种, 用 pyparsing 更方便一点
Levox
2019-04-07 18:24:06 +08:00
``` python
>>> s = 'ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1'
>>>
>>> from urllib import parse
>>> d = parse.parse_qs(s.replace(' ', '&'))
>>>
>>> d['src']
['232.190.252.222']
>>>
```
secsilm
2019-04-07 22:02:13 +08:00
@CEBBCAT split 不低级,而且比 re 模块快
911speedstar
2019-04-07 22:19:54 +08:00
非结构化用正则,结构化用 xpath。。。
mintist
2019-04-07 22:43:37 +08:00
先 split,然后用个 json 来结构化存储
lastpass
2019-04-08 00:34:47 +08:00
@matsuz 不不不,正则并没有 antlr 强大。而且正则那又臭又长辣眼睛的代码无论是写还是维护都是灾难。所以,我目前项目里处理这种字符串都是使用的 antlr。
jiaqiangbandongg
2019-04-08 04:04:34 +08:00
s = "ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1"
data = dict(map(lambda x:x.split("="),str.split()))
print(data["rcode"])
jiaqiangbandongg
2019-04-08 04:05:23 +08:00
一行处理就够了
dartabe
2019-04-08 06:03:45 +08:00
split 之后存个字典 再查找键值就行了 求大佬评价一下。。。

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

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

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

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

© 2021 V2EX