Help us understand the problem. What is going on with this article?

たのしいRuby5版22章で躓いたこと【エンコード関係】

Rubyの知識を復習するため、『たのしいRuby第5版』という書籍を読んでいます。
今回は、その22章の「テキスト処理を行う」というところで詰まった箇所とその解決方法を書いていこうと思います。

環境

OS:windows10

詰まったところ

まず、青空文庫から江戸川乱歩『二銭銅貨』をダウンロードします。

nisendouka.rb
#ダウンロードするライブラリ
require "open-uri"

# 青空文庫のURL
url = "https://www.aozora.gr.jp/cards/001779/files/56647_58167.html"
# 書きこむファイル名
filename = "nisendouka.html"

# バイナリモードでファイルを開きます
File.open(filename, "wb") do |f|
    text = open(url).read #ここがよくない
# nisendouka.htmlに書き込む
    f.write text
end

このコードを実行すると、nisendouka.htmlという名前のHTMLファイルが作成され(すでに存在する場合は上書きされます)指定したURLのhtmlファイルが書き込まれます。

問題は次のコード

cut_nisen.rb
htmlfile = "nisendouka.html"
textfile = "nisendouka.txt"

html = File.read(htmlfile, encoding: "UTF-8")

open(textfile, "w:UTF-8") do |f|
    in_header = true
    html.each_line do |line|
        if in_header && /<div class="main_text">/ !~ line
            next
        else
            in_header = false
        end
        break if /<div class="bibliographical_information">/ =~ line
        f.write line
    end
end

処理の内容としては、 <div class="main_text" と <div class="bibliographical_information" で囲まれた部分(本文)を取り出すという処理ですが、これを実行するとエラーが出ました。

# エラー内容
cut_nisen.rb:9:in `=~': invalid byte sequence in UTF-8 (ArgumentError)

初めてみるエラーだったので調べてみました。

エラー原因

調べてみると、どうもUTF-8以外の文字コードで読み込んでいる(?)ことが原因で起こるエラーのようでした。(参考

確かに元の青空文庫の文字コードはSHIFT-JISとなっていたので、それをUTF-8で読み込もうとしたことがよくなかったようです。

そこで青空文庫から読み込む際の文字コードをSHIFT-JIS、HTMLファイルに書き込む際の文字コードをUTF-8と明示することでエラーが解消されました。

nisendouka.rb
# 変更後のコード

#ダウンロードするライブラリ
require "open-uri"

url = "https://www.aozora.gr.jp/cards/001779/files/56647_58167.html"
filename = "nisendouka.html"

File.open(filename, "wb") do |f|
    text = open(url, "r:shift_jis").read #文字コードをshift-jisに指定
    f.write text.encode("utf-8") # 文字コードをutf-8に変更
end

まとめ

スクレイピングなどをするときは文字コードに気を付けることが重要だと思いました。

補足

Stringクラスのencodingメソッドを使うとその文字列の文字コードを確認することができます

sample.rb
str = "こんにちは" 
p str.encoding #=> #<Encoding:UTF-8>

また、Rubyのデフォルトの文字コードはUTF-8ですが、Encoding.default_internalを使うことでencodeメソッドによる文字コードを指定することができます。

手元の環境で実行したのですが、UTF-8のままになってしまいました…。
原因の分かる方、教えていただけると幸いです。

sample2.rb
Encoding.default_internal = "Shift_JIS"
s = "太郎"
puts s.encode

くわしくはこちらのRubyリファレンスをご覧ください。
あとこちらのブログもかなり参考になりそうです(2012年のものなので情報の正確性に注意!)

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away