Как преобразовать ответ Net :: HTTP в определенную кодировку в Ruby 1.9.1? - PullRequest
8 голосов
/ 30 июля 2009

У меня есть приложение Sinatra (http://analyzethis.espace -technologies.com ), которое выполняет следующие действия:

  1. Получить страницу HTML (через сеть / http)
  2. Создать документ Nokogiri из response.body
  3. Извлеките некоторую информацию и отправьте ее обратно в ответ. Ответ должен быть в кодировке UTF-8

Итак, я столкнулся с проблемой, пытаясь читать сайты, использующие кодировки windows-1256, такие как www.filfan.com или www.masrawy.com.

Проблема в том, что преобразование кодировки неверно, хотя ошибки не выдаются.

net / http response.body.encoding предоставляет ASCII-8BIT, который нельзя преобразовать в UTF-8

Если я выполняю Nokogiri :: HTML (response.body) и использую селекторы css для получения определенного содержимого со страницы - скажем, содержимого тега title, например - я получаю строку, которая при вызове string.encoding возвращает WINDOWS-1256. Я использую string.encode ("utf-8") и отправляю ответ, используя его, но опять-таки ответ не правильный.

Любые предложения или идеи о том, что не так в моем подходе?

Ответы [ 2 ]

21 голосов
/ 08 декабря 2012

Потому что Net :: HTTP неправильно обрабатывает кодировку. См. http://bugs.ruby -lang.org / Issues / 2567

Вы можете проанализировать response['content-type'], который содержит кодировку вместо анализа целого response.body.

Затем используйте force_encoding() для установки правильной кодировки.

response.body.force_encoding("UTF-8"), если сайт обслуживается в UTF-8.

3 голосов
/ 02 августа 2009

Я нашел следующий код, работающий для меня сейчас

def document
  if @document.nil? && response
    @document = if document_encoding
                  Nokogiri::HTML(response.body.force_encoding(document_encoding).encode('utf-8'),nil, 'utf-8')
                else
                  Nokogiri::HTML(response.body)
                end
  end
  @document
end

def document_encoding
  return @document_encoding if @document_encoding
  response.type_params.each_pair do |k,v|
    @document_encoding = v.upcase if k =~ /charset/i
  end
  unless @document_encoding
    #document.css("meta[http-equiv=Content-Type]").each do |n|
    #  attr = n.get_attribute("content")
    #  @document_encoding = attr.slice(/charset=[a-z1-9\-_]+/i).split("=")[1].upcase if attr
    #end
    @document_encoding = response.body =~ /<meta[^>]*HTTP-EQUIV=["']Content-Type["'][^>]*content=["'](.*)["']/i && $1 =~ /charset=(.+)/i && $1.upcase
  end
  @document_encoding
end 
...