2016-07-08 2 views
0

Я пытаюсь преобразовать следующий JSON в CSV через Ruby, но у меня проблемы с моим кодом. Я учусь, когда я иду, поэтому любая помощь приветствуется.JSON to CSV File Ruby

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

+0

Какая у вас конкретная проблема? –

+0

Он просто не пишет в CSV. Я продолжаю получать ошибку, указывающую на строку JSON.parse (struct). – awald

+0

Какая ошибка вы получаете? Вы уверены, что «response.body» - это то, что вы ожидаете от этого? Вы проверили, что 'response.body.scan (/ processPOIs \ ((. *) \); /)' На самом деле JSON? –

ответ

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 

Это должно работать IIFstruct является объектом, который отвечает на 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, и это быстрее.

0

Спасибо всем за помощь. Я смог получить все в 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