渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きくなれるように。。。 ※所属団体とは一切関係がありません

Pythonでログインサイト先のHTMLをパースする


前回記事からの続きです。
最低限の機械学習の知識を手に入れるため勉強中。

前回は非ログインサイトのHTMLをパースしましたが、今回はログインサイトをパースします。 その際、ポイントとなるのがセッションを保存したままサイトにアクセスしないとログイン情報が保持されないという点です。

そこで登場する便利ライブラリがRequestsです。

pip3 install requests

いつものようにpip3でインストールしておきます。
Requestsのドキュメントはコチラ

本書に登場するサンプルの通り、ログイン - 作詞掲示板(uta.pw) こちらのサイトにPythonからログインしてみます。最終的には自分のマイページURLに表示されるお気に入りリストを取得します。

ログイン処理

ログイン時にPOSTでログイン情報をサーバーに送っている部分をまずHTMLソースで確認します。

<form action="users.php?action=login&amp;m=try" method="post">
    <table>
        <tr><td>ユーザー名</td><td><input id="user" name="username_mmlbbs6" type="text" size="12" value=""/></td></tr>
        <tr><td>パスワード</td><td><input id="pass" name="password_mmlbbs6" type="password" size="12" /></td></tr>
        <tr><td></td><td><input type="submit" value="ログイン" size="8" /></td></tr>
    </table>
    <input type="hidden" name="back" value="index.php" />
    <input type="hidden" name="mml_id" value="0" />
</form>

上記サイトでは、このようなソースになっています。

必要なのは各送信情報のname(キー)名です。
※ユーザー名であればusername_mmlbbs6、パスワードであればpassword_mmlbbs6がキーになります

これらの情報を元にログイン情報をPythonで作成し、接続してみます。

アクセスURL(変数url_login)は、ベースURL + フォームのaction属性値を組み合わせた文字列です。

ベースURL : http://uta.pw/sakusibbs/
フォームのaction属性値 : users.php?action=login&m=try
アクセスURL : http://uta.pw/sakusibbs/users.php?action=login&m=try

# ログイン情報を作成
login_info = {
    "username_mmlbbs6": "ユーザーネーム",
    "password_mmlbbs6" : "パスワード",
    "back":"index.php",
    "mml_id":"0"
}

# セッションスタート
session = requests.session()

# POSTでログインURLに送信
url_login = "http://uta.pw/sakusibbs/users.php?action=login&m=try"

# 成功すればログイン先のページのHTMLが返却される
res = session.post(url_login, data=login_info)

ログインが成功しているかどうかは、ログイン先のページのソースを見て条件を確認します。

本サイトでは以下のようにログインしたユーザーを表示するソースがあるため、この要素が存在すればログイン済みと判定できます。

<span class="islogin"><a href='users.php?user_id=【ユーザーID】'>[Hogehogeさんのマイページ]</a></span>

よってBeautifulSoupでHTMLをパースし、ログイン条件をチェックします。

# ログインページのHTMLをBeautifulSoupに渡してパース
soup = BeautifulSoup(res.text, "html.parser")

# ログイン済みチェック
a = soup.select_one(".islogin a")
if a is None:
    print("ログインしていないのでここで終了")
    quit()

※BeautifulSoupによるHTMLパースについては前回記事を参考にしてください。

マイページURLを取得

ログイン直後は以下のURLです。 http://uta.pw/sakusibbs/index.php

マイページURLは以下のようにクエリパラメータで管理されています。 http://uta.pw/sakusibbs/users.php?user_id=番号

このパラメータを取得するため先のパース結果からマイページURLを生成します。

# マイページURLを生成
url_mypage =  urljoin(url_login, a.attrs["href"])
# マイページを取得
res = session.get(url_mypage)
  • http://uta.pw/sakusibbs/users.php?action=login&m=try
  • users.php?user_id=番号

urljoin関数がとても便利で、上記2つのURLをイイ感じにくっつけてくれて、以下のURLにしてくれます。

http://uta.pw/sakusibbs/users.php?user_id=番号

最後にマイページのパース

マイページURLが取得できたら再度そのHTMLを取得し、おなじみのBeautifulSoupでパースします。

#マイページへアクセス
res = session.get(url_mypage)

# マイページHTMLをパース
soup = BeautifulSoup(res.text, "html.parser")
links = soup.select("#favlist li > a")
for a in links:
    href = a.attrs["href"]
    title = a.get_text()

ほぼ本書通りですが、僕なりのコメントを残したサンプルコードをアップしておきます。

【サンプルコード】

余談

サンプルに登場するraise_for_statusについて調べておきます。
公式ドキュメントに説明されていますが、ステータスコードが200以外の場合(404等)、例外を発生させることが出来るようです。
レスポンスを受け取っている箇所に仕込んでおいた方がデバッグ作業は捗ると思われます。

最後に

ログイン済みサイトのパース方法が分かって面白かったです。
しかし2段階認証ページはこの方法だと歯がたたないんだろうなって思いました。

環境

  • macOS 10.12.6
  • Python3.6.3
  • BeautifulSoup4 4.6.0
  • Requests (2.18.4)

参考サイト