如何用Python解析日志文件并将数据存储到数据库中?
我正在尝试解析一个日志文件,这个文件的结构如下所示。我想用Python来完成这个任务,并把提取的数据存储到数据库中,我该怎么做呢?
我能解析简单的键值对,但遇到了一些问题。
1: 我该如何解析嵌套结构?比如在示例文件中,context字段是嵌套在主组里的。
2: 如果分隔符是字符串,我该如何处理?比如对于键值对,分隔符是冒号(:),但在“site”这个键中,有一个键值对是site_url:http://something.com,这里的URL也包含冒号(:),这就导致了错误的结果。
{
"username": "lavania",
"host": "10.105.22.32",
"event_source": "server",
"event_type": "/courses/XYZ/CS101/2014_T1/xblock
/i4x:;_;_XYZ;_CS101;_video;_d333fa637a074b41996dc2fd5e675818/handler/xmodule_handler/save_user_state",
"context": {
"course_id": "XYZ/CS101/2014_T1",
"course_user_tags": {},
"user_id": 42,
"org_id": "XYZ"
},
"time": "2014-06-20T05:49:10.468638+00:00",
"site":"http://something.com",
"ip": "127.0.0.1",
"event": "{\"POST\": {\"saved_video_position\": [\"00:02:10\"]}, \"GET\": {}}",
"agent": "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:18.0) Gecko/20100101 Firefox/18.0",
"page": null
}
{
"username": "rihana",
"host": "10.105.22.32",
"event_source": "server",
"event_type": "problem_check",
"context": {
"course_id": "XYZ/CS101/2014_T1",
"course_user_tags": {},
"user_id": 40,
"org_id": "XYZ",
"module": {
"display_name": ""
}
},
"time": "2014-06-20T06:43:52.716455+00:00",
"ip": "127.0.0.1",
"event": {
"submission": {
"i4x-XYZ-CS101-problem-33e4aac93dc84f368c93b1d08fa984fc_2_1": {
"input_type": "choicegroup",
"question": "",
"response_type": "multiplechoiceresponse",
"answer": "MenuInflater.inflate()",
"variant": "",
"correct": true
}
},
"success": "correct",
"grade": 1,
"correct_map": {
"i4x-XYZ-CS101-problem-33e4aac93dc84f368c93b1d08fa984fc_2_1": {
"hint": "",
"hintmode": null,
"correctness": "correct",
"npoints": null,
"msg": "",
"queuestate": null
}
},
"state": {
"student_answers": {},
"seed": 1,
"done": null,
"correct_map": {},
"input_state": {
"i4x-XYZ-CS101-problem-33e4aac93dc84f368c93b1d08fa984fc_2_1": {}
}
},
"answers": {
"i4x-XYZ-CS101-problem-33e4aac93dc84f368c93b1d08fa984fc_2_1": "choice_0"
},
"attempts": 1,
"max_grade": 1,
"problem_id": "i4x://XYZ/CS101/problem/33e4aac93dc84f368c93b1d08fa984fc"
},
"agent": "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0",
"page": "x_module"
}
{
"username": "troysa",
"host": "localhost",
"event_source": "server",
"event_type": "/courses/XYZ/CS101/2014_T1/instructor_dashboard/api/list_instructor_tasks",
"context": {
"course_id": "XYZ/CS101/2014_T1",
"course_user_tags": {},
"user_id": 6,
"org_id": "XYZ"
},
"time": "2014-06-20T05:49:26.780244+00:00",
"ip": "127.0.0.1",
"event": "{\"POST\": {}, \"GET\": {}}",
"agent": "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0",
"page": null
}
2 个回答
你的数据是用JSON格式存储的。可以使用标准库中的json
模块来解析它。
不过,看起来你的数据是几个JSON字典拼在一起的。希望你只是从几个单独的条目中复制粘贴过来的,否则在详细解析之前,你可能需要先整理一下数据。
假设这些是单独的文件,我会给出一个例子,关于"username": "raeha"
这一组数据,它已经加载到data
变量中:
>>> import json
>>> newdata = json.loads(data)
>>> print(newdata["context"])
{'course_id': 'XYZ/CS101/2014_T1', 'course_user_tags': {}, 'org_id': 'XYZ', 'user_id': 40, 'module': {'display_name': ''}}
>>> print(newdata["context"]["user_id"])
40
json.loads()
这个方法可以把原始的JSON数据(以字符串形式)转换成Python的数据类型。通常,最外层的类型是一个字典(dict),每个键都是字符串,而每个值可以是字符串、列表、字典、数字,或者像True
、False
、None
这样的项。这些在JSON中分别对应true
、false
和null
。
正如之前提到的,这是一种JSON数据结构。我写了一些简单的代码,可以逐行读取你的日志文件,并尝试找到完整的多行JSON对象。一旦所有行都读取完毕,程序就结束了。我使用pprint来输出这些对象,这样结果就更容易被人理解,确保返回的字典看起来是正确的。
import json
import pprint
with open("log.txt") as infile:
# Loop until we have parsed all the lines.
for line in infile:
# Read lines until we find a complete object
while (True):
try:
json_data = json.loads(line)
# We have a complete onject here
pprint.pprint(json_data)
# Try and find a new JSON object
break
except ValueError:
# We don't have a complete JSON object
# read another line and try again
line += next(infile)
这段代码有点儿笨拙。它读取一行,看看是否有一个完整的可解析对象。如果没有,它就读取下一行,并把它和上一行连接起来。这个过程会一直持续,直到找到一个可以解析的对象。然后它会不断重复这个过程,直到所有行都被处理完,所有对象都被找到。
在代码的这个阶段,你已经把一个完整的JSON对象读入到json_data
中:
pprint.pprint(json_data)
我把这个字典用pprint输出,但它其实是一个标准的Python字典,可以像平常那样处理数据。例如,你可以用下面的方式获取course_id
:
json_data['context']['course_id']
或者通过下面的方式获取host
:
json_data['host']