Python

Python基礎:Webスクレイピング①

スポンサーリンク

はじめに

今回はスクレイピングを扱います。「requests」というwebページを取得するためのhttpライブラリと、「BeautifulSoup」というHTMLから情報を抽出するライブラリを使います。requestsでURLからHTMLを取得し、BeautifulSoupで要素を取得する、という使い方をします。

準備

requests

requestsはPythonのHTTP通信ライブラリです。インストールされていない場合は、次のコマンドでインストールしておきましょう。

pip install requests

利用するときにはまずライブラリをインポートしておきます。

# ライブラリのインポート
import requests

HTTP通信ライブラリなので、get, post, put, etcなどのHTTPリクエストを生成することができますが、今回はスクレイピングをしたいので、getが使えればよいです。試しにこのブログのトップページを取得してみましょう。

response=requests.get('https://happy-analysis.com/')

requests.get()ではresponseオブジェクトが生成されます。これを直接指定しても、次のようにステータスがわかるだけです。

response

requestオブジェクトから情報を取り出すには、属性を指定する必要があります。url属性にアクセスすると、次のようになります。

response.url

responseの内容(文字列)はtext属性で取得できます。

response.text

確かにHTMLは取得できていますが、このままだと見づらいですね。このHTMLを解析して必要な情報だけ抽出するのが、BeautifulSoupというライブラリの役割になります。

BeautifulSoup

まずインストールしておきましょう。

pip install beautifulsoup4

無事インストールできたら、次のようにしてライブラリをインポートしておきましょう。

# ライブラリのインポート
from bs4 import BeautifulSoup

これで準備ができました。先ほど取得したHTMLを解析してみましょう。次のような書式で解析を実行します。

BeautifulSoup(解析対象,'html.parser')

先ほど、取得したHTMLはresponse.textとなるので、簡単ですね。この解析結果をsoupという変数に格納することにしましょう。

# HTMLの解析
soup=BeautifulSoup(response.text,'html.parser')

このsoupの中身を見てみましょう。

soup

これが解析結果です。読み込んだHTMLをそのまま表示しているようにも見えますが、先ほどのresponse.textよりも格段に見やすくなっていますね。BeautifulSoupの威力を発揮するのはここからで、このHTMLから必要な情報を抽出することができます。

スポンサーリンク

BeautifulSoupを使って情報を抽出する

BeautifulSoupクラスのインスタンス(上記のsoupオブジェクトのこと)から情報を取り出す方法は、大きく分けてfind系(find_all( ), find( ))のメソッドと、select系(select( ), select_one( ))のメソッドの2種類がある。これらはできることはほぼ同じで、条件の指定方法が異なる。ここではfind系を扱うことにする。

find( )とfind_all( )の違いは、次の点です。

  • find( )は引数に一致する最初の要素を1つだけ取得する
  • find_all( )は引数に一致する要素をすべて取得する

find_all( )を使った解析の基本

ここではfind_all( )を使って解析してみましょう。まずはタイトルを取得してみましょう。

soup.find_all('title')

タイトル部分を取得することができました。このように、基本は、

soup.find_all('タグ名')

という書式でタグを指定することで取得することができます。タグを階層で指定することもできます。

soup.body.div.li()

この例では、bodyの中のdivタグの中のliタグを抽出しています。このようにタグを「.」でつなぐだけです。簡単ですね!

タグだけではなく、クラスで条件指定したり、idでの条件指定、あるいは、これらの組み合わせでの条件指定もできます。

find_all( )の引数

find_all( )には次のような引数があります。

nameタグを指定する。
文字列、正規表現、リスト、関数、True値での指定が可能。
attrsタグの属性を辞書で渡し指定する。
recursiveTagオブジェクトの検索対象範囲を指定。
True: Tagオブジェクトの全ての子孫要素を検索。
False: Tagオブジェクトの直下の子要素のみを検索。
textタグに挟まれているテキスト(文字列)を指定する。
文字列、正規表現、リスト、関数、True値での指定が可能。
imit検索条件にマッチしたタグ・文字列の取得する数を制限する。
キーワード引数タグの属性を指定する。
文字列、正規表現、リスト、関数、True値での指定が可能。
引用元:https://ai-inter1.com/beautifulsoup_1/#find_detail

先ほどの「soup.find_all(‘title’)」は「soup.find_all(name=’title’)」とかいても同じ意味になります。引数が多いときは、明示的に書いてもよいかもしれませんね。

soup.find_all(name='title')

次にタグだけではなく、タグの属性も指定する場合です。

soup.find_all(name='a',class_='home_menu')

aタグの中で、class属性が「home_menu」であるものを抜き出しました。属性の指定では、通常、属性をそのまま記述すればよいのですが、classだけは予約語となるので、「class」ではなく「class_」とします。

次に属性を複数指定する場合を見ておきましょう。このブログのソースを見ると、次のような部分があります。

「class」属性に複数の値が設定されています。この部分を指定してみましょう。これは次のように書きます。

soup.find_all(name='li',class_="clearfix num1 type1")

このように、classが「clearfix num1 type1」であるものに完全一致させて、抽出することができました。完全一致ではなく、部分一致にさせたいときには、次のように書きます。

soup.find_all(name='li',class_=["clearfix","type1"])

idの指定も見ておきましょう。表にまとめたように属性の指定は「属性名」とその値を指定するだけなので、次のように指定できます。(※classだけは予約語だったので、「class_」とします。)

soup.find_all(name='ul',id='menu-python')

「class_」の指定の時とまったく同じ要領ですね。複数選択で部分一致させるときも同じように角括弧で指定します。

引数「text」も見ておきましょう。こちらは、タグに挟まれているテキストを指定します。

soup.find_all(text='分析環境の構築')

2件ヒットしました。この指定は完全一致になるので、たとえば次のようにテキストの値に「分析」を指定した時では、検索結果が異なります。

soup.find_all(text='分析')

今回取得したHTMLの中にはタグの間に「分析」とだけ書かれている箇所はなかったので、結果はnullになりました。部分一致で「分析」という文字がが含まれているものを抽出したいときには、正規表現を用いて次のようにします。

# 正規表現ライブラリのインポート
import re
# text引数と正規表現を使った条件指定
soup.find_all(text=re.compile('分析'))

このように正規表現を組み合わせると条件指定の幅が広がります。属性の指定の場合も、たとえばhref属性である文字列を含むURLを抽出したければ次のように記述できます。

soup.find_all(href=re.compile('python-topic-summary-basic'))
スポンサーリンク

まとめ

いかがでしょうか?だいぶイメージできるようになりましたか?まずは取得したいHTMLのソースを見ながら大体の条件指定を考えて、何度か試してみるとよいでしょう。

コメント

タイトルとURLをコピーしました