スクレイピング
インターネット上には大量の情報があり、データ分析の題材にはピッタリです。しかし、HTMLはWebブラウザのためのマークアップ言語であり、データ分析用のツールを用いてもそのまま利用できません。この記事では、Webページからデータを収集するスクレイピングについて解説します。
##スクレイピング環境の準備
スクレイピングを行うための準備として、2つの外部パッケージをインストールします。
pip install requests
pip install beautifulsoup4
-Requestsは、Webブラウザの代わりにWebサイトにアクセスして、HTTPでデータの送受信を行う。
-BeautifulSoup4はHTMLやXMLを解析してデータを取り出すためのライブラリです。
##対象Webページをダウンロード
Requestsを使用して、取得したいWebページの情報を得ます。
例として、CodeZineの情報を取得してみたいと思います。
import requests
r=requests.get('https://codezine.jp/') #URLにアクセスする
print(type(r))
print(r.status_code) #ステータスコードを確認
結果は次の通りです。アクセス成功すると200とでます。
<class 'requests.models.Response'>
200
ページの内容(HTML)を取得し、<title>タグと<h1>タグの要素を取得します。
text=r.text #HTMLのソースコードを取得
for line in text.split('\n'):
if '<title>' in line or '<h1>' in line:
print(line.strip())
結果は下の通りで、正しくHTMLの中身を取得できていることが確認できます。
<title>CodeZine (コードジン)</title>
<h1><a href="/"><img src="/lib/img/cmn/cmn-header-logo.png" alt="CodeZine(コードジン)"></a></h1>
##Webページ要素取得
上の例ではin演算子による文字列処理でHTMLから目的要素を取得しています。他に正規表現を使う方法もありますが、複雑なHTMLから任意の要素を抜き出すのは困難です。そこでHTMLを構文解析して要素を探しやすくします。
BeautifulSoup4を使うとHTMLを構文解析して任意の要素を取得できます。
from bs4 import BeautifulSoup
soup=BeautifulSoup(text, 'html.parser') #HTML解析オブジェクト生成
print(soup.title) #<title>タグ情報取得
print(soup.h1) #<h1>タグ情報取得
print(soup.h1.a.img['alt']) #h1タグ中のaタグ中のimgタグ中のalt属性
find_allメソッドを使用すると、HTMLに存在する引数で指定したタグをすべて取り出すことができます。次のコードは全<a>タグを取得し、件数を表示します。その後、先頭5件の文字列とhref属性の中身を取得しています。
atags=soup.find_all('a') #全aタグ取得
print('aタグ数:', len(atags)) #aタグ数取得
for atags in atags[:5]:
print('タイトル:',atags.text) #aタグのテキスト取得
print('リンク:',atags['href']) #aタグのリンク取得
##記事一覧取得
RequestsとBeautifulSoup4の基本的操作を基に、スクレイピングによるデータ収集を行います。CodeZineにはタグごとに関連する記事を一覧表示するページがあるので、Pythonタグがついている記事一覧から各記事の日付やタイトルを取得します。
以下の情報を取得していきます。
- 日付:記事公開日
- タイトル:記事タイトル
- URL:記事URL
- タグ:タグ情報
プログラムコードを書く前に、取得対象WebページのHTML構造を解析します。「Python」記事一覧のHTMLは以下のようになっています。
<div style="clear:both"></div>
<ul class="catList">
<li id="10865">
<figure><a href="/article/detail/10865"><img width="80" height="60" src="/static/images/article/10865/10865_t.png" alt=""></a></figure>
<div class="day">2019/05/01</div>
<h2><a href="/article/detail/10865">タイトル文</a></h2>
<p>キャッチ文</p>
<ul class="tag">
<li><a href="/article/t/Python">Python</a></li>
<li><a href="/article/t/%E3%63%37%36">レポート</a></li>
</ul>
</div>
</li>
<li id="10846">
<figure>***</figure>
:
:
この記事一覧のHTML構造は、
- 記事全体が<ul class="catList">の中にある
- 1つの記事は<li>単位
- <h2>中の<a>中にタイトルとリンク先
- <ul class="tag">中にタグ情報、各タグごとに<li>がある
よってpythonでコードを書いていきます。
from datetime import datetime
from bs4 import BeautifulSoup
import requests
r=requests.get('https://codezine.jp/article/tag/223')
soup=BeautifulSoup(r.text,'html.parser')
articles=[] #各記事の情報を格納するためのリスト
lis=soup.select('ul.catList > li') #<ul class="catList"><li>取得
for li in lis:
day=li.find('div',class_='day').text.strip() #日付の文字列取得
published=datetime.strptime(day, '%Y/%m/%d') #日付をdatetime変換
h2_tag=li.find('h2') #h2タグ取得
title=h2_tag.text #タイトル取得
url=h2_tag.a['href'] #URL取得
tag_list=li.select('ul.tag > li') #タグのli要素を取得
tags=[tag.text.strip() for tag in tag_list] #タグリスト生成
article={
'published':published,
'title':title,
'url':url,
'tags':tags
}
articles.append(article)
print(articles[:3]) #先頭3件を参照
Webページの情報が正しくスクレイピングで取得できたら、取得データをDataFrameに変換するなどして、分析用データとして使用したりします。
import pandas as pd
df=pd.DataFrame(articles)
このWebページの情報を取得するプログラムを改良して、1ページだけでなく他のページを読み込ませて取得することもできます。また各記事のリンク先にアクセスして、それぞれの記事の詳細情報を取得することもできます。
##スクレイピングで気を付けること
数多くあるWebサイトの中には、プログラムでのアクセスを許可していないものがあります。許可があるかないかを確認するにはWebサイトのrobots.txtというファイルを参照してください。どのURLにプログラムでアクセスしてよいかが定義されています。
また、同じWebサイトに連続してアクセスしないことも気を付けるべきです。プログラムから同じWebサイトの記事を連続して取得しようとすると、Webサイトに大量のアクセスを発生させてWebサーバの負荷が高くなる場合があるからです。連続してWebサイトにアクセスする際は数秒の間隔をあけてアクセスするようにしましょう。
##スクレイピングの応用
###Javascript取得
紹介したRequestsとBeautifulSoup4はJavaScriptで表示されているWebコンテンツの取得はできません。
JavaScriptで表示されるコンテンツを取得するには、WebブラウザなどでJavaScriptを解釈する必要があります。以下のツールが役立ちます。