0

我正在使用 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 对象,JSON.parse(data)但它返回错误:

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>'

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

4

2 回答 2

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}

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

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

这是关于同一问题的与 Python 相关的讨论:如何在 Python 中读取简单的 Json 结果(来自 Google 计算器)?

简而言之,解决方案要么手动解析响应,要么使用http://rate-exchange.appspot.com而不是 Google。

于 2013-06-06T23:57:55.213 回答
2

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

接收到的数据是 Ruby 中的哈希,或 JavaScript 中的对象,并且根据规范,键应该被引用,因为它们是字符串。一个对象被包装在{and}中,"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 不坚持引用哈希键。对于那些不是明显数字的东西,它默认为字符串,这是我尝试 YAML 的线索。

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

您可能想考虑改用https://openexchangerates.org/。他们的示例输出似乎是一种更理智的方法。

于 2013-06-08T22:10:20.787 回答