こんにちは、エンジニアのオオバです。

前回記事からの続きです。

あわせて読みたい記事

BeautifulSoupを使ったHTMLパース

最低限の機械学習の知識を手に入れるため勉強中。

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

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

pip3 install requests  

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

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

→11万文字で徹底解説した「DOTweenの教科書」Unityアニメーションの超効率化ツールはこちら

ログイン処理

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

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

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

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

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

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

<GoogleAdsense type='1' />

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

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

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

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

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

<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>  

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

<GoogleAdsense type='1' />

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

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

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

BeautifulSoupを使ったHTMLパース - 渋谷ほととぎす通信

マイページURLを取得

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

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

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

<GoogleAdsense type='1' />

## マイページURLを生成
url_mypage =  urljoin(url_login, a.attrs["href"])  
## マイページを取得
res = session.get(url_mypage)  

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

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

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

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

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

<GoogleAdsense type='1' />

## マイページ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()  

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

【サンプルコード】

uta_favorite.py · GitHub

余談

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

最後に

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

参考サイト

オススメ記事
検証環境