素人がPythonでWebスクレイピングを実装する5

よこのじ(@yokonoji_work)です。

素人がPythonでWebスクレイピングを実装する」の第5回です。今回からPythonでコードを書いていきます。

このスクレイピングプログラムは「ローレライ(Loreley)」と名付けることにしています。

ローレライとはドイツのライン川にある岩山のことで、この岩山周辺では舟が川に飲まれる魔女伝説があります。美しい少女の歌に舟人が心を奪われて舟が沈むという伝説です。

スクレイピングプログラムをローレライに見立てると、あらゆるデータをWebから自分の場所へと収集することが、ローレライが美しい歌で魅了して舟を川に引きずり込むことと重なりましたので、思いつきで名前を付けてみようと思いました(大層な名前なので名前負けしないように作り込んでいきたい)。

実装開始

第3回記事で決定したように、ライブラリはRequestsとBeautiful Soup 4を使用します。Requestsでは日本語の場合に文字化けが発生する可能性があるということで、これを回避する方法をみていきます。

文字化けする仕組み

Webページの文字コード特定

Webページで文字コードを特定する方法は3つあります。

  1. HTTPレスポンスのContent-Typeヘッダーのcharset(特定精度があまり良くない)
  2. <meta>タグ 例:<meta charset=”utf-8″>(特定精度が良い)
  3. HTTPレスポンスのバイト列から推定(特定精度が良い)

Requestsでのエンコーディング

Requestsによる応答内容にはr.textとr.contentがあり、この2つには違いがあります。

  • r.textは、Requestsによって推測されたエンコーディング(r.encoding)によりデコードされている
  • r.contentは、bytes型としてレスポンスボディにアクセスする(デコードされていない)

Requestsは、HTTPページにアクセスするだけのライブラリなので<meta>タグの確認は行えず、HTTPレスポンスより文字コードを特定してエンコードします。1のContent-Typeヘッダーのcharsetより文字コードを特定する際、textタイプが含まれていてcharsetがない場合、r.encodingはISO-8859-1になります。

これが日本語の場合に文字化けする原因となっているようです。

Beautiful Soup 4でのエンコーディング

Requestの動作による文字化けを防ぐためには、Requestsによるエンコーディングが行われたr.textではなく、r.contentを使用する必要があります。

Beautiful Soupの関数BeautifulSoup()には、str型のr.textだけではなく、bytes型のr.contentを指定することもできます。デコードされたstr型の場合にはBeautiful Soupは何もしませんが、bytes型の場合にはBeautiful Soupがデコードを行います。

Beautiful Soupによるデコードは、次の3つの方法で順にデコードを試して適切な文字コードでデコードされますので、Requestsより精度の高いデコードが行われるというわけです。

  1. from_encodingで指定したエンコーディング
  2. <meta>タグのエンコーディング(上記2に該当)
  3. 推定されたエンコーディング(上記3に該当)

ここまでのコーディング

python-scraping-5-coding

ここまでの内容を取り込んだコードになります。

RequestsのドキュメントにならってGitHUBのpublic timelineにアクセスして、200の応答(リクエスト成功)を確認しました。

soup = BeautifulSoup(r.content, ‘lxml’)では、パーサーとして高速なlxmlを指定しています。

ちなみに、見てのとおりJupyterでコーディングしています。

 

Python3に対応したスクレイピングの本

素人がPythonでWebスクレイピングを実装する1
素人がPythonでWebスクレイピングを実装する2
素人がPythonでWebスクレイピングを実装する3
素人がPythonでWebスクレイピングを実装する4
素人がPythonでWebスクレイピングを実装する6
素人がPythonでWebスクレイピングを実装する7
素人がPythonでWebスクレイピングを実装する8