【问题标题】:JSON to CSV File RubyJSON 到 CSV 文件 Ruby
【发布时间】:2016-11-10 12:17:29
【问题描述】:

我正在尝试通过 Ruby 将以下 JSON 转换为 CSV,但我的代码遇到了问题。我边走边学,感谢您的帮助。

require 'json'
require 'net/http' 
require 'uri' 
require 'csv'

uri = 'https://www.mapquestapi.com/search/v2/radius?key=Imjtd%7Clu6t200zn0,bw=o5-layg1&radius=3000&callback=processPOIs&maxMatches=4000&origin=40.7686973%2C-73.9918181&hostedData=mqap.33882_stores_prod%7Copen_status%20=%20?%20OR%20open_status%20=%20?%20OR%20open_status%20=%20?%7CExisting,Coming%20Soon,New%7C' 

response = Net::HTTP.get_response(URI.parse(uri)) 

struct = JSON.parse(response.body.scan(/processPOIs\((.*)\);/).first.first)  


CSV.open("output.csv", "w") do |csv| 
  JSON.parse(struct).read.each do |hash| 
    csv << hash.values
  end
end

我收到的错误是:

from c:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/json-1.8.3/lib/json/common.rb:155:in `new'
from c:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/json-1.8.3/lib/json/common.rb:155:in `parse'
from test.rb:14:in `block in <main>'
from c:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1273:in `open'
from test.rb:13:in `<main>'

我正在尝试从以下链接中获取所有数据并将其放入一个 CSV 文件中,以便稍后进行分析。 https://www.mapquestapi.com/search/v2/radius?key=Imjtd%7Clu6t200zn0,bw=o5-layg1&radius=3000&callback=processPOIs&maxMatches=4000&origin=40.7686973%2C-73.9918181&hostedData=mqap.33882_stores_prod%7Copen_status%20=%20?%20OR%20open_status%20=%20?%20OR%20open_status%20=%20?%7CExisting,Coming%20Soon,New%7C

【问题讨论】:

  • 您遇到了什么具体问题?
  • 只是没有写入 CSV。我不断收到指向 JSON.parse(struct) 行的错误。
  • 您遇到什么错误?您确定response.body 是您所期望的吗?你检查过response.body.scan(/processPOIs\((.*)\);/) 确实是 JSON 吗?
  • 收到错误:在“
    中的块”中。正如我所提到的,我对所有这些都是新手。我认为 response.body.scan 将 JSON 转换为文本字符串。
  • 错误不止于此。 'where is pancakes house?' 是字符串而不是 JSON,'{"where is":"pancakes house?"}' 是字符串和 JSON。

标签: ruby json csv


【解决方案1】:

感谢大家的帮助。我能够将所有内容都放入 CSV,然后使用一些 VBA 按照我想要的方式组织它。

require 'json'
require 'net/http' 
require 'uri' 
require 'csv'

uri = 'https://www.mapquestapi.com/search/v2/radius?key=Imjtd%7Clu6t200zn0,bw=o5-layg1&radius=3000&callback=processPOIs&maxMatches=4000&origin=40.7686973%2C-73.9918181&hostedData=mqap.33882_stores_prod%7Copen_status%20=%20?%20OR%20open_status%20=%20?%20OR%20open_status%20=%20?%7CExisting,Coming%20Soon,New%7C' 

response = Net::HTTP.get_response(URI.parse(uri)) 

matches = response.body.match(/processPOIs\((.*)\)/)
json = response.body[12..-3]
struct = JSON.parse(json)

CSV.open("output.csv", "w") do |csv| 

    csv << struct['searchResults'].map { |result| result['fields']}
  end

【讨论】:

    【解决方案2】:

    您在这里遇到了几个问题,其中最重要的是您调用了两次JSON.parse。第二次调用struct,这是第一次调用JSON.parse的结果。你基本上是在做JSON.parse(JSON.parse(string))。哎呀。

    在你第二次调用JSON.parse 的那一行还有另一个问题:你在它返回的值上调用read。据我所知,JSON.parse 通常不会返回任何响应 read 的内容。

    修复这两个错误后,您的代码如下所示:

    struct = JSON.parse(response.body.scan(/processPOIs\((.*)\);/).first.first)
    
    CSV.open("output.csv", "w") do |csv| 
      struct.each do |hash| 
        csv << hash.values
      end
    end
    

    这应该可以工作 iif struct 是一个响应 each 的对象(像一个数组),each 产生的值都响应 values(像一个哈希)。换句话说,这段代码假定JSON.parse 将返回一个哈希数组或类似的东西。如果不是——那么,这超出了这个问题的范围。

    顺便说一句,这不是很好:

    response.body.scan(/processPOIs\((.*)\);/).first.first
    

    String#scan 的目的是查找字符串中与正则表达式匹配的每个子字符串。但是您只关心第一场比赛,所以scan 是错误的选择。

    另一种方法是使用String#match

    matches = response.body.match(/processPOIs\((.*)\)/)
    json = matches[1]
    struct = JSON.parse(json)
    

    但是,这太过分了。由于这是一个 JSONP 响应,我们知道它看起来像这样:

    processPOIs(...);
    

    ...给出或采用尾随分号或换行符。我们不需要正则表达式来查找括号内的部分,因为我们已经知道它在哪里:它从开头开始 13 个字符(即索引 12)并在结束前结束两个字符(“索引”-3) .这使得使用String#slice,又名String#[] 变得容易:

    json = response.body[12..-3]
    struct = JSON.parse(json)
    

    就像我说的,“给或取一个尾随分号或换行符”,因此您可能需要根据 API 返回的内容调整该结束索引。这样一来,.first.first 就不再丑陋了,而且速度也更快了。

    【讨论】:

      猜你喜欢
      • 2011-07-18
      • 2016-06-14
      • 2015-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      • 2015-12-10
      相关资源
      最近更新 更多