この記事は阿部寛 Advent Calendar19日目の記事です。
※Webの高速化1は専門外なのでできません。ご了承ください。
阿部寛さんのHPを見て思ったこと
ご存知の通り2、阿部寛さんのホームページは、高速に画面遷移するホームページです。サクサク動くのでストレスを感じません。ユーザ体験として素晴らしいです。
ですが、阿部寛さんのホームページで1つだけ残念だと思ったことがありました。それはリンク切れです。
阿部寛さんのホームページでは、サイトのいたるところに過去の出演作品ページへの外部リンクが貼られています。しかし、番組や映画が終わって一定期間が経つと、リンク先のページが閉鎖になってしまいます。そのため、自然とリンク切れが増えていってしまいます。
「このドラマ懐かしいなー」と思ってクリックしたリンク先が「404 Not Found」とか表示されると、ちょっと残念ですよね。これはユーザ体験としてはよろしくないわけです。
スクレイピングしてリンク切れをチェックする
今回は阿部寛さんのホームページをスクレイピングすることで、リンク切れになっているリンクを探してみることにしました。
Pythonでのスクレイピングではrequests
ライブラリが便利なので、こちらを使ってスクレイピングしていきます。
手順
1. 仮想環境の作成(任意)
requests
ライブラリをインストールするため、環境を汚したくない方はPythonの仮想環境を作成した方が良いと思います。仮想環境の作成方法はここでは割愛します。
2. ライブラリのインストール
requestsライブラリ
今回使用するrequests
ライブラリは標準では使用できませんのでpip
でインストールする必要があります。
$ pip install requests
lxmlライブラリ
htmlのパースに使用するlxml
ライブラリもpip
でインストールします。
$ pip install lxml
libxml2,libxsltのインストール(Macの場合)
lxml
ライブラリの内部で使用しているモジュールをインストールします。Macの場合はhomebrewでインストールできました。
$ brew install libxml2 libxslt
3. スクレイピングするコードの作成
3-0. 完成品
完成したソースはこちらになります。
こちらを実行すると以下のような出力が得られます。
$ python checklink.py
(前略)
リンク切れしているURLがあります
http://www.tbs.co.jp/e-housoku/
http://www.tbs.co.jp/mayonaka/
http://www.tbs.co.jp/mlc/
http://www.bunkamura.co.jp/cocoon/lineup/shosai_09_coast.html
http://www.bunkamura.co.jp/cocoon/lineup/shosai_08_dogen.html
http://www.tsuka.co.jp/kitaku/butai/monte2002/poster.htm
http://www.rlsm.bias.ne.jp/%7Esong/shashin/shashin-kan.htm
http://www.tsuka.co.jp/kitaku/butai/monte2002/poster3.html
http://www.tsuka.co.jp/kitaku/butai/monte2002/arasuji.html
http://www.s-woman.net/bebunko/016/index.html
ライブラリの使い方を中心に説明します。
3-1. ページの取得
requests.get(url)
関数を使用することでページ情報を取得できます。
今回はホームページ内をクローリングする関係で、Sessionオブジェクトのgetメソッドを使用しています3が、取得できる内容は同じです。
session = requests.Session()
response = session.get(start_url)
3-2. 取得情報のパース
get(url)
で取得した内容をパースします。htmlの情報はresponse.content
に記録されていますので、これをhtmlとして解釈し、パースします。
root = lxml.html.fromstring(response.content)
3-3. 相対URLの絶対URL化
requests.get(url)
(またはsession.get(url)
)の引数にはスキームから始まる絶対URLを指定する必要があります。
今回はページ内のリンクをクローリングするので、ホームページ内遷移を記述した相対URLに対してもページの取得を行います。そのために相対URLを絶対URLに変換します。
絶対URLへの変換はパースして得られたオブジェクトのmake_links_absolute()
メソッドを使うと簡単にできます。
root.make_links_absolute(response.url)
3-4. 要素・属性を取得する
パースして得られたオブジェクトでは、CSS使われるセレクタでHTML要素を取得できます。また、HTML要素のオブジェクトでは.属性名
で属性にアクセスすることができます。このあたりの書き方はjQueryやJavaScriptの書き方に似ており理解しやすいです。
今回はページ内のリンクを全て取得したいため、セレクタa[href]
に該当するオブジェクトのhref
属性を取得する処理を書きました。
# href属性を持つ<a>要素の取得
for atag in root.cssselect('a[href]'):
# href属性の取得
url = atag.get('href')
3-5. ステータスコードのチェック
requests.get(url)
で得られたオブジェクト内のstatus_code
をチェックすることで、HTTPステータスコードを確認できます。
今回はとりあえず400以上を対象にしました。
if res.status_code >= 400:
# リンク切れだった場合の処理を記述
yield url
3-6. レスポンススピードのチェック(おまけ)
阿部寛さんのHPが爆速なのに、外部リンクのレスポンスが遅いとストレスを感じかねないので、レスポンスが遅いページも一応チェックしておきます。4
レスポンスの速度はレスポンスオブジェクトのelapsed.total_seconds()
で確認できます。
elif res.elapsed.total_seconds() > 1:
# レスポンスが遅い場合の処理を記述
print("このリンク先は遅い:" + url)
感想
requests
ライブラリが便利で助かりました。スクレイピングでは非常に使いやすいライブラリだと思います。
外部リンクのリンク切れはレガシーなHPに限らず発生しうる問題ですが、リンクをいちいちクリックしてチェックするのは効率が悪いです。コード化する、専用のツール5を使うなどして管理の手間を省くのが大事だと思いました。