我正在使用Nokogiri打开关于各个国家/地区的维基百科页面,然后从interwiki链接(链接到外语wikipedias)中提取其他语言的这些国家/地区的名称。但是,当我尝试打开the page for France时,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')
测试:
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 :(得分:9)
Nokogiri没有检索页面,它要求OpenURI使用Open :: URI返回的StringIO对象上的内部read
来执行此操作。
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 #=> []
在这种情况下,如果它是[]
,AKA“text / html”,它会读取。如果它是["gzip"]
则解码。
完成上述所有操作并将其扔到:
require 'nokogiri'
page = Nokogiri::HTML(body)
language_part = page.css('div#p-lang')
应该让你回到正轨。
在完成上述所有操作之后,请在视觉上确认您正在获得可用的内容:
p language_part.text.gsub("\t", '')
参见Casper的回答和评论为什么你看到两个不同的结果。最初看起来Open-URI在处理返回数据方面不一致,但根据Casper的说法,以及我使用curl看到的内容,维基百科并没有尊重大型文档的“Accept-Encoding”标头并返回gzip。对于今天的浏览器来说这是相当安全的,但是像Open-URI这样不会自动检测编码的客户端会遇到问题。这就是上面的代码应该有助于解决的问题。
答案 1 :(得分: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压缩数据,open-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"))
答案 2 :(得分: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