2011-07-02 85 views
2

我正在使用Nokogiri打开关于各个国家/地区的维基百科页面,然后从interwiki链接(外国语言wikipedias链接)中提取其他语言的这些国家/地区的名称。但是,当我尝试打开the page for France时,Nokogiri不会下载整个页面。可能它太大了,无论如何它不包含我需要的跨wiki链接。我如何强制它下载所有?为什么Nokogiri不加载整个页面?

这里是我的代码:

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

测试:

with country_name = "France" 
=> [] 

with country_name = "Thailand" 
=> really long array that I don't want to quote here, 
    but containing all the right data 

也许这个问题超出了引入nokogiri进入OpenURI - 反正我需要找到一个解决方案。

+0

您是否知道open()不是Nokogiri? –

回答

9

引入nokogiri不检索页面,它会询问OpenURI与内部read做StringIO对象是开放:URI的回报上。

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", '') 

见卡斯帕的回答和评论。最初,它看起来像Open-URI在处理返回的数据时不一致,但基于Casper的说法和我使用curl看到的内容,Wikipedia不遵守大文档的“Accept-Encoding”头并返回gzip。这对于今天的浏览器来说是相当安全的,但像Open-URI这样的不能自动感知编码的客户端会遇到问题。这就是上面的代码应该帮助解决的问题。

+0

谢谢。我实现了这一点,现在我正在获取数据。唯一的问题是,Unicode国名不再正确显示,例如, G。作为法国的印地语名字,我得到了αñ½αñααÑìαñ░αñ╛αñ¿αÑìαñ。这只是gzip编码名称的一个问题,其他的都是自动修正的。任何想法? – Sprachprofi

+0

没关系,我想明白了:只是做page = Nokogiri :: HTML(body,nil,'UTF-8')来代替。 – Sprachprofi

+0

而不是假定它是“UTF-8”,你可能想使用响应的'external_encoding'方法。假设UTF-8与一个站点一致是相当安全的,但如果您正在查看多个站点,您可能会得到不兼容的编码。只是需要考虑。 –

0

颇有几分挠头的问题后,就在这里:

> 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! 
    ... 

你需要解压gzip压缩的数据,其开放式的URI不会自动做。
解决方案:

def http_get(uri) 
    url = URI.parse uri 

    res = Net::HTTP.start(url.host, url.port) { |h| 
    h.get(url.path) 
    } 

    headers = res.to_hash 
    gzipped = headers['content-encoding'] && headers['content-encoding'][0] == "gzip" 
    content = gzipped ? Zlib::GzipReader.new(StringIO.new(res.body)).read : res.body 

    content 
end 

然后:

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

实际上,Open :: URI确实可以解码gzip,但是对于一定大小的页面似乎是这样做的。所有来自Wikipedia的结果都是gzipped,但法国的页面没有解码。来自泰国的较小的页面被解码。 –

+0

呃..不在我的机器上。泰国在我提出要求时没有被压缩。这似乎取决于你的位置,或者你碰巧碰到了哪一个维基百科服务器。随着wget -S泰国不为我压缩。另外看着open-uri的代码,我找不到打开打包页面的位置......你确定它是这么做的吗? – Casper

+0

看到我上面的答案。 –

0
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 
相关问题