Python上のBeautiful Soup使用方法|HTMLから必要なデータを抽出しよう

PythonにおいてBeautiful Soupを使用すれば、スクレイピング(抽出)をプログラミング化できます。そのため、人の目で確認し必要データを取得する方法に比べ、はるかに高速でデータ処理・収集を行うこと可能です。競合他社の商品データ収集業務を自動化など、必要な情報のみをスクレイピングする需要は日に日に増しています。

Python初心者の方にも分かりやすく解説いたします。ぜひデータ収集・分析などにご活用ください。

スクレイピングの概要

そもそも英単語スクレイピング(scraping)の意味は「削る」です。それが「データを削り出す」の意味合いを持つようになりました。現在ではIT用語として「Webサイトから必要な情報を抽出・取得・収集する」の意味で使われるようになりました。

Webサイトは基本的にHTMLと呼ばれるプログラミング言語で構成されています。そのため、HTML構造内の必要とするテキストや画像を指定すれば、指定した物だけをスクレイピング(削り出す)ことができます。

スクレイピングを行う際の注意点

必要な情報のスクレイピングは非常に便利である反面、注意すべきポイントがあります。実行する前に以下の3点について、理解しておかなければなりません。

Webサイトでスクレイピングが禁止されていないか

スクレイピングを行う際にもっとも注意しなければならない点は「利用規約でスクレイピングを禁止されていないか」です。利用規約は一般的にWebサイトのフッター部分にリンク設置されています。規約に違反した場合は、措置を受ける可能性もあるため必ず確認してから実行してください。

以下にスクレイピングの禁止されている代表的なWebサイトを挙げました。

  • Twitter
  • Facebook
  • Instagram
  • Amazon
  • メルカリ
  • Yahoo!ファイナンス

ファイナンス系やSNS系では禁止されている可能性が高いため、とくに慎重に利用規約をご確認ください。

スクレイピングによるサーバーの負荷

スクレイピングを実行するには、情報元であるWebサイトに訪れて必要データを取得しなければなりません。Python上でBeautiful Soupを使用することにより、スクレイピングをプログラミング化し、高速でデータ処理・収集を行うことができます。しかし、高速でWebサイトにアクセスをかけると、相手のレスポンスも自動的に高速化させてしまいます。そのため、短時間に何度もスクレイピングを実行することは、相手のサーバーに負荷をかけることにつながる行為です。「情報元のサーバーに負荷がかかりすぎていないか」といった点にも気をつけながらスクレイピングを行うようにしましょう。

著作権侵害

スクレイピングにより、取得したオリジナルデータを譲渡する行為は「著作権侵害」に該当します。また、「データ解析」を目的としていないスクレイピングも、趣旨とは反しているため著作権法の違反行為です。

ただし、下記に当てはまる場合は、著作権侵害の例外として認められています。

  • 収集したデータの解析を目的としている
  • 取得したデータの記録や翻訳
  • 取得したデータに個人の思想や感情を付け加えた「著作物」

スクレイピングに必須ライブラリ

スクレイピングを行う際に、必要となる代表的なライブラリは「Requests」と「Beautiful Soup」です。JavaScriptが使用されている場合は「Selenium」がよく使われています。

今回は、Webサイト上のHTML「データ取得」を行うRequestsライブラリと「データ抽出」を行うBeautiful Soupについて詳しく解説します。

Beautiful Soupとは

Beautiful Soupとは、Python上で実装できるスクレイピング用ライブラリの1つです。

Python自体がもともとスクレイピングに適した開発言語であるため、Beautiful Soupを併用すればより簡単に作業を行うことができます。 Beautiful Soupを使えばWebサイト内のHTMLやXMLファイルから必要な情報だけを抽出できます。

Beautiful Soupの実装条件

2020年10月4日にBeautiful Soupの最新バージョン4.9.3がリリースされました。このバージョンに対応するPythonのバージョンは「Python 2.7」と「Python 3系」です。また、Beautiful Soupはクロスプラットフォーム形式のため、「Windows・macOS・Linux」など異なるOSにも対応しています。

PythonでBeautiful Soupを使用する手順

Python上でBeautiful Soupを使用し、目的とするデータを得るための手順を紹介します。

①RequestsでHTMLの取得

PythonでBeautiful Soupを使用するためには、準備として「Requests」ライブラリを取得する必要があります。同様にPythonでは「urllib」ライブラリでも、HTMLの情報取得を行うことができます。しかし、「urllib」は「Requests」に比べ長く難解なコードを書かなければなりません。そのため、HTMLに関する情報取得には「Requests」の使用をおすすめします。

