Amazon AWS Data Pipeline提供CSV文件作为MySQL数据库的输出。在CSV中,有一个包含JSON的字段,我们试图分别使用Python的内置CSV和JSON阅读器提取和解码。但是,由于生成CSV的方式,JSON不会以引号开头,并且CSV解析器仅返回该CSV字段的JSON中的第一个“{”。
我们认为CSV阅读器会看到第一个'{',然后会看到一个换行符,它将其解释为CSV行的结尾。如果JSON包装在引号中,则脚本可以正常工作。请参阅以下代码:
with open(args.env_vars[0] + '/click_stream_source.csv', 'r') as csvFile:
csvReader = csv.reader(csvFile, delimiter = ',')
with open(args.env_vars[1] + '/clickstream_target.csv', 'wb') as csvTarget:
csvWriter = csv.writer(csvTarget, delimiter = ',')
for row in csvReader:
json_data = json.loads(row[5])
示例CSV为:
495019,,8239,E3728E7D480248AA2EB5D5BB5C467737,67.84.254.6,{
""requests"": [
{
""queryString"": null,
""time"": ""2013-06-14T11:53:40Z"",
""userAgent"": ""Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"",
""requestURI"": ""/xxxxx/xxxx/xxxx.xxxxxxx"",
""class"": ""xxxxx"",
""params"": {
""action"": ""xxxxx"",
""controller"": ""xxxx""
},
""isAjaxRequest"": false
}]}
我们得到了
ValueError:期待对象......
其中json.loads()方法
答案 0 :(得分:1)
我认为这不能称为CSV,因此CSV模块无效。
您可以使用正则表达式将[\r\n]\s+
转换为空格。如果“JSON”是最后一个字段,则可以按列数进行拆分(为了将最后一列转换为有效的JSON所需的转换留作读者的作业)示例:
In [1]: l = """495019,,8239,E3728E7D480248AA2EB5D5BB5C467737,67.84.254.6,{
...: ""requests"": [
...: {
...: ""queryString"": null,
...: ""time"": ""2013-06-14T11:53:40Z"",
...: ""userAgent"": ""Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"",
...: ""requestURI"": ""/xxxxx/xxxx/xxxx.xxxxxxx"",
...: ""class"": ""xxxxx"",
...: ""params"": {
...: ""action"": ""xxxxx"",
...: ""controller"": ""xxxx""
...: },
...: ""isAjaxRequest"": false
...: }]}"""
In [2]: import re
In [3]: l_ = re.sub(r'[\n\r]\s+', ' ', l)
In [4]: l_
Out[4]: '495019,,8239,E3728E7D480248AA2EB5D5BB5C467737,67.84.254.6,{ ""requests"": [ { ""queryString"": null, ""time"": ""2013-06-14T11:53:40Z"", ""userAgent"": ""Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"", ""requestURI"": ""/xxxxx/xxxx/xxxx.xxxxxxx"", ""class"": ""xxxxx"", ""params"": { ""action"": ""xxxxx"", ""controller"": ""xxxx"" }, ""isAjaxRequest"": false }]}'
In [5]: l_.split(',', 5)
Out[5]:
['495019',
'',
'8239',
'E3728E7D480248AA2EB5D5BB5C467737',
'67.84.254.6',
'{ ""requests"": [ { ""queryString"": null, ""time"": ""2013-06-14T11:53:40Z"", ""userAgent"": ""Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"", ""requestURI"": ""/xxxxx/xxxx/xxxx.xxxxxxx"", ""class"": ""xxxxx"", ""params"": { ""action"": ""xxxxx"", ""controller"": ""xxxx"" }, ""isAjaxRequest"": false }]}']
查看“JSON”内部的分割线是否与记录末尾不同(例如,一个是\n
,另一个是\r\n
,这可以使您的工作更轻松。
这有点hackish - 正确的实现可能应该使用a parser(正式的EBNF语法应该在10行以下)。
答案 1 :(得分:1)
我认为从技术上讲你不能称之为CSV,因为它违反了解析规则,但我并不想迂腐,我试图说这是放弃内置解析工具和老去的理由,制作有限状态机。这是一个快速而肮脏的例子,你可以适应你的目的。
#!/usr/bin/env python
import re
import json
def fix_and_parse(gathered_lines):
strJson = '{' + "\n".join(gathered_lines)
strJson = strJson.replace('""', '"')
return json.loads(strJson)
state = 0
with open('csvFile', 'r') as csvFile:
gathered_lines = []
for line in csvFile:
if re.search('^\d', line):
if gathered_lines:
print json.dumps(fix_and_parse(gathered_lines), indent=4)
state = 0
gathered_lines = []
else:
state = 1
if state == 1:
gathered_lines.append(line)
print json.dumps(fix_and_parse(gathered_lines), indent=4)
答案 2 :(得分:1)
这里有一些非常有趣的建议,但经过进一步的考虑,我的团队决定我们会寻求更直接的解决方案。不幸的是,对于未来的读者来说,这有点特定于MySQL / AWS CSV,但我们决定纠正SQL查询本身的问题:
SELECT RANDOM_FIELD, RANDOM_FIELD2, ..., REPLACE(JSON_FIELD,'\n','NEWLINE') FROM DATABASE ....
这解决了换行问题,而不是CSV问题。注意,最初的目标是使用\\ n来替换\ n,但CSV生成器再次删除转义符'\'。话虽如此,我真的很喜欢Paulo Scardine的解决方案,它适用于我们玩过的少数测试用例;如果JSON中的字符串实际上包含换行符(这是我们没有机会与数据库作者讨论的话),似乎可能存在问题。
答案 3 :(得分:0)
你既没有有效的csv,也没有有效的json。
您可以使用正则表达式将[\ r \ n] \ s +转换为空格
出于什么目的?
import json
data = '''495019,,8239,E3728E7D480248AA2EB5D5BB5C467737,67.84.254.6,{
"requests": [
{
"queryString": null,
"time": "2013-06-14T11:53:40Z",
"userAgent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)",
"requestURI": "/xxxxx/xxxx/xxxx.xxxxxxx",
"class": "xxxxx",
"params": {
"action": "xxxxx",
"controller": "xxxx"
},
"isAjaxRequest": false
}]}'''
pieces = data.split(',', 5)
print pieces[5]
json_dict = json.loads( pieces[5] )
print json_dict['requests'][0]['time']
--output:--
{
"requests": [
{
"queryString": null,
"time": "2013-06-14T11:53:40Z",
"userAgent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)",
"requestURI": "/xxxxx/xxxx/xxxx.xxxxxxx",
"class": "xxxxx",
"params": {
"action": "xxxxx",
"controller": "xxxx"
},
"isAjaxRequest": false
}]}
2013-06-14T11:53:40Z