hitode909の日記

趣味はマリンスポーツですの日記です

Nokogiriが文字化けするのの対策

そこらへんで拾ってきたHTMLをNokogiriに渡すと,文字化けすることがあって,困ってた.
Nokogiriに文字コードを渡せるので,HTMLから正規表現でcharsetを取り出して,一番多く出現するcharsetをそのページのcharsetとして採用すると,うまくいった.
ヒューリスティックにやってるだけだけど,だいたいうまくいく.


こんな感じ.

  charset = io.scan(/charset="?([^\s"]*)/i).flatten.inject(Hash.new{0}){|a, b|
    a[b]+=1
    a
  }.to_a.sort_by{|a|
    a[1]
  }.reverse.first[0]

before
"〓\u0082«〓\u0083¼〓\u0083\u0089〓\u0083\u0095〓\u0082〓〓\u0082〓〓\u0083\u0088!! 〓\u0083´〓\u0082〓〓\u0083³〓\u0082¬〓\u0083¼〓\u0083\u0089〓\u0080\u0080〓¬¬6〓〓±〓\u0080\u008C〓¬\u008E〓\u0081〓〓\u0082«〓\u0083¼〓\u0083\u0089〓\u0082·〓\u0083§〓\u0083\u0083〓\u0083\u0097〓\u0080\u008D 〓\u0080\u0090 〓\u0083\u008B〓\u0082³〓\u0083\u008B〓\u0082³〓\u008B\u0095〓\u0094»(〓\u008E\u009F〓〓〓)"
after
"カードファイト!! ヴァンガード 第6話「謎のカードショップ」 ‐ ニコニコ動画(原宿)"


https://gist.github.com/827022

# -*- coding: utf-8 -*-
require 'open-uri'
require 'nokogiri'

def before(url)
  io = URI.parse(url).read
  Nokogiri(io)
end

def after(url)
  io = URI.parse(url).read
  charset = io.scan(/charset="?([^\s"]*)/i).flatten.inject(Hash.new{0}){|a, b|
    a[b]+=1
    a
  }.to_a.sort_by{|a|
    a[1]
  }.reverse.first[0]
  Nokogiri(io, url, charset)
end

puts 'before'
p before('http://www.nicovideo.jp/watch/1297306177').at('title').content

puts 'after'
p after('http://www.nicovideo.jp/watch/1297306177').at('title').content

追記

この方法だとはてなグループEUC-JPだと思われてしまう.文字コードのちがう,よそのウェブサービスJavaScriptを読みこんでると,こうなる.困った.

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="/diary_css/base.css" type="text/css" media="all" charset="euc-jp">
<link rel="stylesheet" href="/theme/hatena/hatena.css" type="text/css" media="all" charset="euc-jp">
<script type="text/javascript" src="http://d.hatena.ne.jp/js/quick_pager.js" charset="euc-jp"></script>

追記

require "open-uri" ; open(url).charset はどうでしょう http://rurema.clear-code.com/1.9.2/library/open=2duri.html

はてなブックマーク - sonota88のブックマーク - 2011年2月16日

open-uriのcharsetは,だいたい合っていて,よい感じだけど,ニコニコ動画がiso-8859-1になったりしてしまう.
ので,open-uriのcharsetがiso-8859-1じゃないときはcharsetを適当に探して使う,ということにした.
id:sonota88さんありがとうございます.

def after(url)
  io = URI.parse(url).read
  charset = io.charset
  if charset == "iso-8859-1"
    charset = io.scan(/charset="?([^\s"]*)/i).flatten.inject(Hash.new{0}){|a, b|
      a[b]+=1
      a
    }.to_a.sort_by{|a|
      a[1]
    }.reverse.first[0]
  end
  Nokogiri(io, url, charset)
end

before
# "〓\u0082«〓\u0083¼〓\u0083\u0089〓\u0083\u0095〓\u0082〓〓\u0082〓〓\u0083\u0088!! 〓\u0083´〓\u0082〓〓\u0083³〓\u0082¬〓\u0083¼〓\u0083\u0089〓\u0080\u0080〓¬¬6〓〓±〓\u0080\u008C〓¬\u008E〓\u0081〓〓\u0082«〓\u0083¼〓\u0083\u0089〓\u0082·〓\u0083§〓\u0083\u0083〓\u0083\u0097〓\u0080\u008D 〓\u0080\u0090 〓\u0083\u008B〓\u0082³〓\u0083\u008B〓\u0082³〓\u008B\u0095〓\u0094»(〓\u008E\u009F〓〓〓)"
after
"カードファイト!! ヴァンガード 第6話「謎のカードショップ」 ‐ ニコニコ動画(原宿)"
before
"復讐 - eigokunの手記 - - -"
after
"復讐 - eigokunの手記 - - -"