seleniumを使ってスクレイピング

おはこんばんにちは。マタキチです。
フィットネスをはじめたマタキチですが、あんまり運動しなくなって久しい体には全然フィットがネスしない。もうアンフィットがすごい。20分のHIITで翌日筋肉痛。あちゃーっつって。追い込みすぎたかなって。酸素カプセルに入りたい。そんな今日この頃です。

pythonを独学ですが勉強中です。スクレイピングを勉強しているので忘備録的に書きますが悪しからず。

seleniumを使ったスクレイピング

前回の内容でseliniumの環境構築は完了。今回はseleniumを利用してスクレイピングして行こうと思います。seleniumは複数ブラウザに対応していますが、今回はGoogle Chromeで行こうかと思います。

#必要なドライバー、モジュールをインポート
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

#ログインに必要な情報とURL
USER = "JS-TESTER"
PASSWORD = "ipCU12ySxI"
FAV_USER_ID = 32
SNS_URL = "https://uta.pw/sakusibbs/"

#ログイン画面を開く
driver = webdriver.Chrome()
url_login = SNS_URL + "users.php?action=login"
driver.get(url_login)

#ログイン画面の入力欄に必要な情報を入力してログイン
def form_post(frm, d):
   for field, value in d.items():
       e = frm.find_element_by_name(field)
       e.clear()
       e.send_keys(value)
   frm.submit()
   WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".islogin")))
frm = driver.find_element_by_css_selector("#loginForm form")
form_post(frm, {"username_mmlbbs6": USER, "password_mmlbbs6": PASSWORD})

#ログインできているかの確認。ログインできていなかったら終了
e = driver.find_element_by_id("bbsheader")
html = e.get_attribute("innerHTML")
if html.find("action=logout") < 0:
   print("ログインできていません")
   quit()
print("ログインしました")
time.sleep(1)

#マイページの表示
url = SNS_URL + "users.php?user_id=" + str(FAV_USER_ID)
driver.get(url)

#作品一覧を取得
sakushi_list = []
links = driver.find_elements_by_css_selector("ul#mmlist li a")
for a in links:
   href = a.get_attribute('href')
   title = a.text
   sakushi_list.append((href, title))
print("作品一覧を{0}件取得しました。".format(len(sakushi_list)))

#一気にお気に入りをつける
for href, title in sakushi_list:
   print(title)
   driver.get(href)
   try:
       #お気に入りボタンをクリック
       e = driver.find_element_by_id("fav_add_btn")
       e.click()
       #お気に入りを解除
       e = driver.find_element_by_id("fav_remove_btn")
       e.click()
       print("good!")
   except:
       #すでにお気に入りされていたら
       print("すでにgoodでした")
#負荷軽減のため
   time.sleep(1)

すごく長くなりました。もっと短くできないもんかなと考えていますが、今の僕腕では難しい。誰かヘルプミー、ビリーブミー。しかしプログラムは動きます。ただし自動でChromeが起動します。headlessでしたいなと思いました。コンソールから起動すると結果も無事に表示されました。

スクリーンショット 2019-10-04 22.14.24

基本的にすでに登録されてましたね。誰だよ登録したやつ・・・

コード解説

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

1段目から、webdriverはインスタンスを作成して、Webブラウザを操作するためのドライバーです。今回はwebdriver.Chrome()とすることでgooglechromeのブラウザが操作できるようにしています。seleniumには要素を見つけるための関数が用意されています。find_elements_byやfind_element_byなどです。これらを使用するために2段目をインポートします。3段目と4段目は組み合わせでseleniumの待機処理するため。待機処理には二つあって、暗黙の待機処理(implicit waits)と明示的な待機処理(explicit waits)この違いは画面が静的か動的かの違いだと認識していますが・・・つまり、スクロールすることで読み込まれていくサイトとかですかね。要素が読み込まれるまで待機するとかが使用できます。

#ログイン画面の入力欄に必要な情報を入力してログイン
def form_post(frm, d):
   for field, value in d.items():
       e = frm.find_element_by_name(field)
       e.clear()
       e.send_keys(value)
   frm.submit()
   #ログインに必要な情報を送信した10秒待機
   WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".islogin")))
frm = driver.find_element_by_css_selector("#loginForm form")
form_post(frm, {"username_mmlbbs6": USER, "password_mmlbbs6": PASSWORD})

最初に設定したUSERとPASSOWRDを入力してログインする部分です。frm変数にcssがloginForm formの部分(ユーザ名、パスワードを入力する座標がある場所)を代入してdef form_postに代入しています。もう一つの引数にはログインに必要な情報を辞書型で渡しています。submit()で送信してWebDriverWaitでcssが.isloginを確認するまで最大で10秒待機する流れです。ログインすると.isloginが確認できるので。

#ログインできているかの確認。ログインできていなかったら終了
e = driver.find_element_by_id("bbsheader")
html = e.get_attribute("innerHTML")
if html.find("action=logout") < 0:
   print("ログインできていません")
   quit()
print("ログインしました")
time.sleep(1)

ログインできているかの確認をしています。ヘッダー(bbsheader)を取得して、ログアウトボタンがある場合はログインできていることになります。ログアウトボタンはaction=logoutという文字が含まれるのでこれがあるかないかで判断しています。

肝の部分はこれくらいかと思います。残りの詳しい解説は割愛させていただきましょう。なんてったって忘備録だから。

まとめ

seleniumを使用してGoogleChromeから会員制のページにログインして作品にお気に入りをつけるプログラムを書きました。待機処理が2種類あることとその違い、各要素を取得する関数の使い方、学んだことはあったけど最後に一つ。これをheadlessにしたいんじゃ!!!!!!!!!!!!

この記事が気に入ったらサポートをしてみませんか?