[図解]0から学ぶ、Python+ seleniumでのWebスクレイピング

# はじめに
Pythonのseleniumモジュールを使用して、Chromeを操作する方法をまとめています。
Pythonの基礎がわかる人であれば理解できる内容にしています。
実在するサイトを用いて操作手順を記載しています。

注意事項として、変なプログラム（連続してリクエストを投げるなど）を実行してしまうとWebサイトに負荷がかかる可能性があります。また、DoS攻撃と判断される可能性もあります。
プログラムを実行する前には間違いがないか注意してください。

# seleniumインストール
インストール方法は以下を参照してください。

[selenium向け] ChromeDriverをpipでインストールする方法（パス通し不要、バージョン指定可能）
https://qiita.com/hanzawak/items/2ab4d2a333d6be6ac760

[超図解]AnacondaインストールからPythonプログラム実行までの手順（Windows版）
https://qiita.com/hanzawak/items/9dedcde1a43aa7d0e71a

# selenium概要
seleniumはWebサイトのテストを自動化するためのツールです。
以下の流れでブラウザを操作します。

1. 操作したいブラウザを開く
2. 操作したいページを開く
3. 操作したい要素を確認する
4. 操作したい要素を指定する
5. 操作したい要素を操作する

# selenium基本操作
## 0. seleniumインポート
```python
from selenium import webdriver
import chromedriver_binary    # ChromeDriverをpipでインストールした場合はchromedriver_binaryもインポートしてください
```

## 1. 操作したいブラウザを開く
まずはブラウザを開きます。

```python
driver = webdriver.Chrome()
```

以下のような画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/806187f4-a277-ece6-3cf9-6695f14ac091.png)

## 2. 操作したいページを開く
操作したいページを開きます。今回は楽天を開きます。

```python
driver.get("https://rakuten.co.jp")
```

楽天が開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/f50f7093-d3ac-43bf-5726-bc47f513a76b.png)


## 3. 操作したい要素を確認する
「キーワードから探す」の部分に文字を入力してみたいと思います。
「キーワードから探す」の要素を確認するには、ページのソースを見る必要があります。
Chromeの場合は開発者ツールを用いることで簡単に確認できますので、その使用方法を記載します。

#### I. F12キーをクリックする
画面右側に開発者ツールが開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/ab21550d-2214-cec5-434c-170cc120f566.png)

#### II. マウスカーソルボタンをクリックする
以下の赤丸部分を1回クリックしてください。するとマウスカーソルボタンが青色になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/2fe99968-95b8-f9f6-3cad-3483fb9b863c.png)

#### III. 要素を確認したい箇所をクリックする
マウスカーソルボタンが青色の状態の時に、左側の画面で要素を確認したい箇所をクリックしてください。
今回はキーワードを入力したいので、「キーワードから探す」の部分をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/ea7eae15-9055-2533-fbdb-a5f8255e4402.png)

#### IV. ソースを確認する
画面右側の一部が青くハイライトされています。
この部分が「キーワードから探す」のソースです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/77f39b64-ad4c-fb81-7051-c86f6c021b15.png)

#### V. 要素を確認する

以下は「キーワードから探す」のソースの部分です。

```html

<input type="text" value="" name="sitem" size="40" class="searchInput" id="sitem" placeholder="キーワードから探す" autocomplete="off" maxlength="2048">
```

seleniumで操作する際に使用できる要素としては以下がありました。

- name="sitem"
- class="searchInput"
- id="sitem"

上記以外にもXPathというXMLの特定の部分を指定する方法があります。
（XPathはソースに表示されません）
確認方法は、画面右側の青くハイライトされた部分を右クリックし、Copy→Copy XPath で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/8e590bd5-9e09-6eac-b8c7-03746b72fa26.png)

コピーした内容は `//*[@id="sitem"]` でした。

## 4. 操作したい要素を指定する
前の項目で取得できた以下4つの要素のいずれかを用いて、操作したい要素を指定します。

- name="sitem"
- class="searchInput"
- id="sitem"
- XPath -> //*[@id="sitem"]

今回はclassで要素を指定します。

```python
x = driver.find_element_by_class_name('searchInput')
```

## 5. 操作したい要素を操作する
「switch lite」という文字を入力する場合は以下のようにします。

```python
x.send_keys('switch lite')
```

以上がseleniumを使用する際の基本操作です。
要素を確認して、指定して、操作する、というだけの流れです。

# selenium応用
まずはselenium基礎のコマンドについて、もう少し他の方法がありますのでその説明をします。

## 要素指定と要素の操作を1つにまとめる
「4. 操作したい要素を指定する」と「5. 操作したい要素を操作する」は２つの処理を１行にすることができます。
以下のように記載すると、「キーワードから探す」を指定して、「switch lite」を入力できます。

```python
driver.find_element_by_class_name('searchInput').send_keys('switch lite')
```

## class_name以外の要素の指定
「4. 操作したい要素を指定する」ではclass_nameを指定しましたが、name, id, XPathでは以下のようにして指定ができます。

```python
driver.find_element_by_name('sitem').send_keys('switch lite')
driver.find_element_by_id('sitem').send_keys('switch lite')
driver.find_element_by_xpath('//*[@id="sitem"]').send_keys('switch lite')
```

# seleniumを使用した色々なブラウザ操作
## 入力されている文字を消す
「キーワードから探す」に入力されている文字を消す方法です。
class_name, name, id, xpathの順で記載しています。

