はじめに
こんにちは、Webスクレイピングに関して、いつもお世話になってます。
Python3、Requests、Beautifulsoup4の組み合わせは、大変便利なのですが、Yahooログインの様に、Javascriptで動的に要素を書き換えていくサイトは、requestsでは対応できない様です。
Seleniumの仕組みや検証については、詳しい方にお願いするとして^^;、実際にログインして、(好みと既存のソースとの兼ね合いで)requestsへセッションを渡すところまで実装してみました。
部分的には他の記事が詳しいのですが、古かったりまとまってるものが見つからなかったので、ご参考になれば。。
環境の準備から
- Windows10Pro 64bit
- Python 3.6.1
- PhantomJS v2.1 Download (Windows / Mac OS X / Linux 64-bit)
> pip install requests
> pip install beautifulsoup4
> pip install selenium
> pip list --format=columns
beautifulsoup4 4.6.0
requests 2.18.1
selenium 3.5.0
(…他省略)
サンプルコード
User-Agent等、HttpRequestヘッダに設定するブラウザはご自由に。
Python不慣れなのはご容赦ください。
# -*- coding: utf-8 -*-
import logging
import time
from bs4 import BeautifulSoup
import requests
from selenium import webdriver
import os.path
_dir = os.path.dirname(os.path.abspath(__file__))
def create_session():
s = requests.Session()
s.headers.update({
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "ja,en-US;q=0.7,en;q=0.3",
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0"
})
return s
def yahoojp_session(target_url, login_id, password):
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "ja,en-US;q=0.7,en;q=0.3",
"Connection": "keep-alive",
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0"
}
cap = webdriver.DesiredCapabilities.PHANTOMJS
for key, val in headers.items():
cap["phantomjs.page.customHeaders." + key] = val
cap["phantomjs.page.settings.userAgent"] = headers["User-Agent"]
try:
# <class 'selenium.webdriver.phantomjs.webdriver.WebDriver'>
driver = webdriver.PhantomJS()
except Exception as e:
logging.error(e)
return None
# クッキーを先に取得する
driver.get(target_url)
bs4 = BeautifulSoup(driver.page_source, "html5lib")
login_url = bs4.find("a", attrs={"id": "msthdLogin"})["href"]
driver.get(login_url)
time.sleep(1)
driver.find_element_by_name("login").send_keys(login_id)
driver.find_element_by_name("btnNext").click() # 次へボタン
time.sleep(1)
driver.find_element_by_name("passwd").send_keys(password)
driver.find_element_by_name("btnSubmit").click() # ログインボタン
time.sleep(1)
# driver.save_screenshot(_dir + "/login.png") # ログイン済みを画像で確認できます
# セッション情報をrequestsに移す
s = create_session()
for c in driver.get_cookies():
s.cookies[c["name"]] = c["value"]
driver.close()
return s
if __name__ == '__main__':
s = yahoojp_session("対象のURL", "ヤフーID", "ヤフーパスワード")
こちらの部分で、Selenium + PhantomJSのヘッドレスブラウザにて、クッキーの取得と実際にヤフーへアクセスしてログイン画面へのURLを取得しています。Parserは僕はbs4しか知らないです。(User-Agentによっては、要素ごと無くなるのでご注意)
driver = webdriver.PhantomJS()
# クッキーを先に取得する
driver.get(target_url)
bs4 = BeautifulSoup(driver.page_source, "html5lib")
login_url = bs4.find("a", attrs={"id": "msthdLogin"})["href"]
PhantomJS?では、実際にブラウザにする動作をコーディングします。
その都度、画像でブラウザの状態を確認できて便利ですし、
非常に仕様変更に強いと思います。
driver.get(login_url)
time.sleep(1)
driver.find_element_by_name("login").send_keys(login_id)
driver.find_element_by_name("btnNext").click() # 次へボタン
time.sleep(1)
driver.find_element_by_name("passwd").send_keys(password)
driver.find_element_by_name("btnSubmit").click() # ログインボタン
time.sleep(1)
# driver.save_screenshot(_dir + "/login.png") # ログイン済みを画像で確認できます
このまま、webdriver(Selenium)+ Parserでスクレイピングして問題ないと思いますが、自分はrequests + BeautifulSoupの方が便利なので、セッション情報を渡してます。
# セッション情報をrequestsに移す
s = create_session()
for c in driver.get_cookies():
s.cookies[c["name"]] = c["value"]
driver.close()
return s
まとめ
ヘッドレスブラウザについて、勉強不足です…。
(Requestsの設定で解決できないか悩んだり、JS追ってみたり、mechanizeやSeleniumとSelenium-Requestsの違いで混乱したり、あとPhantomJSでなくても良いと思います)
ですが、ログイン等出来れば他はそれほど問題にならないので、非常に使えると思います。
参考資料
PythonでさくっとWebスクレイピングする (JavaScript読み込みにも対応しつつ)
Seleniumアレルギーのための処方箋
Requests: 人間のためのHTTP > API Document