皆さんは
スクレイピングという言葉をご存じでしょうか?
例えばPythonでの機械学習を行うために必要な大量のデータが必要な場合や、あるサイトの情報を定期的に取得したい場合などに役立ちます。
ここでは
- スクレイピングって何?
- Pythonでスクレイピングはどうやるの?
といった疑問に回答しつつ、Pythonでスクレイピングする方法を解説します。
なお、ここではrequestsを使ったスクレイピングについて解説します。
Seleniumを使ったスクレイピングはこちら↓
※Seleniumの記事は次書く予定
目次
スクレイピングとは
スクレイピングとは「Webサイトから情報を収集する」技術の一つです。
主にhtmlファイルを解析して中身のデータを取得することを目的としています。スクレイピングができるようになると、他のWebサイトから情報を収集するのが容易になります。
※スクレイピングの注意点
スクレイピングは他のWebサイトから情報を取得することなので、著作権に違反するようなことはできません。
例えばスクレイピングで得たデータをそのまま公開し、そのデータで直接利益を得るといった行動は違反となります。
しかし、日本ではスクレイピングの規制が非常にゆるく、スクレイピング時の著作権の取り扱いは「データ分析、教育目的、および引用目的の範囲であれば、そのスクレイピングは著作権法上認められる範囲」とされています。
参考→https://www.itmedia.co.jp/news/articles/1710/10/news040.html
つまり、機械学習のためのデータ収集自体は問題なく、例えば大量の画像をスクレイピングで取得して、それをTensorFlow等のディープラーニングFWで学習させた成果物を、営利目的に公開・販売すること自体は特に問題ないようです。
しかし、先ほども言いましたが、取得した大量のデータをそのまま公開するのは違法です。注意しましょう。
※筆者は法律の専門家ではありません。よって、情報が間違っている、または法律の改正により、スクレイピング時の著作権法上認められる範囲が限られる可能性があります。スクレイピングを営利目的で扱う場合は専門家にご相談の上ご活用ください。
【Pythonでのスクレイピング】requestsを使ったスクレイピング方法
では実際にPythonでスクレイピングをやってみましょう。
いくつか方法がありますが、ここではrequestsを使ってhtmlを取得し、beautiful soupで取得したhtmlを解析します。
先にpipを使ってインストールしておきましょう。
pip install requests beautifulsoup4
beautiful soupは beautifulsoup4という名前なので注意しましょう。
requests
requestsはhtmlを取得するためのサードパーティライブラリです。
実はpythonにはurllibという標準ライブラリがあるのですが、requestsの方がよりシンプルに使えるので、サードパーティ製ライブラリが使えるのであれば、基本にrequestsを使うことが多いです。
requests.get()でhtmlを取得する
では実際にrequestsを使ってhtmlを取得してみましょう。
import requests
url = 'https://webhack.jp/'
response = requests.get(url)
print(response.text)
<!doctype html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="ja"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="ja"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9" lang="ja"> <![endif]-->
<!--[if IE 9]> <html class="no-js lt-ie10" lang="ja">
以下略
requests.get()の引数にurlを渡すことで、htmlを取得することができました。
requests.get()はhttpリクエストのGETメソッドに相当する処理です。
requests.get()はResponseオブジェクトを返却します。今回はその中のtextメンバを参照し、取得したhtmlを出力しています。
Responseオブジェクト
requests.get()は戻り値としてResponseオブジェクトを返却します。
ここではResponseオブジェクトのメンバやメソッドを見ていきましょう。
アクセスしたURLを取得する
urlメンバを参照することでアクセスしたurlを取得できます。
import requests
url = 'https://webhack.jp/'
response = requests.get(url)
print(response.url)
https://webhack.jp/
ステータスコードを取得する
status_codeメンバを参照することでステータスコードを取得できます。
import requests
url = 'https://webhack.jp/'
response = requests.get(url)
print(response.status_code)
url = 'https://webhack.jp/notfound' #存在しないページ
response = requests.get(url)
print(response.status_code)
200
404
下のurlのページは存在しないので、404エラーが返ってきました。
status_codeを参照することでページを正常に読み込めたかどうかが判断できます。
200番台以外のステータスコードの場合例外にする
status_codeを参照することでも正常にページが読み込めたかどうかは確認できます。
ですが、raise_for_status()メソッドを使うことでより簡単に判定でき、さらに親切な例外メッセージを出力してくれるので、単純に200番台以外のステータスコードの判定にはこちらをおすすめします。
import requests
url = 'https://webhack.jp/notfound' #存在しないページ
response = requests.get(url)
response.raise_for_status()
requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://webhack.jp/notfound
ヘッダ情報を取得する
headersメンバを参照することでヘッダ情報を取得できます。
import requests
url = 'https://webhack.jp/'
response = requests.get(url)
print(response.headers)
{'Server': 'nginx/1.12.2', 'Date': 'Mon, 23 Mar 2020 11:12:00 GMT', 'Content-Type': 'text/html; charset=UTF-8'
以下略
主にContent-Typeから目的のファイルを取得できているかなどを判定する場合などに使えます。
【Pythonでのスクレイピング】beautiful soupの使い方
次にbeautiful soupの使い方を見ていきましょう。
beautiful soupはrequests等で取得したhtmlを解析し、扱いやすい状態にしてくれるモジュールです。
htmlを解析する
では実際にhtmlを解析してみましょう。ここでは当サイトのprogrammingカテゴリのページから記事タイトルの一覧を取得してみます。
import requests
from bs4 import BeautifulSoup
url = 'https://webhack.jp/category/programming/'
response = requests.get(url)
bs = BeautifulSoup(response.text, 'html.parser')
h3_tags = bs.find_all('h3', class_ = 'jeg_post_title')
for h3 in h3_tags:
a_tag = h3.find('a')
print(a_tag.get_text())
【Tech Academy】ブートキャンプで活きた知識を身につける!
【子供向けプログラミング教室】寺子屋方式でしっかり学ぶ!TENTOの魅力とは
【Python初心者向け】辞書(dict)の使い方を徹底解説!
【Python初心者向け】タプル(tuple)の使い方を徹底解説!
【Python初心者向け】リスト(list)の使い方を徹底解説!〜リストのあれこれ〜
【N高校】プログラミングコースって実際どうなの?
プログラミングスキルを身につけて副業に活かす、Progateの紹介
以下略
順番に見てきましょう。まずこちら
bs = BeautifulSoup(response.text, 'html.parser')
BeautifulSoupを使ってresponse.textをhtmlとして解析しています。解析結果はbs変数に格納され、以降はbeautiful soupのメソッドを使ってhtml内の情報を取得できます。
次にこちら
h3_tags = bs.find_all('h3', class_ = 'jeg_post_title')
html内の情報を取得するため、まずはタグを抽出しています。上記ではh3要素、かつclassがjeg_post_titleのタグを全てリスト形式で取得しています。h3の中にはaタグが入っており、そのaタグのテキストがお目当ての記事タイトルです。
なので、最後にh3タグの中から記事タイトルを取得します。
for h3 in h3_tags:
a_tag = h3.find('a')
print(a_tag.get_text())
h3タグ内のa要素を取得しています。h3の中にはaタグが1つしかないので、find()を使います(find_all()は複数、findは単数の要素を取得する)。
最後にget_text()でaのテキストを出力しています。
このように、スクレイピングを使えばサイトの情報をhtmlからひっぱり出すことができます。
ただし、requests + beautiful soupで取得できるのは静的なサイトのみです。JavaScriptを使った動的なページでスクレイピングする場合はSeleniumを使う必要があります。
※ここにSeleniumの記事のurlを添付予定
find_all()の使い方
最後にbeautiful soupで重要なfind_all()の使い方を見ていきましょう。
idで指定する
先ほどはclassでタグを指定しましたが、idでも指定できます。基本的にidは1つのhtml内で一意であるべきですが、一応指定可能です。
elements = bs.find_all(id='abc')
タグをリストで渡す
タグの文字列をリスト形式で渡すことで、指定したタグ全ての要素を取得できます。
elements = bs.find_all(["h2", "h3", "b"])
html内の全てのタグを取得する
引数にTrueを指定することで、html内の全てのタグを取得できます。
all_elements = bs.find_all(True)
文字列を検索する
string引数に文字列を渡すことで、html内にその文字列があるかどうかを検索できます。存在するしないにかかわらずリストを返却しますが、文字列が存在しなかった場合は空のリストが返却されます。
strings = bs.find_all(string="Python")