```python
driver.find_element_by_class_name('searchInput').clear()
driver.find_element_by_name('sitem').clear()
driver.find_element_by_id('sitem').clear()
driver.find_element_by_xpath('//*[@id="sitem"]').clear()
```

## ボタンのクリック
検索ボタンをクリックしてみたいと思います。
前の手順と同じように開発者ツールから検索ボタンの様子を確認すると、`class=searchBtn`でした。
そのため`class_name`で`searchBtn`を指定し、末尾に`click()`をつけるとボタンをクリックできます。

```python
driver.find_element_by_class_name('searchBtn').click()
```

## 値段の一覧を取得
いつも通り開発者ツールからマウスカーソルボタンを押して、今度は値段の部分をクリックします。
すると`class=important`であることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/f994b0eb-00a5-c933-fc36-88fb5234b83c.png)

テキストの情報を取得するには以下のように記載します。末尾が`text`になります。

```python
driver.find_element_by_class_name('important').text
```

これを実行すると「21,978円」と表示されます。
次に2件目の値段を取得するために、開発者ツールからマウスカーソルボタンを押して、2件目の値段の部分をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/edd2e1ea-4df1-75c0-9a73-262096aa27a9.png)

まさかの２件目も`class=important`でした。
この場合、今までの方法ですと２件目の値段が取得できません。
どうやって解決するかというと、`element`を`elements`というように末尾に`s`をつけます。そして`.text`の前を`[0]` `[1]` といったようにします。
以下のようにすると値段の１件目、２件目、３件目が取得できます。

```python
driver.find_elements_by_class_name('important')[0].text
driver.find_elements_by_class_name('important')[1].text
driver.find_elements_by_class_name('important')[2].text
```

なぜか楽天の検索結果には「1〜45件」と記載されていますが、数えてみると48件表示されていますので、以下のようにすると`prices`に全ての価格を記録できます。

```python
prices = []
for i in range(48):
    prices.append(driver.find_elements_by_class_name('important')[i].text)

print(prices)
```

楽天が修正する可能性を考えると以下のようにtry-exceptを使用した方が安全かもしれません。

```python
prices = []
i = 0

while True:
    try:
        prices.append(driver.find_elements_by_class_name('important')[i].text)
        i += 1
    except:
        break
```

## プルダウンメニューの操作
価格のソートをしてみようと思います。
プルダウンメニューを操作する時には、「要素」と「変更したいvalue」の情報が必要になります。

「要素」はいつものように「並べ替え」の横の「標準」の部分で調べると、`class=sorting`ということがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/48755911-0673-057c-4720-614a5dd5002d.png)

「変更したいvalue」は`class=sorting`の左側の三角ボタンを押して詳細を表示し、その中から`value`を選択します。
今回は「価格が安い順」にしてみたいので`value`は`https://search.rakuten.co.jp/search/mall/switch+lite/?s=2`ということになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/a26386e0-6d10-e1e8-7e4a-4c78d0a8d245.png)

「要素」と「変更したいvalue」の情報が入手できましたのでプルダウンメニューを操作します。
以下のように記載すると「価格が安い順」が選択されます。
なお`Select`をインポートする必要があります。

```python
from selenium.webdriver.support.ui import Select

price_sort = driver.find_element_by_class_name('sorting')
price_sort_select = Select(price_sort)
price_sort_select.select_by_value('https://search.rakuten.co.jp/search/mall/switch+lite/?s=2')
```

## チェックボックスを操作
画面左側の「送料無料」のチェックボックスにチェックを入れたいと思います。
その場合はいつも通り要素を確認し、末尾に`click()`を記載します。

```python
driver.find_element_by_name('f').click()
```

チェックが付いた状態で再度上記を実行するとエラーになります。
そのため以下のようにしても良いと思います。

```python
try:
    driver.find_element_by_name('f').click()
except:
    print('checked')
```

## 前のページに戻る・先のページに進む

```python
driver.back()    # 前のページに戻る
driver.forward() # 先のページに進む
```

## URLの取得
現在表示しているページのURLを取得できます。

```python
driver.current_url
```

## ページタイトルの取得
現在表示しているページのタイトルを取得できます。

```python
driver.title
```

## マウス操作をする
画面上部の「買い物かご」にマウスカーソルを合わせてみようと思います。
まずいつも通り「買い物かご」の要素を確認すると`class=basket-link`でした。
この情報を用いて以下のように記載して実行します。

```python
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://rakuten.co.jp")

actions = ActionChains(driver)
actions.move_to_element(
    driver.find_element_by_class_name("basket-link")
).perform()
```

すると「買い物かご」の部分が色が薄くなっていると思います。
自分でマウスカーソルをいじってみるとわかりますが、「買い物かご」の上にマウスカーソルをあてると色が薄くなります。
マウスカーソルは表示されないですが、カーソルがあたった時と同じ動作になっていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/494d5eb4-9c92-553f-bad6-d5a6bcf2387c.png)

## スクリーンショットを撮る
同じフォルダにスクリーンショットが保存されます。

```python
driver.save_screenshot('test.png')
```

## 画面をスクロールする

```python
driver.execute_script("window.scrollTo(0, 1000);") 
```

## DoS攻撃と間違われないようにするために
サイトに負荷を与えないように、またDoS攻撃と間違われないようにするために、処理の途中にsleepをはさむのも良いと思います。

```python
from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get("https://rakuten.co.jp")
time.sleep(5)
driver.find_element_by_class_name('searchInput').send_keys('switch lite')
time.sleep(5)
driver.find_element_by_class_name('searchBtn').click()
```

## ブラウザを閉じる

```python
driver.quit()
```