Почему Nokogiri не загружает полную страницу? - PullRequest
2 голосов
/ 02 июля 2011

Я использую Nokogiri для открытия страниц Википедии о различных странах, а затем извлекаю названия этих стран на других языках из ссылок вики (ссылки на википедии на иностранных языках). Однако, когда я пытаюсь открыть страницу для Франции , 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

Может быть, эта проблема выходит за рамки Нокогири и входит в OpenURI - в любом случае мне нужно найти решение.

Ответы [ 3 ]

9 голосов
/ 03 июля 2011

Nokogiri не извлекает страницу, он просит OpenURI сделать это с внутренним read объектом StringIO, который возвращает Open :: 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 #=> []

В этом случае, если это [], AKA "text / html", он читает.Если он ["gzip"], он декодируется.

Выполнение всего вышеперечисленного и добавление:

require 'nokogiri'
page = Nokogiri::HTML(body)
language_part = page.css('div#p-lang')

должно вернуть вас в нужное русло.

Сделайте это после всего вышеперечисленного, чтобы визуально подтвердить, что вы получаете что-то полезное:

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

См. Ответ Каспера и комментарии о том, почему вы увидели два разных результата.Первоначально казалось, что Open-URI был непоследователен в обработке возвращаемых данных, но, основываясь на том, что сказал Каспер, и на том, что я видел с помощью curl, Wikipedia не учитывает заголовок «Accept-Encoding» для больших документов и возвращает gzip.Это довольно безопасно в современных браузерах, но такие клиенты, как Open-URI, которые автоматически не чувствуют кодирование, будут иметь проблемы.Вот что приведенный выше код должен помочь исправить.

0 голосов
/ 08 июля 2013
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
0 голосов
/ 03 июля 2011

После небольшого количества царапин на голове проблема здесь:

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

Вам нужно распаковать сжатые данные, что 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"))
...