Requestsライブラリとは

Requestsは、PythonでURLにアクセスする際に必要となるライブラリです。Requestsを使用すれば、HTTP通信(※)・HTML上のテキスト・画像の取得・APIのアクセスが可能となります。

※HTTP通信:相手のサーバーに情報をリクエスト(要求)し、それにレスポンス(返答)がくること通信の呼称

Requestsモジュールをインストール

Requestsライブラリのインストールを行います。

PythonでAnacondaを使っている場合は、すでにRequestsライブラリが含まれているため、下記のようにライブラリからインポートを行ってください。

import requests

Anacondaを使っていない場合でも、Requestsのインストールは簡単にできます。「コマンドプロンプト」を起動し、下記を入力するだけでRequestsのダウンロードがはじまり、インストールの完了までが実行されます。

pip install requests

Requestsライブラリを使用

Requestsライブラリを使用して、スクレイピングを実行するWebサイトのURLを指定します。

▼サンプルコード例

import requests 
response = requests.get(URLを代入する) 
print (response.text)

「変数r」にURLを格納すれば、さらに簡潔なコードになります。

▼サンプルコード例

import requests 
r = requests.get(URLを代入する) 
print (r.text)

これで指定したURLのHTMLを取得できました。Requestsライブラリの役目はここで終了です。

②Beautiful Soupを使用しHTMLの解析

Requestsライブラリを使用し、URLのHTMLを取得が完了しました。次のステップはBeautiful Soupモジュールです。取得したHTMLの解析に進みましょう。

Beautiful Soupモジュールをインストール

Beautiful Soupモジュールのインストールを行いましょう。

インストールする際は、Python3.4以降に標準装備されている「pip」を使用します。

pip install beautifulsoup4

さらに、インポートと初期化を実行します。

from bs4 import BeautifulSoup

また、PythonでAnacondaを使われている場合は、下記のコードでライブラリからインポートを行います。

conda install beautifulsoup4

以上で、今回使用するBeautiful Soupモジュールの準備が完了しました。

Beautiful Soupの基本的な使用方法

それでは、Beautiful Soupモジュールの基本であるHTMLの読み込みを実行します。

先述にもあるとおり、Requestsライブラリを使用してURLにアクセスし、HTMLを取得してください。その後、Beautiful Soupモジュールでデータの抽出を行います。

▼サンプルコード例

import requests 
from bs4 import BeautifulSoup   

response = requests.get(URLを代入する)   

soup = BeautifulSoup( r.text, 'html.parser' )

「変数soup」に対してBeautifulSoupを使えば、Requestsで読み込んできたHTMLをデータとして取得できるようになりました。第2引数に「, ‘html.parser’」を指定しましたが、これはパーサと呼ばれる読み取り方式で、標準使用されているため省略することもできます。

また、上記のコードを入力するとHTML情報すべてを読み込むことになります。

▼実行結果:HTMLコーディング例

html_doc = """ 
<html><head><title>桃太郎物語</title></head> 
<body> <p class="title"><b>桃太郎物語</b></p> <p class="story">きび団子をもら 
い、桃太郎と鬼退治の仲間となったのは<a href="http://sample.co/dog" 
class="company" id="link1">犬</a>, <a href="http://sample.co/monkey" 
class="company" id="link2">さる</a> そして、<a href="http://sample.co/pheasant" 
class="company" id="link3">キジです。</a> 向かうは鬼ヶ島。いざ出発です。 
</p> <p class="story">...</p> 
</body> </html>

これでは、情報元であるWebサイトをデベロッパーツール(検証結果)で解読する方法と大差はありません。そこで読みやすく、HTMLをインデントした形にしましょう。

print(soup.prettify())

上記を入力すると、きれいにインデントされます。

▼実行結果:HTMLコーディング例

html_doc = """ 
<html> 
<head>
  <title>
   桃太郎物語
  </title> 
</head> 
<body>
  <p class="title">
   <b>
    桃太郎物語
   </b>
  </p>
  <p class="story">
    きび団子をもらい、桃太郎と鬼退治の仲間となったのは
   <a href="http://sample.co/dog" class="company" id="link1">
    犬
   </a>
    、
   <a href="http://sample.co/monkey" class="company" id="link2">
    さる、
   </a>
   そして、
   <a href="http://sample.co/pheasant" class="company" id="link3">
   キジです。
   </a>
   向かうは鬼ヶ島。いざ出発です。
  </p>
  <p class="story">
    ...
  </p>
