Webスクレイピング・ブラウザ操作¶
Webから情報を抽出・整形・解析したり、ブラウザ上での特定の操作を自動化する、といったこともPythonでは比較的容易に実行することができる。
Web上にある情報にアクセスしたりする方法は色々あるが、大まかには2つに分類され
プログラムでWebページにアクセスして中身(HTML)を読み、そこから情報を抽出する方法
ブラウザをプログラムに操作させて特定の作業を実行する方法
この章では、とくに1.のWebから情報を抽出すること(スクレイピング)に絞ってそのエッセンスを紹介する。
HTMLとは、Webページを作るための言語のことで、みなさんが普段からアクセスする多くのWebページは、HTMLで記述されています。
Webから情報を抽出したりする際、共通して言える注意点を述べておく:
対象とするページの利用規約を必ず確認する
規約でスクレイピングを禁止しているページがある
(例: Amazon, Twitter, Instagram, facebook, 金融系などなど)
禁止している場合でも、APIが提供されている場合がある
(※APIはApplication Programming Interfaceの略)
今の場合、大雑把にはデータ提供用の窓口とでも思ってください.サーバーに負荷をかけない
規約で特にスクレイピングを禁止していない場合でも、過度なアクセスをしてはいけません。
(どこかの大学の教務ポータルみたいに落ちてしまったら大変です)
過度なアクセスは、悪意のあるDos攻撃とみなされてアクセスを制限されたり、
最悪の場合、偽計業務妨害罪などの罪に問われる可能性があります。
東京都の新型コロナウイルス関連情報の取得¶
スクレイピングを可能とするライブラリは多数存在する。
代表的なものはrequests
やurllib
。以下ではrequests
を使います。
JavaScriptの実行などがないページならこれでだいたい十分かと思います.
またBeutifulSoup4
というライブラリを使うと、HTMLを構文解析して、
タグなどを取り除くといった操作が比較的容易に行えます。
1つ目の例として、東京都 新型コロナウイルス感染症対策サイトの公開データを取得して
それをグラフにして可視化してみましょう。まずは必要なライブラリをインポートしておきます。
import requests
import json #json形式のデータを扱うために必要
import datetime #日付の処理に使う
import matplotlib.pyplot as plt
!pip install japanize-matplotlib
import japanize_matplotlib
東京都 新型コロナウイルス感染症対策サイトのレポジトリで公開されているデータ(json形式)を読み出す。
指定したurlにリクエストを送り、レスポンスをjson形式で取得する
ちなみに、json形式のデータは、元々JavaScriptのオブジェクトとして扱うために作られたものだが、
PythonやJava, PHPなどでも扱うことができる。Pythonで言うと辞書型が近い。
url = "https://raw.githubusercontent.com/tokyo-metropolitan-gov/covid19/development/data/data.json"
response = requests.get(url)
data = response.json()
上のdata
(辞書型)を直接print
すると表示が冗長になるため、代わりに、キーとして何があるかを見てみよう。
data.keys()
それぞれ
contacts: 新型コロナコールセンター相談件数
querents: 帰国者・接触者電話相談センター相談件数
patients_summary: 陽性患者数
inspections_summary: 検査実施日別状況
lastUpdate: 最終更新日時
main_summary: (これはよくわからない, 使用されていなかったっぽい)
に対応している。
陽性患者数のデータの構造を調べつつ結果を可視化してみよう。
まずは型を調べてみる。
type(data['patients_summary'])
辞書型とわかったのでキーの一覧を見てみよう
data['patients_summary'].keys()
同様にしてdata['patients_summary']["data"]
が”日付”と”小計”をキーに持つ辞書のリストだと分かる。
type(data['patients_summary']['data'])
data['patients_summary']["data"][0]
日付と陽性患者数をリストに直して、描画してみよう
# "2022-01-01"のような文字列をdatetimeに変換する関数
def str_to_dt(tstr):
tdatetime = datetime.datetime.strptime(tstr, '%Y-%m-%d')
tdate = datetime.date(tdatetime.year, tdatetime.month, tdatetime.day)
return tdate
tdat = data['patients_summary']["data"]
N = len(tdat)
tdat = data['patients_summary']["data"]
dates = [ str_to_dt(tdat[i]["日付"].split("T")[0]) for i in range(N)]
num_patients = [ tdat[i]['小計'] for i in range(N)]
print("dates=>", dates)
print("陽性患者数=>", num_patients)
fig = plt.figure(figsize=(12,4))
plt.title("東京都")
plt.xlabel("日付")
plt.ylabel("陽性者数[人]")
plt.plot(dates,num_patients, color="green")
plt.show()
plt.close()
このようにして、Web上のデータを取得して、可視化することができた。
ちなみに、東京都のCOVID19のレポジトリは、 5類以降後の2023年6月にPublic archiveとなり、更新を停止している。
e-Statのデータを取得する¶
政府統計の総合窓口(e-Stat)は日本の各府省が公表する統計データを一つにまとめた政府統計のポータルサイトである。
e-StatではAPI機能(ユーザー登録が必要)が提供されていて、
指定されたURLに対してリクエストを送信することで各APIを利用することが出来る。
準備1 e-Statの登録¶
以降の内容でも、e-StatのAPI機能を使用するため予めe-Statへの登録が必要になる。
国内の公開データを使って最終課題に取り組みたいという方は、必ず、ここに記載の手順にならって登録しておこう。
まずこちらのページからメールアドレス(Gmailを推奨します)を入力し、届いたメールから本登録を行う
このとき、gmailアカウントによる認証をオンにしておくと、以後のログインが楽になる。ログインページからログインし、右上の[マイページ]に遷移
[API機能(アプリケーションID発行)]に遷移する
以下の例にならって、名称とURLを入力し、発行ボタンを押す。
ここでは、名称はGoogleColab、URLはhttp://test.localhost
としている。
[appId]に生成された文字列を、どこかに控えておく(appIdを他人と共有してはいけません)
準備2 Pandas e-Statの導入¶
さて、e-Statへの登録ができたでしょうか。
早速e-Statにあるデータをどんどん抽出したい
…のだが、マニュアルを理解してAPIに適切なリクエストを送るというのは、それ自体がややハードルが高いように思う。
そこで、このノートブックではPython用のライブラリPandas e-Statを使用することにする。
ただし、このライブラリについてもpublic archive化されていてpip
などでインストールできないため、
Google Colabで使用しているサーバー上にライブライのソースファイルをダウンロードして展開し、インポートする荒業で対応する。
#ホームディレクトリにレポジトリをクローン
%cd
!git clone https://github.com/kotamya/pandas-estat.git
# ディレクトリ名を変更し、レポジトリ内に移動しインポート
!mv pandas-estat local_library
%cd ./local_library/
import pandas_estat as pandas_estat
# Pandasをインポート
import pandas as pd
AppIDの定義
appID = "" #引用符内に先ほど作成したAppIDを貼り付ける
pandas_estat.set_appid(appID)
read_statslist()
関数の引数に”政府統計コード”を指定することで、
該当する統計データの一覧をpandas.DataFrame
形式で取得することができる。
政府統計コードの一覧はこちら
以下では、「サービス産業動向調査」の結果を例に抽出してみる。
# サービス産業動向調査
from pandas_estat import read_statslist
statslist = pandas_estat.read_statslist("00200544")
statslist
次に、これらのデータが表データとしてどうやって分類されているのかを調べてみよう。
列(column)を表示してみると
print(statslist.columns)
例えば、CYCLE
(周期)というものがあるので、
CYCLEが”月次”(月ごと)になっているデータだけをピックアップして、
statslist = statslist[statslist.CYCLE == "月次"]
そのTABLE_INF
(統計表ID)とTITLE
(タイトル)だけを表示してみると…
statslist[["TABLE_INF", "TITLE"]]
TABLE_INF
の数値が[統計表ID]と呼ばれるものになる。
この中から”事業活動の産業(中分類)別売上高(月次)【2013年1月~】”を読み出してみよう。
それにはread_statsdata
という関数が用意されているので、引数にTABLE_INF
(統計表ID)を入力すると…
from pandas_estat import read_statsdata
df = read_statsdata("0003191203")
df
これで、データを抽出することができた。
df.columns
次に、もう属性を少し絞ってみよう。
dataframeの”事業活動の産業”列にどんなものがあるかを抽出し、set
関数を使って重複を除くと…
set(df["事業活動の産業"])
例えば”42鉄道業”に注目してみると…
ndf = df[df["事業活動の産業"] == "42鉄道業"] #dfの中の、"事業活動の産業欄が"42鉄道業"のものを抽出し、ndfと名前をつける
#月次データを抽出
ndf = ndf[ndf["時間軸(月次)"].str.endswith("月")]
ndf["時間軸(月次)"] = pd.to_datetime(ndf["時間軸(月次)"], format="%Y年%m月")
ndf = ndf.sort_values("時間軸(月次)")
#さらに必要な列のみ抽出する
ndf[["時間軸(月次)", "value", "unit"]]
図を描いてみよう
import matplotlib.pyplot as plt
!pip install japanize-matplotlib
import japanize_matplotlib
import matplotlib.dates as mdates
x = ndf["時間軸(月次)"].values
y = ndf["value"].values.astype(float) * 1.e-2 # 元が百万円単位なので、100で割ると億円単位になる
fig = plt.figure(figsize=(30, 4))
ax = fig.add_subplot(111)
ax.set_facecolor("#e0e0e0")
ax.set_ylabel("鉄道業の収益 [億円]")
ax.xaxis.set_major_locator(mdates.MonthLocator(bymonth=range(1, 13, 4)))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m"))
ax.grid(True,axis="both",color="w", linestyle="dotted", linewidth=0.8)
ax.plot(x,y,marker="o",color="green")
plt.show()
plt.close()
新型コロナウイルスの感染拡大を受けて2020年の1月ごろから
緊急事態宣言の解除(5月25日)まで、大幅に収益が減っていることが分かる。
なお、図を保存したければ、Google Driveのマウントを行った上で、plt.savefig
を使ってパスを指定し保存すれば良い。
備考¶
あらかじめ興味のあるデータ,分類・属性等がわかっている場合は上記のコードの対応するIDなどを変更すればよいし
コードを拡張して、データ,分類・属性等の一覧表などを適宜表示しながら、特定のキーワードを含むものに絞ってデータを取得したりもできる。
ちなみに、GoogleColabで提供されているコードスニペット(テンプレートのようなもの)を用いることで、
プルダウンでデータ,分類・属性等を選んでプロットする、といったように
Google Colab.上で自分だけのe-Stat分析ツールを作ることもできる(最終課題で取り組むのも良い)。