【问题标题】:Python CSV Reader Only First Character of JSONPython CSV 阅读器仅 JSON 的第一个字符
【发布时间】:2013-06-14 23:14:25
【问题描述】:

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

【问题讨论】:

  • 有人将此标记为过于本地化。 MySQL 用户可能一直在处理糟糕的 CSV,但 MySQL 和 AWS 是这样一个小众数据库和 ISP...

标签: python json csv


【解决方案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】:

    我认为这不能称为 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,这可以让您的工作更轻松。

    这有点骇人听闻 - 正确的实现可能应该使用 a parser(正式的 EBNF 语法应该在 10 行以下)。

    【讨论】:

    • 这与我的想法一致——我们只是希望避免手动字符串操作以降低代码复杂性。具有不同样式换行符的 JSON 没有这样的运气,所以如果数据库作者打算将换行符存储为特定字段的一部分(在我们周末离开之前它们不是),这可能是一个问题。我们可以更具体地使用匹配模式,但同样,这个特定项目的目标是保持代码简单和可维护。感谢您在帖子上所做的所有努力!
    【解决方案3】:

    这里有一些非常有趣的建议,但在进一步考虑后,我的团队决定我们将寻求更直接的解决方案。不幸的是,对于未来的读者来说,这有点特定于 MySQL/AWS CSV,但我们决定纠正 SQL 查询本身的问题:

    SELECT RANDOM_FIELD, RANDOM_FIELD2, ..., REPLACE(JSON_FIELD,'\n','NEWLINE') FROM DATABASE ....
    

    这修复了真正问题所在的换行符,而不是 CSV。请注意,最初的目标是用 \\n 替换 \n,但 CSV 生成器再次删除了转义“\”。话虽如此,我真的很喜欢 Paulo Scardine 的解决方案,它在我们使用的少数测试用例中运行良好;如果 JSON 中的字符串实际上包含换行符,似乎可能会出现问题(这是我们没有机会与数据库作者讨论的问题)。

    【讨论】:

    • 如果 stackoverflow 政策允许,我会在下周恢复工作时接受最终答复。
    【解决方案4】:

    您既没有有效的 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
    

    【讨论】:

    • 如果同一个文件中有多个记录,这会起作用吗?
    • 我同意 Paulo Scardine 的观点 - 这对于 CSV 的第一“行”之外的任何内容都不起作用,特别是因为每个 JSON 补丁中的逗号数量可变(sn- p 只是众多可能性中的一种)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-25
    • 1970-01-01
    • 2019-11-05
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    • 1970-01-01
    相关资源
    最近更新 更多