masuTomo’s blog

競技プログラミングの勉強メモです.主にPythonを使用します.数学の記事も書くかもしれません.

Pythonでwebスクレイピング(ログインとデータ取得)

動機

バイクの免許を取ろうと,自動車学校に通うことにした。講習はwebからの予約制であり,今は新型コロナウイルスで大学が休みだったりするらしく,例年より生徒が多いらしい。そこで,予約に空きがでたらすぐに確認・予約ができるようにpythonでwebスクレイピングしてみることにした。

条件

  1. 自動車学校のホームページの予約ページから,idとパスワードを入力してログインする

  2. ログイン先の画面から予約可能枠を取得

  3. 予約可能枠を自分のラインに送信する

  4. 上記の操作を定期的に実行する

自動で予約するところまで作ろうかとも思ったが,変な予約してしまうことのリスクを避けるため,予約状況を送信するにとどめました(大変そうだったからというのもある)。

実装

やり方を調べる

とりあえず,「python webスクレイピング ログイン」などとしてググってみると,いろいろ記事がある。seleniumというのを利用すると簡単らしいということがわかったので,それを利用した。

shimi-dai.com

また,ブラウザ(Google Chrome)にアクセスするためにはchromedriverと呼ばれるものが必要らしく,それをダウンロードしてきて,適当な場所に格納する(そこにパスを通すのを忘れずに)

Downloads - ChromeDriver - WebDriver for Chrome

最新版でいいだろ,と思って適当にやったらエラーがでました。サポートしているchromeのバージョンを確認しておきましょう。(Chromeのヘルプでバージョンを確認したら83,最新です。となっていたのにchromedriverの最新版はchromeのver84をサポートしているようでした。どういうこと?)

ログインする

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

url = "ログインしたいwebページのURL"

# ヘッドレスモードの設定。
# True => ブラウザを描写しない。
# False => ブラウザを描写する。
options = Options()
options.add_argument('--headless')

# Chromeを起動
driver = webdriver.Chrome(executable_path="chromedriverのexeのパスを指定", chrome_options=options)

# ログインページを開く
driver.get(url)

idとパスワードを入力する

まずは,idとパスワードの入力欄を取得してくる必要がある。chromeブラウザでログインページを開いてF12(その他のツールからデベロッパツール)を押すと,ページソースが見れる。 f:id:masuTomo:20200621111220p:plain さらにソースが見えているエリアの左上の矢印ボタンを押しておく。
その状態で,画面左側にマウスカーソルを持っていくと,画面上のアイテムに該当するソースがハイライトされる。 f:id:masuTomo:20200621111246p:plain この方法で入力欄のidなどを調べる。idを指定して,アイテムを取得し,そこに値を引き渡す。

from selenium.webdriver.common.keys import Keys

#入力欄にidを入力する処理
driver.find_element_by_id('idを入力するアイテムのid').send_keys('あなたのid')
driver.find_element_by_id('パスワードを入力するアイテムのid').send_keys('あなたのパスワード')
#ログインボタンをクリックする処理
driver.find_element_by_id('ログインボタンのid').send_keys(Keys.ENTER)

アイテムによってはidが指定されていなかったりという状況もあるので,取得したいアイテムに合わせるメソッドを利用する。classやname属性を指定することもできる。

qiita.com

これで,ログイン後の画面に遷移しているはずである。ただし,ページ読み込みなどに時間がかかる場合があるので念のためこんな感じの処理を入れておく。

from time import sleep
#ページ読み込み待機
sleep(5)

ログイン後画面から予約情報を読み取る

なんだかよくわからないがbeautifulsoupなるものを利用することが多いらしく,真似してみた。

from bs4 import BeautifulSoup

# # soupオブジェクトを作成(ここはよくわかっていないのでおまじないのつもり)
soup = BeautifulSoup(driver.page_source, "lxml")

で,このsoupオブジェクトからページ要素を取得する方法がわからなかったのだが,find,fild_allなどというメソッドが用意されているようで,それを利用すれば,ページ要素からタグを指定して値を取得することができるようだった。 私が調べたいサイトは予約枠がテーブルで書かれており,idが割り振られていなかったため,tdタグとclassを指定して取得した。
ページソースを眺めていると,classがstatus1だと予約可能,status3は自分の予約,という風になっていたので,statsu1を指定して要素を取得することとした。当然,複数の予約可能枠があるので,それをリストに格納することにした。

#予約ページからstatus1(予約可能)の情報を取得
tmp_list = list(str(soup.find_all('td', class_ = 'status1')).split())

そこのタグ内に日付や時間情報も持っていたので,文字列操作でそこを取り出しておいた。

取得した予約可能枠をLINEに送信する

LINEのアクセストークンというものを発行しなければならないらしいが,とても簡単だった。

qiita.com

import requests

#line送信の準備    
lineurl = "https://notify-api.line.me/api/notify"
access_token = '自分のアクセストークン'
headers = {'Authorization': 'Bearer ' + access_token}

message = ’送信したい文字列’
payload = {'message': message}
r = requests.post(lineurl, headers=headers, params=payload,)

定期的に実行する

pythonプログラムを実行するbatファイルを作成して,それをタスクスケジューラから定期的に実行する形にした。
batファイルはこんな感じ

cd C:\Users\username\workspace\pythonファイルのパス
py 実行したいファイル.py

タスクスケジューラの場所は[スタートメニュー]→[Windows管理ツール]→[タスクスケジューラ]