【问题标题】:How to pipe multi-line JSON Objects into separate python invocations如何将多行 JSON 对象通过管道传输到单独的 python 调用中
【发布时间】:2016-08-20 07:24:32
【问题描述】:

我知道将标准输入管道传输到 shell 中的下游进程的基础知识,只要将每一行单独处理或作为一个输入,我就可以让我的管道工作。

但是当我想读 4 行标准输入,做一些处理,再读 6 行,然后做同样的事情时,我对管道的理解有限就成了一个问题。

例如,在下面的管道中,每次 curl 调用都会产生未知数量的输出行,这些行构成一个 JSONObject:

cat geocodes.txt \
  | xargs  -I% -n 1 curl -s 'http://maps.googleapis.com/maps/api/geocode/json?latlng='%'&sensor=true' \
  | python -c "import json,sys;obj=json.load(sys.stdin);print obj['results'][0]['address_components'][3]['short_name'];"

如何每次python 调用只消耗一个 JSONObject?请注意,我实际上在 Python 方面的经验可以忽略不计。我实际上对Node.js 有更多经验(使用Node.js 处理JSON curl 输出会更好吗?)

Geocodes.txt 类似于:

51.5035705555556,-3.15153263888889
51.5035400277778,-3.15153477777778
51.5035285833333,-3.15150258333333
51.5033861111111,-3.15140833333333
51.5034980555556,-3.15146016666667
51.5035285833333,-3.15155505555556
51.5035362222222,-3.15156338888889
51.5035362222222,-3.15156338888889

编辑 我有一种讨厌的感觉,答案是你需要逐行阅读并在解析之前检查你是否有一个完整的对象。有什么功能可以帮我完成繁重的工作吗?

【问题讨论】:

    标签: python json node.js stdin xargs


    【解决方案1】:

    我相信这种方法会实现您想要的。首先,将您的 python 脚本保存在一个文件中,例如my_script.py。然后执行以下操作:

    cat geocodes.txt \
      | xargs  -I% sh -c "curl -s 'http://maps.googleapis.com/maps/api/geocode/json?latlng='%'&sensor=true' | python my_script.py"
    

    my_script.py 在哪里:

    import json,sys;obj=json.load(sys.stdin);print obj['results'][0]['address_components'][3]['short_name'];
    

    输出:

    Cardiff
    Cardiff
    Cardiff
    Cardiff
    Cardiff
    Cardiff
    Cardiff
    Cardiff
    

    我承认,这看起来有点老套。


    原始答案

    我不是 bash 向导,所以我的直觉是简单地用 Python 做所有事情。以下脚本将说明 Python 3 中的这种方法:

    import urllib.request as request
    import urllib.parse as parse
    import json
    
    serviceurl = "http://maps.googleapis.com/maps/api/geocode/json?"
    
    with open("geocodes.txt") as f:
        for line in f:
            url = (serviceurl +
                   parse.urlencode({'latlng':line, 'sensor':'true'}))
            with request.urlopen(url) as response:
                bytes_data = response.read()
            obj = json.loads(bytes_data.decode('utf-8'))
            print(obj['results'][0]['address_components'][3]['short_name'])
    

    输出:

    Cardiff
    Cardiff
    Cardiff
    Cardiff
    Cardiff
    Cardiff
    Cardiff
    Cardiff
    

    【讨论】:

    • 感谢您的回复,我可能最终会使用其中的一部分,即使它违背了我的新编程宗教(Unix 哲学),即保持您的程序小而可组合,以便您可以轻松修改他们。我想做的是:find -iname "**jpg" | head -10 | xargs exiftool -n -p '$GPSLatitude,$GPSLongitude' | xargs -I% -n 1 curl -s 'http://maps.googleapis.com/maps/api/geocode/json?latlng='%'&sensor=true' | python -c "import json,sys;obj=json.load(sys.stdin);print obj['results'][0]['address_components'][3]['short_name'];"
    • @Sridhar-Sarnobat 那么 Python 脚本如何简单地接受一些可变数量的 Lat,Long 对(即来自 xargs exiftool -n -p $GPSLatitude,$GPSLongitude' 并打印到 stdout 你想要什么?这是否足够模块化?因为我'不知道如何使用 curl 和 xargs 来一次一个地管道每个 JSON 对象。也许有一种方法。尝试解析乱七八糟的 JSON 对象似乎很不简洁。
    • @Sridhar-Sarnobat 查看我的编辑,我相信我已经知道如何使用管道和您正在使用的确切 python 脚本来完成您想要的工作。
    • 哇,它确实有效。 find -L $PWD -maxdepth 50 -type f -iname "**jpg" | xargs -n 1 -d'\n' exiftool -q -n -p '$GPSLatitude,$GPSLongitude' 2>/dev/null | xargs -I% sh -c "curl -s 'http://maps.googleapis.com/maps/api/geocode/json?latlng='%'&sensor=true' | python ~/trash/my_script.py" 。剩下的唯一事情(留给我作为练习)是内联 python 代码,这样我就可以将其复制并粘贴到任何主机的命令行,而无需先创建脚本文件。也许在 commandlienfu.com 上分享它:)
    • 理想情况下,我想避免使用动态字符串命令的子shell,但正如任何经验丰富的程序员也知道的那样 - 先让它工作并收获使用它的成果,然后分别尝试和改进代码的优雅。我还应该说,对你有礼貌是有回报的。通常我会否决你提出的整体怪物不如 Unix 哲学。我很高兴我没有那样做。再次感谢您:D
    【解决方案2】:

    您不需要 python 或 node.js。 jq 专为 UNIX 风格的 json 过滤设计:

    sudo apt-get install jq
    

    然后:

    cat geocodes.txt  \
      | xargs  -I% curl -s 'http://maps.googleapis.com/maps/api/geocode/json?latlng='%'&sensor=true'  \
      | jq --unbuffered '.results[0].formatted_address'
    

    或者,如果您想对所有 JPG 文件执行此操作:

    find -iname "**jpg" \
      | xargs -n 1 -d'\n' exiftool -q -n -p '$GPSLatitude,$GPSLongitude' 
      | xargs  -I% curl -s 'http://maps.googleapis.com/maps/api/geocode/json?latlng='%'&sensor=true'  
      | jq --unbuffered  '.results[0].formatted_address'
    

    【讨论】:

      【解决方案3】:

      看看:

      http://trentm.com/json/#FEATURE-Grouping

      Grouping can be helpful for "one JSON object per line" formats or for things such as:
      
      $ cat *.json | json -g ...
      

      安装:

      sudo npm install -g json
      

      我自己没有尝试过,因此无法验证它是否有效,但可能是缺少链接来执行您想要的操作(组 JSON)

      【讨论】:

        猜你喜欢
        • 2015-01-05
        • 1970-01-01
        • 2020-06-22
        • 2016-02-13
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多