PythonでWebスクレイピングをする際には、requestsとbeautifulsoup4モジュールを組み合わせて使うことが多いかと思います。
BeautifulSoupクラスをインスタンス化する際、requests.getで取得したResponseオブジェクト(r)をどのように引数に指定していますか?
本記事では、その選択肢について私の考えを書きたいと思います。
r.textとr.contentの違い
requestsとbeautifulsoup4モジュールを組み合わせてBeautifulSoupクラスをインスタンス化する際の基本的なコードは以下のとおりです。
from bs4 import BeautifulSoup
import requests
r = requests.get('https://webscraper.blog/')
r.raise_for_status()
soup = BeautifulSoup(r.text, 'lxml')
# または
# soup = BeautifulSoup(r.content, 'lxml')そもそもr.textとr.contentの違いは何でしょうか?
r.textはHTMLを人間が理解できるようにデコード(復元)したテキストであり、r.contentは元のバイナリデータです。
どちらをBeautifulSoupの第1引数に指定しても基本的には問題なく、HTMLを解析してWebスクレイピングを行うことができます。
体感ではWebサイトや書籍等ではr.textを指定している方が多いように思います。
個人的な見解はr.contentとすべき
前項で説明したようにr.textを指定している解説が多く、私もr.textを指定していました。コーディング量も僅かながら短いし、どちらも同じように動作するしあまり深くは考えていませんでした。
ではなぜ、r.contentにすべきという見解になったのか。それはnetkeibaのスクレイピングを行った際の出来事です。
私はココナラをメインにスクレイピングの案件をいただくことがあるのですが、機械学習やAIの発展もあってかnetkeibaからのスクレイピング案件を多くいただきます。netkeibaを知らない方に説明するとJRA全レースの出馬表からオッズ、結果等さまざまなデータが公開されています。
実はこのnetkeiba、encodingがISO-8859-1となっており、r.textを指定するとBeautifulSoupでテキスト等を取得すると文字化けが発生します。
そのため、サイトのencodingを都度確認するのが面倒なので以下のようなコードを基本としていました。
from bs4 import BeautifulSoup
import requests
r = requests.get('https://webscraper.blog/')
r.raise_for_status()
r.encoding = r.apparent_encoding # 追加
soup = BeautifulSoup(r.text, 'lxml')Responseオブジェクトのencodingにapparent_encodingプロパティを指定することでHTMLからencodingを推定して設定してくれるみたいです。
とある日、いろいろ試していたところ、r.contentを指定するとなんとr.encoding = r.apparent_encodingの1文がいらないことが分かったのです。
この1文のコード量を減らせるのです。大きいですよね?
その分、textからcontentにすることで3文字分のコード量は増えてますが…
私がBeautifulSoupの第1引数はr.contentとすべきと思うのはencodingを考慮しなくてよい。これが理由です。
from bs4 import BeautifulSoup
import requests
r = requests.get('https://webscraper.blog/')
r.raise_for_status()
# この1文が不要となる。
# r.encoding = r.apparent_encoding
soup = BeautifulSoup(r.content, 'lxml')ではなぜr.textとしている解説が多いのか
なぜr.textとしている解説している書籍やWebサイトが多いかというのは正直なところ私には分かりません…
r.contentと指定することのデメリットがあるのでしょうか。どなたか分かる方はコメントいただければ幸いです。


コメント