読者です 読者をやめる 読者になる 読者になる

ログってなんぼ

日々のメモです

MechanizeでISO-8859-1のページタイトルが文字化けしてしまう対応

どうも。脱PHPerを目指しGoとRubyの本読みながらコード書き書き中のokisanjpです。

URLからページタイトルをMechanizeで取得してDBに保存する実装をしていてややこしかったんでメモします。未来の自分宛にw

require 'mechanize'

def entry_params
  # ページタイトルを取得してパラメータに含める
  agent = Mechanize.new
  data = agent.get(params[:entry][:url])
  params[:entry][:title] = data.title
  params.require(:entry).permit(:user_id, :url, :title, :comment, :category)
end

formからurlをもらってtitleフィールドの値はMechanizeで作ってDBに保存する実装の一部分。

invalid byte sequence in UTF-8

UTF−8の文字列でも、不正なバイト列を含むタイトルがあるとRubyが「invalid byte sequence in UTF-8」を吐いてしまう状況に遭遇・・・

これについては

Ruby の invalid byte sequence in UTF-8 例外を encode("UTF-8", "UTF-8") で回避するのはおかしいよ、という話 - sonots:blog はてなブックマーク - Ruby の invalid byte sequence in UTF-8 例外を encode(

Ruby の invalid byte sequence in UTF-8 例外を encode("UTF-8", "UTF-8") で回避するのはおかしいよ、という話をします。 引用元:Ruby の invalid byte sequence in UTF-8 例外を encode("UTF-8", "UTF-8") で回避するのはおかしいよ、という話 - sonots:blog


こちらのエントリが非常に参考になりました。

ISO-8859-1ページの日本語が文字化けする

タイトルを取得してRailsアプリにUTF−8で保存する処理についてはShift_JISもEUC−JPも基本的にMechanize任せで大丈夫だったんですが、たまにcharsetがなぜかISO-8859-1になってるページがあって、どうしても文字化けしてしまう・・・

.rvm/gems/ruby-2.2.1/gems/mechanize-2.7.3/lib/mechanize/agent.rb

上記ソースの一部

  def request_language_charset request
    request['accept-charset']  = 'ISO-8859-1,utf-8;q=0.7,*;q=0.7'
    request['accept-language'] = 'en-us,en;q=0.5'
  end

.rvm/gems/ruby-2.2.1/gems/mechanize-2.7.3/lib/mechanize/util.rb

上記ソースの一部

  def self.detect_charset(src)
    case enc = src && NKF.guess(src)
    when Integer
      # Ruby <= 1.8
      CODE_DIC[enc]
    else
      # Ruby >= 1.9
      enc && enc.to_s.upcase
    end || "ISO-8859-1"
  end

ISO-8859-1を検出したらUTF−8を明示する必要がありそう・・

ということで対応

require 'mechanize'

def entry_params # ページタイトルを取得してパラメータに含める agent = Mechanize.new data = agent.get(params[:entry][:url]) # ISO-8859-1 Mechanizeの推測優先順位対策 if agent.page.parser.encoding == "ISO-8859-1"   agent.page.encoding = 'UTF-8' end # UTF−8中の不正なバイト列を?に変換 params[:entry][:title] = data.title.scrub('?') params.require(:entry).permit(:user_id, :url, :title, :comment, :category) end

とりあえずちゃんと動いてはいる・・・不安だ・・・

こんな対応で本当に正しいんだろうか・・・PHPerの私がRailsをちゃんとさわり始めて今日で3日目ですが、まだまだ苦難が待ち構えていそうです(笑)

でもこれよく考えたら、フォームのHTMLにAjaxでタイトル取得する実装したほうがいいような気がしてきてるんだよなあ・・・Rails本読みながら勉強していますがAjaxの項目までまだ進んでないんで先に読んで演習してみようかな