OpenURIで取得したデータをDBに入れる際のエラー / invalid byte sequence for encoding “UTF8”

Shunsuke Sawada

Nokogiriでスクレイピングは楽しいんですが、.xpathや.cssメソッドに渡す引数を割り出すのに、けっこう時間がかかったりする。その度にirbで接続するのもなんなのでDBに保存しとくことにした。

パースの練習がしたいだけなので、パースした後のデータを保存するのではなくて、パース前のナマのデータを保存したい。
ところがDBに保存するときにエラーがでましたよと。
 

ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TestContentController < ApplicationController

    require 'open-uri'

    def create
        url = "http://www.yourwebsite_here.com"
        html = open(url).read
        TestContent.create( content: html )
    end

end

# => TestContent.createメソッドでエラー
# invalid byte sequence for encoding “UTF8”

UTF8では扱えないinvalidな文字があるよということなんだろうけど、どう変換していいのか悩んだ。

ちなみにvalidかinvalidかはStringクラスのvalid_encoding?で調べられる。

html = open(url).read で取得した時のエンコードは"ASCII-8BIT"だった。

1
2
html.encoding.name
=> "ASCII-8BIT"

 
いろいろやってみたけど、一度SJISに変換してからUTF-8に変換するという回りくどいやり方でとりあえずは保存できました。
 

ruby
1
2
3
4
5
6
7
html = html.encode( 'SJIS', invalid: :replace, undef: :replace, replace: '' )
html = html.encode( 'UTF-8', invalid: :replace, undef: :replace, replace: '' )

html.valid_encoding?
# => true

 
扱えない文字を''で置き換えているので、元のデータとは若干違うところもあるかもしれませんが、パースの練習用にはとりあえずこれで十分。

 

ruby
1
2
3
4
5
6
7
8
require 'nokogiri'

test_content = TestContent.first.content
parsed = Nokogiri::HTML(test_content)

parsed.css("#my_main_content > .left_column > ul li:first-child").text
# => 目的のテキスト

 
時間を短縮するための試みだったのに、逆に時間がかかってしまった。

悔しいので「Nokogiriテスター」なるものを作ったらもの凄く便利だ…。
暇ができたらherokuにデプロイしてもいいかもしれない。

6
Shunsuke Sawada

おすすめの記事

acts-as-taggable-on タグを表示させる順番を決めたい
Railsを4.2にバージョンアップしたら、Vagrantのローカル開発環境にアクセスできなくなった問題
Railsのバリデーションエラー後にレイアウトが崩れるとき