Selenium(Python)を使ってWebスクレイピング

　Pythonを使用した機械学習等を行うシステムを構築したりすると、インターネット上で公開されているオープンデータと言われる特許などの制御メカニズムの制限なしで利用できるデータを利用したりします。
もちろん、取得したデータを利用して、効率よくモデルを更新したりするのですが、自動化したい場合があります。
今回は、俗にいうWebスクレイピングで[Selenium](https://selenium-python.readthedocs.io/)を使用してみます。

# 注意事項
機械的なダウンロードが禁止されていることもしばしばありますので、アクセス対象サイトの利用規約をよく読んでください。

# Webスクレイピングライブラリの代表的なもの

調べた限りだと、いくつか選択枠がありますが、今回は使ったことがないのでSeleniumを使用してみます。
私の認識では、SeleniumはWebの画面操作を自動化するツールなのですが、画面操作の自動化をスクレイピングに利用してしまうのです。

- lxm
- Requests / BeautifulSoup
- Scrapy
- Selenium（今回使用）

# 環境

Seleniumとブラウザ（今回はChrome）の間に WebDriverといわれるドライバが必要になります。

- Windows 10 64bit
- Google Chrome (78.0.3904.108)
- MacOSX x86_64
- Anaconda(3.6)

## Seleniumインストール

Python は Anacondaを使用しているので、condaでインストールしておきます。

```
conda install selenium
```

## WebDriverインストール

WebDriverは、バイナリファイルをhttp://chromedriver.chromium.org/downloadsからダウンロードしてきて
Pathが通る場所にコピーする方法と、pipでインストールする方法があります。
今回は、pip(conda)でインストールします。

```
conda install chromedriver-binary
```

# サンプル実行

環境ができたので、まずはじめに以下chromedriverサイトのサンプルを実行してみます。
内容てきには、グーグルサイトを表示して、ChromeDriverを検索して、５秒スリープして終了といった内容。
http://chromedriver.chromium.org/getting-started

```test1.py
import time
from selenium import webdriver

driver = webdriver.Chrome()
driver.get('http://www.google.com/');
time.sleep(5) # Let the user actually see something!
search_box = driver.find_element_by_name('q')
search_box.send_keys('ChromeDriver')
search_box.submit()
time.sleep(5) # Let the user actually see something!
driver.quit()
```
```
python test1.py
```

実行されるとブラウザが起動して、ChromeDriverを検索はじめます。ブラウザに「自動テストソフトウェアによって制御されています。」って表示されてる！
そして、簡単だ！

<img width="936" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215344/9cfa329e-10b1-8af0-bae8-a4e3ac2016a9.png">

# オープンデータの取得サンプル
サンプルが起動するだけで終了では寂しいので、下記サイトからCSVをダウンロードしてくるサンプルを作ってみます。

- 指定URL（今回は特定URLではなくXXXXXとぼかしました）
- 日次データ(CSV)のリンク先のCSVをダウンロード(C:\projectに保存)

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

options = Options()
options.add_argument('--headless')

download_dir = 'C:\\project'
prefs = {}
prefs['download.prompt_for_download'] = False
prefs['download.directory_upgrade'] = True
prefs['download.default_directory'] = download_dir

options.add_experimental_option('prefs', prefs)

driver = webdriver.Chrome(chrome_options=options)

driver.get('https://XXXXXXXXXXXXXXXXXXXXXX');
time.sleep(5) # Let the user actually see something!
url = driver.find_element_by_partial_link_text("日次データ(CSV)")


driver.command_executor._commands["send_command"] = (
    "POST",
    '/session/$sessionId/chromium/send_command'
)
params = {
    'cmd': 'Page.setDownloadBehavior',
    'params': {
        'behavior': 'allow',
        'downloadPath': download_dir
    }
}
driver.execute("send_command", params=params)

driver.get(url.get_attribute('href'));

time.sleep(5) # Let the user actually see something!
driver.quit()
```

## ブラウザを非表示で実行

コードの以下の部分で、ブラウザ起動時にオプションで--headlessを渡すことでブラウザを非表示にします。

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

options = Options()
options.add_argument('--headless')
options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(chrome_options=options)
```

## ダウンロードファイルの保存先の指定

コードの以下の部分で、ダウンロードファイルの保存先の指定します。

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

options = Options()
download_dir = 'C:\\project'
prefs = {}
prefs['download.prompt_for_download'] = False
prefs['download.directory_upgrade'] = True
prefs['download.default_directory'] = download_dir
options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(chrome_options=options)
```

## --hedlessの場合は、追加でダウンロードファイルの保存先の指定

--hedlessの場合は、追加でダウンロードファイルの保存先の指定するコードが必要になります。

```
driver.command_executor._commands["send_command"] = (
    "POST",
    '/session/$sessionId/chromium/send_command'
)
params = {
    'cmd': 'Page.setDownloadBehavior',
    'params': {
        'behavior': 'allow',
        'downloadPath': download_dir
    }
}
driver.execute("send_command", params=params)
```

これで、ダウンロードが完了します！簡単。

# まとめ
 複雑な事をやるとコードが増えそうですが、Seleniumを使ったことがある人とかならばWebスクレイピングにSeleniumを選択する事もありな気がします。
欠点としては、ブラウザ・ドライバとインストールするものが増えるぐらいでしょうかね。
ブラウザ上で、作成したSeleniumスクリプトが動けば便利そうですが、まだ不完全なようです。

# 複雑なことをやるのに参考になりそうなサイト
- https://www.seleniumqref.com/