Python CSV Reader只有JSON的第一个字符

时间:2013-06-14 23:14:26

标签: python json csv

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()方法

4 个答案:

答案 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