Pythonでyahooにログインする

## はじめに
こんにちは、Webスクレイピングに関して、いつもお世話になってます。
Python3、Requests、Beautifulsoup4の組み合わせは、大変便利なのですが、Yahooログインの様に、Javascriptで動的に要素を書き換えていくサイトは、requestsでは対応できない様です。

Seleniumの仕組みや検証については、詳しい方にお願いするとして^^;、実際にログインして、（好みと既存のソースとの兼ね合いで）requestsへセッションを渡すところまで実装してみました。
部分的には他の記事が詳しいのですが、古かったりまとまってるものが見つからなかったので、ご参考になれば。。

## 環境の準備から
- Windows10Pro 64bit
- Python 3.6.1
- PhantomJS v2.1 [Download](http://phantomjs.org/download.html) (Windows / Mac OS X / Linux 64-bit)

```shell-session
> 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不慣れなのはご容赦ください。

```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によっては、要素ごと無くなるのでご注意）

```python
    driver = webdriver.PhantomJS()

    # クッキーを先に取得する
    driver.get(target_url)
    bs4 = BeautifulSoup(driver.page_source, "html5lib")
    login_url = bs4.find("a", attrs={"id": "msthdLogin"})["href"]
```

PhantomJS？では、実際にブラウザにする動作をコーディングします。
その都度、画像でブラウザの状態を確認できて便利ですし、
非常に仕様変更に強いと思います。

```python
    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の方が便利なので、セッション情報を渡してます。

```python
    # セッション情報を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読み込みにも対応しつつ)](http://qiita.com/beatinaniwa/items/72b777e23ef2390e13f8#comment-8ec96aa8e93ceb9cf3ea)
[Seleniumアレルギーのための処方箋](http://qiita.com/cognitom/items/27b7375bea653b414c8f)
[Requests: 人間のためのHTTP > API Document](http://requests-docs-ja.readthedocs.io/en/latest/api/)