</body>
</html>
Beautiful Soupで読み込んだHTMLのタイプを確認

BeautifulSoupでRequestsから読み込んだHTMLを解析する際には、扱うデータタイプを調べておきましょう。「type関数」を使って確認します。

import requests 
response = requests.get(URLを代入する) 
print (r.text)   

type(r.text)

▼実行結果

str

BeautifulSoupを使った解析は、扱うデータタイプが「文字列」である必要があります。「str」は「文字列」を表すため、そのままBeautifulSoupに投入できます。

▼データタイプ代表例

str型文字列
int型整数
float型浮動小数点数
bool型真偽値

Beautiful Soupで取得データが文字化けした場合

日本語表記の複雑さゆえに、Requestsから読み込んだHTMLをBeautifulSoupに渡す際「文字化け」を起こす場合があります。

▼サンプルコード例

import requests 
from bs4 import BeautifulSoup   

response = requests.get(URLを代入する)   

soup = BeautifulSoup( r.text, 'html.parser' )

先述した上記のコードでは、文字化けしてしまうWebサイトに出会うことがあります。これは、 r.textでは「unicode文字列」を取得しているためです。そこで、r.contentで「bytes文字列」を取得し直しましょう。

▼サンプルコード例

import requests 
from bs4 import BeautifulSoup   

response = requests.get(URLを代入する)   

soup = BeautifulSoup( r.content, 'html.parser' )

この方法で、ほとんどの文字化けを解消できます。しかし、それでもまだ文字化けが起きている場合は、第3引数で文字コードを指定してください。

▼サンプルコード例

import requests 
from bs4 import BeautifulSoup   

response = requests.get(URLを代入する)   

soup = BeautifulSoup( r.content, 'html.parser' ,from_encoding='utf-8')

以上のいずれかの方法で文字化けを解消できるでしょう。

③必要とするデータを取得する

Beautiful Soupで必要とするデータ要素のみを抽出しましょう。

必要とするデータのソースコードを確認する

Requestsモジュールの実行結果、またはGoogleデベロッパーツール(検証)を使って必要なデータのタグを確認しておきましょう。

先述のHTMLコーディング例を使って、ソースコードのタグを指定します。

▼HTMLコーディング例

