【问题标题】:How do I get JSON from Google currency calculator?如何从 Google 货币计算器获取 JSON?
【发布时间】:2013-06-06 23:24:17
【问题描述】:

我正在使用 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>'

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

【问题讨论】:

  • Sinatra 为何或如何参与其中?

标签: ruby json api calculator currency


【解决方案1】:

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

接收到的数据是 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 的线索。

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

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

【讨论】:

    【解决方案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 相关的讨论:How to Read a Simple Json Result (from Google calculator) in Python?

    简单来说,解决方案要么手动解析响应,要么使用http://rate-exchange.appspot.com而不是谷歌。

    【讨论】:

      猜你喜欢
      • 2014-12-07
      • 2012-05-15
      • 1970-01-01
      • 2012-02-01
      • 2019-03-09
      • 2018-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多