如何从Google货币计算器中获取JSON?

时间:2013-06-06 23:24:18

标签: ruby json api calculator currency

我正在使用HTTParty从Google检索此信息:http://www.google.com/ig/calculator?hl=en&q=1USD=?COP

data = HTTParty.get("http://www.google.com/ig/calculator?hl=en&q=1USD=?COP").body
=> "{lhs: \"1 U.S. dollar\",rhs: \"1\xA0901.14068 Colombian pesos\",error: \"\",icc: true}"

我想解析数据并使用JSON.parse(data)将其显示为JSON对象,但它会返回错误:

JSON.parse(data)
JSON::ParserError: 746: unexpected token at '{lhs: "1 U.S. dollar",rhs: "1�901.14068 Colombian pesos",error: "",icc: true}'
    from /usr/lib/ruby/1.9.1/json/common.rb:148:in `parse'
    from /usr/lib/ruby/1.9.1/json/common.rb:148:in `parse'
    from (irb):39
    from /usr/bin/irb:12:in `<main>'

我想获取该信息并将其显示在我的网站上以供其使用,但我无法解析它。

2 个答案:

答案 0 :(得分:2)

快速但危险:使用eval代替JSON.parse

data = HTTParty.get("http://www.google.com/ig/calculator?hl=en&q=1USD=?COP").body
=> "{lhs: \"1 U.S. dollar\",rhs: \"1\xA0901.14068 Colombian pesos\",error: \"\",icc: true}"
eval(data)
=> {:lhs=>"1 U.S. dollar", :rhs=>"1\xA0901.14068 Colombian pesos", :error=>"", :icc=>true}

要获得更安全的解决方案,我们应该手动解析响应,或者学习如何从谷歌获取有效的JSON。

如您所见,您的响应正文不是有效的JSON。密钥未包含在"

以下是有关同一问题的Python相关讨论:How to Read a Simple Json Result (from Google calculator) in Python?

简而言之,解决方案要么手动解析回复,要么使用http://rate-exchange.appspot.com代替Google。

答案 1 :(得分:2)

我一直在四处寻找,我认为问题出在谷歌的最后。

接收的数据是Ruby中的哈希值,或JavaScript中的对象,根据规范,keys should be quoted because they're strings。对象包含在{}中,格式为"string": value。字符串用双引号括起来:"string"

通过预处理接收的数据以将键名转换为带引号的键名,可以解析JSON:

require 'open-uri'
require 'json'

FIELDS = %w[lhs rhs error icc]

%w[COP USD AED YER ZAR ZMK].each do |currency|
  data = open('http://www.google.com/ig/calculator?hl=en&q=1USD=?' + currency).read
  FIELDS.each { |f| data.sub!(f, %Q["#{f}"]) }
  puts JSON[data]
end

运行后,这些是通过解析JSON创建的哈希:

{"lhs"=>"1 U.S. dollar", "rhs"=>"1 890.35917 Colombian pesos", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"1 U.S. dollar", "error"=>"0", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"3.67290571 United Arab Emirates dirhams", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"215.053763 Yemeni rials", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"9.97575891 South African rands", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"5 208.33333 Zambia kwacha", "error"=>"", "icc"=>true}

但等等,还有更多......

YAML是JSON的超集,因此YAML解析器应该能够理解JSON。将收到的“JSON”扔进YAML解析器会处理不带引号的键:

require 'open-uri'
require 'yaml'

%w[COP USD AED YER ZAR ZMK].each do |currency|
  data = open('http://www.google.com/ig/calculator?hl=en&q=1USD=?' + currency).read
  puts YAML.load(data)
end

使用此输出:

{"lhs"=>"1 U.S. dollar", "rhs"=>"1 890.35917 Colombian pesos", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"1 U.S. dollar", "error"=>"0", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"3.67290571 United Arab Emirates dirhams", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"215.053763 Yemeni rials", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"9.97575891 South African rands", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"5 208.33333 Zambia kwacha", "error"=>"", "icc"=>true}

YAML并不坚持引用哈希键。对于那些显然不是数字的东西,它默认为String,这是我尝试YAML的线索。

所以,在我看来,谷歌做错了。如果他们要输出JSON,他们应该输出正常的,语法正确的JSON。如果他们要输出YAML,他们应该输出常规的YAML,而不是输出数据的“半快”序列化。 API可能有某种方式强制它,但它应该默认为解析的JSON。

您可能希望改为使用https://openexchangerates.org/。他们的示例输出似乎是一种更加理智的方法。