この記事ではPythonで行うWebスクレイピングの方法とその注意点を紹介します。
簡単なサンプルもついています。参考にどうぞ。
1. Webスクレイピングとは?と、その注意点
Webスクレイピングとは
Webスクレイピングとは、
指定されたURL先のサイトからWebサイトを構成するHTMLデータを取得する方法です。
「PythonでWebスクレイピング」とよく聞きますが、
これはPythonでWebスクレイピングが簡単ということから。
実際は、JavaScriptやC、VBAでもやることができます。
Webスクレイピングで注意すべきこと
また、Webスクレイピングを行う上で注意すべきことがあります。
- スクレイピングが禁止されているサイトか
(Twitterはスクレイピング禁止を明示) - 著作権を侵害しないように
(情報解析目的であればOK) - 短時間に大量アクセスでサーバに負荷をかけない
(1秒おき毎が平均らしい?)
上記のことに注意しましょう。
2. PythonでWebスクレイピング【サンプル付き】
では実際にPythonでWebスクレイピングをやっていきます。
目的は、NHKのニュースサイト[https://www3.nhk.or.jp/news/]から
各トピックのニュースタイトルを拾っていきます。
全体の流れ
ここでは、NHKのニュースサイトからHTMLデータを拾うまでを書きます。
Webスクレイピングの全体のコードを書いて、詳細を後で書きます。
import requests
from bs4 import BeautifulSoup
url = 'https://www3.nhk.or.jp/news/'
res = requests.get(url)
res.encoding = res.apparent_encoding
soup = BeautifulSoup(res.text, "html.parser")
ここまででURL先のサイトからHTMLデータを拾うまでをしました。
詳細を書いていきます。
詳細 〜import
import requests
from bs4 import BeautifulSoup
url = 'https://www3.nhk.or.jp/news/'
Webスクレイピングでは「requests」と「BeautifulSoup」が必要になります。
importでそれぞれをコードに入れましょう。
BeautifulSoupはもともと「BeautifulSoup4」(略してbs4)というライブラリに入っているため、from bs4が必要になります。
詳細 〜requests
res = requests.get(url)
requests.getでURL先を訪問して、「res」として取得しました。
ここのrequests.getでは実はいろいろな情報を取得しています。
3つの例を下に書いておきます。
print(res)
-> Response[200] リクエストが成功の意味
print(res.text) テキスト出力(一部抜粋)
-> <title>NHKニュースサイト 日本全国・世界の速報、最新情報|NHK NEWS WEB</title>
<meta name="robots" content="noodp,noarchive">
<meta name="keywords" content="NHK,ニュース,NHK NEWS WEB" />
print(res.content)バイナリ出力(一部抜粋)
-> <title>NHK\xe3\x83\x8b\xe3\x83\xa5\xe3\x83\xbc\xe3\x82\xb9\xe3\x82\xb5\xe3\x82\xa4\xe3\x83\x88 \xe6\x97\xa5\xe6\x9c\xac\xe5\x85\xa8\xe5\x9b\xbd\xe3\x83\xbb\xe4\xb8\x96\xe7\x95\x8c\xe3\x81\xae\xe9\x80\x9f\xe5\xa0\xb1\xe3\x80\x81\xe6\x9c\x80\xe6\x96\xb0\xe6\x83\x85\xe5\xa0\xb1\xef\xbd\x9cNHK NEWS WEB</title>\r\n
<meta name="robots" content="noodp,noarchive">\r\n
<meta name="keywords" content="NHK,\xe3\x83\x8b\xe3\x83\xa5\xe3\x83\xbc\xe3\x82\xb9,NHK NEWS WEB" />
requestsだけでここまで取れるってすげー。
詳細 〜res.encoding = res.apparent_encoding
res.encoding = res.apparent_encoding
これがなぜ必要かというと、
Webスクレイピングで取得したデータの日本語って
文字化けしていることが多いからです。
例えば、res.encoding = res.apparent_encoding がない場合、
res.textはこのように見えていたんです。
print(res.text) (一部抜粋)
-> <title>NHKãã¥ã¼ã¹ãµã¤ã æ¥æ¬å¨åã»ä¸çã®é ±ãææ°æå ±ï½NHK NEWS WEB</title>
<meta name="robots" content="noodp,noarchive">
<meta name="keywords" content="NHK,ãã¥ã¼ã¹,NHK NEWS WEB" />
そのため、Webスクレイピングして
欲しい情報が文字化けしていないか確認が必要です。
もし文字化けしているなら
res.encoding = res.apparent_encoding
が必要になってきます。
詳細 〜BeautifulSoup
soup = BeautifulSoup(res.text, "html.parser")
ここでは取得した「res.text」がテキストデータなので
HTLM形式にして、この後でコンピュータが処理しやすくしていきます。
こんな感じです。
print(soup) (一部抜粋)
-> <title>NHKニュースサイト 日本全国・世界の速報、最新情報|NHK NEWS WEB</title>
<meta content="noodp,noarchive" name="robots"/>
<meta content="NHK,ニュース,NHK NEWS WEB" name="keywords">
:(略)
<dd><a href="/news/html/20210122/k10012828021000.html">
<em class="title">東京都 新型コロナ 1175人感染確認 1000人超は10日連続</em>
<time datetime="2021-01-22T20:08:31">1月22日 20時08分</time></a>
<span class="i-items--group">
<i aria-hidden="true" class="i-new">NEW</i>
<a class="i-word" href="/news/word/0000969.html?word_result=%E6(略)%B0">
新型コロナ 国内感染者数</a>
</span></dd>
:(略)
だいぶ長いので省略しています。
これでHTML形式に変換できました。
ところで、ここの「parser」は文法に従ってデータを解析して、プログラムで扱いやすいようなデータ構造に変換する機能のことを指しています。
なので、HTML形式に変換を指示しています。
3. Webスクレイピングからデータを取得する
さて、Webスクレイピングした結果から欲しいデータだけを抽出します。
この作業は短いため、2つの部分に分けて説明していきます。
欲しいデータの抽出条件を知る
ここでは各トピックのニュースタイトルを抽出します。
まず、欲しいデータの抽出条件を把握しましょう。
上記にもありますが、ニュースタイトルはこの部分です。
<em class="title">東京都 新型コロナ 1175人感染確認 1000人超は10日連続</em>
<em>で囲まれている部分です。これが抽出部分の条件になります。
HTML形式から抽出してみる
抽出条件がわかったら、欲しいデータ部分を取得していきます。
欲しいデータだけを抽出するコードの全体を書きます。
import re
data = soup.find_all('em')
for i in data:
title = re.findall(<em class="title">(.*)</em>', str(i))
print(title)
これがデータを抽出するためのコードです。
詳しい説明を書いていきます。
詳細 〜soup.find_all()
data = soup.find_all('em')
ここではsoupの中にHTML形式の情報が入っており、その中のニュースタイトルの抽出条件である<em>で括られた部分だけをリストとして取り出す処理をします。
そのため、dataの中はこんな感じで、出力結果がリストになります。
print(data)
->[<em class="title">都内の女の子 変異ウイルス感染 海外渡航歴ない男性から感染か</em>,
<em class="title">東京都 新型コロナ 1175人感染確認 1000人超は10日連続</em>,
<em class="title">政府分科会 尾身会長「緊急事態宣言解除に3つの条件」</em>,
<em class="title">新型コロナ 過去最多108人死亡 5045人感染確認(22日20:30)</em>,
<em class="title">東京五輪開幕まで半年 準備進むも輸送面など計画変更可能性も</em>,
<em class="title">【詳報】アメリカ バイデン新大統領 就任演説</em>,
<em class="title">“宣言”2週間「実効再生産数」11都府県の多くで前週より低く</em>]
詳細 〜最後の処理
import re
for i in data:
title = re.findall(<em class="title">(.*)</em>', str(i))
print(title)
最後の処理になります。
ここでは、さらにタイトルの文字だけ抽出する処理をします。
そのためには正規表現モジュールreのfind_allを使います。
モジュール re をインポートしましょう。
また、dataの中にはリスト化した<em>~</em>があるため
for文を使って、一つずつre.findall()で処理をします。
re.findall()はこんな感じに使います。
title = re.findall(<em class="title">(.*)</em>', str(i))
↓
変数 = re.findall(この文字後から取り出す(.*)この文字前まで取り出す, str型)
re.findallで出力される結果もリスト型になるため
このあとも処理しやすいです。
ちなみに出力結果はこんな感じ(1/22の23時ごろのニュースタイトルです。)
print(title)
->['都内の女の子 変異ウイルス感染 海外渡航歴ない男性から感染か']
['東京都 新型コロナ 1175人感染確認 1000人超は10日連続']
['政府分科会 尾身会長「緊急事態宣言解除に3つの条件」']
['新型コロナ 過去最多108人死亡 5045人感染確認(22日20:30)']
['東京五輪開幕まで半年 準備進むも輸送面など計画変更可能性も']
['詳報】アメリカ バイデン新大統領 就任演説']
['“宣言”2週間「実効再生産数」11都府県の多くで前週より低く']
まとめ
これまでのコードはこんな感じです。
import requests, re
from bs4 import BeautifulSoup
url = 'https://www3.nhk.or.jp/news/'
res = requests.get(url)
res.encoding = res.apparent_encoding
soup = BeautifulSoup(res.text, "html.parser")
for i in data:
title = re.findall(<em class="title">(.*)</em>', str(i))
print(title)
たった9行でWebスクレイピングが完成です。
Pythonってやっぱり簡単ですね。
もっと詳しくWebスクレイピングが知りたいって方には
是非もっておきたい一冊を紹介します。