Ruby 为什么';Nokogiri是否加载整个页面?

Ruby 为什么';Nokogiri是否加载整个页面?,ruby,nokogiri,open-uri,Ruby,Nokogiri,Open Uri,我正在使用Nokogiri打开关于不同国家的维基百科页面,然后从interwiki链接(指向外语维基百科的链接)中提取这些国家的其他语言名称。然而,当我试图打开时,Nokogiri并没有下载完整的页面。也许它太大了,反正它不包含我需要的interwiki链接。我怎样才能强制它下载所有内容 这是我的密码: url = "http://en.wikipedia.org/wiki/" + country_name page = nil begin page = Nokogiri::HTML(ope

我正在使用Nokogiri打开关于不同国家的维基百科页面,然后从interwiki链接(指向外语维基百科的链接)中提取这些国家的其他语言名称。然而,当我试图打开时,Nokogiri并没有下载完整的页面。也许它太大了,反正它不包含我需要的interwiki链接。我怎样才能强制它下载所有内容

这是我的密码:

url = "http://en.wikipedia.org/wiki/" + country_name
page = nil
begin
  page = Nokogiri::HTML(open(url))
rescue   OpenURI::HTTPError=>e
  puts "No article found for " + country_name
end

language_part = page.css('div#p-lang')
测试:


也许这个问题超越了Nokogiri,进入了OpenURI——无论如何,我需要找到一个解决方案。

经过一番深思熟虑,问题就在这里:

> wget -S 'http://en.wikipedia.org/wiki/France'
Resolving en.wikipedia.org... 91.198.174.232
Connecting to en.wikipedia.org|91.198.174.232|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.0 200 OK
  Content-Language: en
  Last-Modified: Fri, 01 Jul 2011 23:31:36 GMT
  Content-Encoding: gzip <<<<------ BINGO!
  ...
然后:

page = Nokogiri::HTML(http_get("http://en.wikipedia.org/wiki/France"))

Nokogiri不检索页面,它要求OpenURI使用Open::URI返回的StringIO对象上的内部
读取

require 'open-uri'
require 'zlib'

stream = open('http://en.wikipedia.org/wiki/France')
if (stream.content_encoding.empty?)
  body = stream.read
else
  body = Zlib::GzipReader.new(stream).read
end

p body
以下是您可以键入的内容:

>> require 'open-uri' #=> true
>> open('http://en.wikipedia.org/wiki/France').content_encoding #=> ["gzip"]
>> open('http://en.wikipedia.org/wiki/Thailand').content_encoding #=> []
在本例中,如果它是
[]
,又称为“text/html”,它将读取。如果是
[“gzip”]
它会解码

完成上述所有工作并将其抛给:

require 'nokogiri'
page = Nokogiri::HTML(body)
language_part = page.css('div#p-lang')
应该会让你回到正轨

在完成上述所有操作后执行此操作,以从视觉上确认您正在获得可用的东西:

p language_part.text.gsub("\t", '')

请参阅Casper的回答和评论,了解您为什么看到两个不同的结果。起初,OpenURI在处理返回的数据时看起来不一致,但根据Casper所说的,以及我在使用curl时所看到的,Wikipedia不支持大型文档的“接受编码”头并返回gzip。这在今天的浏览器中是相当安全的,但是像openuri这样不能自动感知编码的客户端会有问题。这就是上面的代码应该帮助解决的问题。

您知道open()不是Nokogiri吗?事实上,open::URI确实对gzip进行解码,但对于某些大小以下的页面似乎是这样的。维基百科的所有结果都被压缩了,但是法国的页面没有被解码。泰国的那一页,比较小,是解码的。嗯……不是在我的机器上。当我提出要求时,泰国不是gzipped。这似乎取决于您的位置,或者您碰巧访问了哪个维基百科服务器。有了wget-S,泰国就不适合我了。同时查看OpenURI的代码,我找不到一个可以解压打包页面的位置……你确定它会这样做吗?@tinman,你错了。问题是,当页面太大时,wikipedia似乎会压缩页面,即使请求中不存在接受编码头。这里有一个2.7k的小页面,你可以用它来测试。OpenURI未正确解码:open(“”,“接受编码”=>“gzip”)。请阅读。我可能对Wikipedia的看法是错误的,但这是一种误导。问题是要正确地解码开放URI结果,这是OPs关心的问题。是的,好的..当然..只是不要认为开放URI能够解码gzip。事实并非如此。即使是一个10字节的页面,它也不会解码。您的示例工作的原因是openuri默认情况下不发送接受编码头,因此大多数web服务器只返回text/html。一旦页面变得太大,一些服务器似乎无论如何都会压缩页面,忽略缺少的Accept编码。这就是OpenURI失败的原因。无论如何,你的解决方案是有效的,但不是因为你想的原因。谢谢。我实现了这个,现在我得到了数据。唯一的问题是Unicode国家名称不再正确显示,例如。G我有点晕眩了╝αÑìαñ░αñ╛αñ?αìαñ作为法国的印地语名称。这只是gzip编码名称的问题,其他名称自动正确。有什么想法吗?没关系,我想出来了:只需执行page=Nokogiri::HTML(body,nil,'UTF-8')。与其假设它是“UTF-8”,不如使用响应的
external\u编码方法。假设UTF-8与一个站点保持一致是非常安全的,但如果您查看多个站点,可能会得到不兼容的编码。只是要考虑一下。所有的冰雹冰激凌!D
require 'open-uri'
require 'zlib'

open('Accept-Encoding' => 'gzip, deflate') do |response|
  if response.content_encoding.include?('gzip')
    response = Zlib::GzipReader.new(response)
    response.define_singleton_method(:method_missing) do |name|
      to_io.public_send(name)
    end
  end

  yield response if block_given?

  response
end
p language_part.text.gsub("\t", '')
require 'open-uri'
require 'zlib'

open('Accept-Encoding' => 'gzip, deflate') do |response|
  if response.content_encoding.include?('gzip')
    response = Zlib::GzipReader.new(response)
    response.define_singleton_method(:method_missing) do |name|
      to_io.public_send(name)
    end
  end

  yield response if block_given?

  response
end