如何使用 Nokogiri return 一个 JSON 对象

How to return a JSON object with Nokogiri

我需要得到一个 JSON 对象:

curl -X GET "https://graph.facebook.com/v2.6/<USER_ID>?fields=first_name,last_name,profile_pic,locale,timezone,gender&access_token=PAGE_ACCESS_TOKEN"    

在 Rails 中,我正在使用 Nokogiri:

# Get the data
data = Nokogiri::HTML(open(<URL>))

我得到的结果是:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p><JSON-OBJECT></p></body></html>

我只需要 return JSON 对象,所以我认为这可行:

Hash.from_xml(data.to_xml)['html']['body']['p'].remove('\')

没有。我如何才能像在终端中使用 cURL 一样只获取 JSON 对象?

我不确定您为什么要使用 Nokogiri 来解析 JSON 对象。 Nokogiri 用于解析 XML/HTML。 Facebook API 的默认响应类型已经是 JSON.

最好使用 httparty, faraday,或者使用纯 ol OpenURI 和 JSON.parse

在 cURL 上:

curl -i -H "Content-type: application/json" -H "Accept: application/json" -X GET \"https://graph.facebook.com/v2.8/me?fields=id%2Cname&access_token=<ACCESS_TOKEN>

通常,JSON 响应未编码或包含在 HTML 页面中,它作为包含整个正文的文本字符串返回:

require 'open-uri'

open('http://httpbin.org/headers').read
# => "{\n" +
#    "  \"headers\": {\n" +
#    "    \"Accept\": \"*/*\", \n" +
#    "    \"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\", \n" +
#    "    \"Host\": \"httpbin.org\", \n" +
#    "    \"User-Agent\": \"Ruby\"\n" +
#    "  }\n" +
#    "}\n"

将其解析回 Ruby 对象很容易:

require 'json'
require 'open-uri'

JSON[open('http://httpbin.org/headers').read]
# => {"headers"=>
#      {"Accept"=>"*/*",
#       "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
#       "Host"=>"httpbin.org",
#       "User-Agent"=>"Ruby"}}

JSON[...] 是一种简单、通用的解析 JSON 字符串或序列化 Ruby 对象的方法。它足够聪明,知道该怎么做:

require 'json'

foo = {'a' => 1}
foo.class # => Hash
bar = JSON[foo] # => "{\"a\":1}"
bar.class # => String
baz = JSON[bar] # => {"a"=>1}
baz.class # => Hash

如果您想更明确一点,可以使用 to_jsonparse 方法:

require 'json'

foo = {'a' => 1}
bar = foo.to_json # => "{\"a\":1}"
baz = JSON.parse(bar) # => {"a"=>1}

请注意,任何时候都不需要 Nokogiri。

如果,由于某些奇怪的原因,JSON 被注入到页面中,或者您可能想获取一些 JavaScript 数据,这是更有可能的是,你可以使用 Nokogiri:

require 'json'
require 'nokogiri'

html = <<EOT
<html>
  <head>
    <script>
      var foo = '{"a":1}';
    </script>
  </head>
</html>
EOT

doc = Nokogiri::HTML(html)
script_contents = doc.at('script').text # => "\n      var foo = '{\"a\":1}';\n    "
foo = JSON[script_contents[/({.+})/, 1]] # => {"a"=>1}
foo.class # => Hash