【シンプル解説】PythonでWebスクレイピングの方法と注意点【サンプル付き】

Python

この記事では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スクレイピングが知りたいって方には
是非もっておきたい一冊を紹介します。

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