html_doc = """ 
<html> 
<head> 
 <title> 
  桃太郎物語 
 </title> 
</head> 
<body> 
 <p class="title"> 
  <b> 
   桃太郎物語 
  </b> 
 </p> 
  <p class="story"> 
   きび団子をもらい、桃太郎と鬼退治の仲間となったのは 
  <a href="http://sample.co/dog" class="company" id="link1"> 
   犬 
  </a> 
   、 
  <a href="http://sample.co/monkey" class="company" id="link2"> 
   さる、 
  </a> 
  そして、 
  <a href="http://sample.co/pheasant" class="company" id="link3"> 
  キジです。 
  </a> 
  向かうは鬼ヶ島。いざ出発です。 
 </p> 
 <p class="story"> 
   ... 
 </p> 
</body> 
</html>

必要なタグ部分のみをスクレイピングする

例として「titleタグ」の内容を取り出します。記述方法は2通りあります。

soup.title

または

soup.find( “title” )

▼実行結果

<title>桃太郎物語</title>

非常にシンプルなコードで抽出できます。しかし、この記述方法ではタグに挟まれた状態のデータが抽出されます。

そのため、同じタグが複数存在する場合は次のようなデータが連続する実行結果が表示されます。

soup.a

または

soup.find( “a” )

▼実行結果


<a href="http://sample.co/dog" class="company" id="link1">犬</a><a href="http://sample.co/monkey" class="company" id="link2">さる</a> <a href="http://sample.co/pheasant" class="company" id="link3">キジです。</a>

必要なテキスト部分のみをスクレイピングする

タグで挟まれたままの連続した抽出結果では、データを読みにくい場合もあります。そこで、タグの中身であるテキスト部分だけをスクレイピングを行いましょう。以下のコードを使います。

soup.title.string

または

soup.find( “title” ).text

▼実行結果

‘桃太郎物語’

今回も2通りの記述方法を紹介しました。このほかにも、Beautiful Soupでデータを抽出する際のコードは存在しています。そのため煩雑にも見えますが、使用される際のポイントとしては「使うコードのルールを自分でつくること」です。

たとえば、タグの抽出には「soup.find( “指定するタグ” )」、テキストの抽出には「soup.find( “指定するタグ” ).text」と決めておけば混乱を防ぐことができるでしょう。

必要なすべてのタグをスクレイピングする

「soup.find_all()」を使えば、必要とするタグのデータを一気にスクレイピングできます。pタグを例にとって実行します。

soup.find_all( “p” )

▼実行結果

[<p class="title"><b>桃太郎物語</b></p> ,<p class="story">きび団子をもら い、桃太郎と鬼退治の仲間となったのは、<a href="http://sample.co/dog" class="company" id="link1">犬</a>, <a href="http://sample.co/monkey" class="company" id="link2">さる</a> そして、<a href="http://sample.co/pheasant" class="company" id="link3">キジです。</a> 向かうは鬼ヶ島。いざ出発です。 </p>,<p class="story">...</p> ]

このように「soup.find_all()」を使用すると、pタグのデータすべてを抽出できました。soup.find_all()の実行結果は[ ]で囲まれています。Pythonで[ ]で囲まれている範囲は「データがリストに格納されている」ことを指します。そこで、[ ]内を数値指定することもできます。

例えば、上記で1つ目のpタグのみを抽出します。

soup.find_all( “p” )[0]

▼実行結果

<p class="title"><b>桃太郎物語</b></p>

また、クラス名を指定することもできます。

soup.find_all( class_= “company” )

▼実行結果

[<a href="http://sample.co/dog" class="company" id="link1">犬</a>, <a href="http://sample.co/monkey" class="company" id="link2">さる、</a>, <a href="http://sample.co/pheasant" class="company" id="link3">キジです。</a> ]

このようにPythonでBeautiful Soupを使用すれば、タグ名やクラス名など柔軟に文字列を指定しスクレイピングが実行できます。

必要なすべてのテキストをスクレイピングする

「soup.find(  ).text」でテキスト部分のみを抽出しました。では、すべてのテキスト部分を抽出するために「soup.find_all(  ).text」として実行します。

soup.find_all( “title” ).text

▼実行結果

AttributeError: ResultSet object has no attribute ‘text’. You’re probably treating a list of items like a single item. Did you call find_all(  ) when you meant to call find()?

エラーが表示されてしまいました。内容は「textは含まれていません。find()を使うつもりだったのに、find_all(  ) を使ってしまいましたか?」といった内容です。先述にもあるとおりfind_all(  ) を使用すると、[ ]リストに格納されます。soup.find(  ).textではリスト内を指定するコードとは言えないためエラーを起こしてしまいました。

テキスト部分を指定するには、以下のように「forループ」を使う必要があります。

for p_tag in soup.find_all( “p” ): print(p_tag.text )

▼実行結果

桃太郎物語 
きび団子をもらい、桃太郎と鬼退治の仲間となったのは、犬、さる、そして、キジです。向かうは鬼ヶ島。いざ出発です。
...

このように指定したタグのテキストすべてをスクレイピングできました。

必要な画像データをスクレイピングする

画像データの取得もテキストデータと基本的には同じです。

▼サンプルコード例

import requests 
from bs4 import BeautifulSoup   

URL =’(URLを代入する)’ 
soup = BeautifulSoup( r.get(URL).content, 'html.parser'  ) 
srcs= [ ] 
for link in soup. find_all( “img” ):

BeautifulSoupで取得したデータ内にある「src」を格納範囲に指定し、「imgタグ」をすべて取得できます。

指定したスクレイピング情報がHTML上になかった場合

コードが正しくても、指定したスクレイピング情報がHTML上に存在しなかった場合はどのようになるでしょうか。上記のHTMLコーディング例には含まれていない「h2タグ」を指定するとどうなるでしょう。

soup.find( “h2” ).text

▼実行結果

None

このように、HTML上に存在しないタグを指定してしまった場合は「None」と表示されます。そのため、スクレイピングを行う前には必ず抽出したいタグの確認を行ってください。

また、以下のようなパターンも起こりがちです。

▼サンプルコード例

import requests 
from bs4 import BeautifulSoup   

response = requsts.get(URLを代入する)   

soup = BeautifulSoup( r.text, 'html.parser' )

▼実行結果

NameError: name ’requsts’ is not defined.

このような単純なコードのスペルミスでも実行できなくなるケースがあります。エラーが表示されても落ち着いて対処しましょう。

spanタグ部分のみをスクレイピングする

HTML上では「spanタグ」が多用されています。そのため、spanタグ部分のスクレイピングにも挑戦しましょう。soup.find_all(span)のコードでspanタグ部分を抽出しますが、今回は「len関数」を使ってspanタグを数えてみます。その結果を「print」します。

print(len(soup.find_all(‘span’))) soup.find_all(‘span’)

▼実行結果:例

10   

[<span class=”red”>tomato</span>, <span class=”red”>strawberry</span>, <span class=”red”>apple</span>, <span class=”yellow”>banana</span>, <span class=”yellow”>lemon</span>, <span class=”yellow”>star</span>, <span class=”blue”>fish</span>, <span class=”blue”>ocean</span>, <span class=”blue”>sky</span>, <span class=”green”>leaf</span>]

このようにHTML上にあるspanタグの数と、spanタグが[ ]に格納されている結果が出ました。

class名のついたspanタグ部分のみをスクレイピングする

実際のスクレイピングでは、HTML上に存在するspanタグがすべて必要になることはあまりありません。そのため、spanタグのクラス名を指定して必要なデータを抽出します。find_all()に引数の「class_」を追加するだけです。Pythonでは予約語「class」も存在するため、classの後に「_ 」をつけ忘れないようにしてください。

soup.find_all(‘span’, class_=’red’)

▼実行結果:例

[<span class=”red”>tomato</span>,  
<span class=”red”>strawberry</span>, 
<span class=”red”>apple</span>]

また、複数のclass名を選択する場合は[ ]を使い、下記のように指示します。

soup.find_all(‘span’, class_=[’yellow’, ‘blue’])

▼実行結果:例

[ <span class=”yellow”>banana</span>, 
<span class=”yellow”>lemon</span>, 
<span class=”yellow”>star</span>, 
<span class=”blue”>fish</span>, 
<span class=”blue”>ocean</span>, 
<span class=”blue”>sky</span>]

Beautiful Soupを使用する際の注意点

Requestsから読み込まれたHTMLデータは膨大な量となります。そのため、Beautiful Soupを使用する際にスクレイピングする範囲を狭くすることが、迅速に目的のデータを手に入れるポイントとなります。「.find 」を2回使って範囲を狭めてみましょう。

soup.find(article).find_all([‘h2’,’h3’])

このように書けば「articleタグ」内と範囲を限定して、その中の[‘h2’,’h3’]すべてを抽出できます。

さらに、「.extract()」を使えば抽出したデータから該当する要素の削除を行うこともできます。「spanタグ部分をすべて抽出」する際に利用したコードの中から「class名’green’」だけを削除する場合は下記のようになります。

soup.find_all(‘span’) soup.find_all(‘span’, class_=’green’).extract()

Beautiful Soupのコードまとめ

pip install requestsRequestsライブラリのインストール
import requestsRequestsライブラリのインストール
response = requests.get(URL)スクレイピングを行うURLを指定
pip install beautifulsoup4Beautiful Soupのインストール
from bs4 import BeautifulSoupBeautiful Soupのインポートと初期化
soup = BeautifulSoup( r.text, ‘html.parser’ )Requestsから取得したHTMLのtextをBeautifulSoupで解析
print(soup.prettify())読み込んだHTMLをインデントで整列
type(r.text)読み込んだHTMLの型を確認
response = requests.get(URL)bytes文字列として取得
soup.titletitleのみ抽出
soup.find( “” )タグを指定して抽出
soup.find_all( “” )全タグ検索
soup.find_all( “” )[ ]全タグ内から行を指定
soup.find_all( class_= “” )クラス名の指定
soup.find(  ).textテキスト部分のみ抽出
for p_tag in soup.find_all( “p” ):pタグのテキスト部分のみ抽出
soup.find_all(‘span’, class_=’’)spanタグのclass名を指定
soup.find_all(‘span’, class_=[’’, ‘’])spanタグのclass名を複数指定

Beautiful Soupを使ってスクレイピングしてみよう!

PythonでRequestsライブラリとBeautiful Soupを使用し、データ収集・解析する方法を解説しました。Beautiful Soupの活用は一見難しそうに見えますが、コードの多くは簡潔化されています。活用方法さえ習得すれば、データ解析を自動化でき作業効率も高まるでしょう。HTMLのデータ解析に関する企業からのニーズも高騰しています。独学でもマスターすることもでき、副業につながる可能性も秘めています。

ただし、時間の効率化を図るなら、オンラインレッスンで働きながら受講できるプログラミングスクールもご検討ください。

Pythonが学べる学習比較サイトはこちら▶︎▶▶︎