【Selenium】「次ページ」への繰返し移動は、while文を使う

# Tips
##1. While文によるページ遷移の繰り返し処理（うまくいく）

```python:selenium_success.py
# 1ページ目の次のページ（2ページ目）のURLを取得
next_page_url = driver.find_element_by_class_name("js-next-page-link").get_attribute("href")

# 2ページ目から最終ページまでをループ処理する
while len(next_page_url) > 0:
	driver.get(next_page_url)
	#要素がロードされるまでの待ち時間を10秒に設定
	driver.implicitly_wait(10)
	next_page_html = driver.page_source.encode('utf-8')

# 任意の処理の実装コードをここに書く

	next_page_url = driver.find_element_by_class_name("js-next-page-link").get_attribute("href")
else:
	print("\n\n最後のページの処理が終わりました。\n\n")
```


##2.for文によるページ遷移の繰り返し処理（途中で止まる）

```python:selenium_failure.py
# 1ページ目の次のページ（2ページ目）のURLを取得
next_page_url = driver.find_element_by_class_name("js-next-page-link").get_attribute("href")

# 2ページ目から最終ページまでをループ処理する
if len(next_page_url) != 0:
	driver.get(next_page_url)
	#要素がロードされるまでの待ち時間を10秒に設定
	driver.implicitly_wait(10)
	next_page_html = driver.page_source.encode('utf-8')

# 任意の処理の実装コードをここに書く

	next_page_url = driver.find_element_by_class_name("js-next-page-link").get_attribute("href")
else:
	print("\n\n記事検索結果の最後のページの処理が終わりました。\n\n")
```

# 実際に作成したコード

```python:selenium_python_multi_pages_while.py
# coding: utf-8
import time, argparse, datetime
from selenium import webdriver
from bs4 import BeautifulSoup
from pprint import pprint
import pandas as pd
import numpy as np
import time

### 定数 ###
url = "http://qiita.com"

### 変数の初期化宣言 ###
pagenum = 0
# コマンドライン引数を受け取る
parser = argparse.ArgumentParser()

# コマンドライン引数を1つだけ受け取る
parser.add_argument('-word', '--search_word', default='Python', help='Qiitaの記事検索ページに入力する検索単語を指定してください。')
parser.add_argument('-max', '--max_page_num', default='50', help='該当するページが複数ある場合、データ取得するページ数に上限を設定する場合は、上限ページ数を指定してください。')
args = parser.parse_args()
search_word = args.search_word
num_of_search_pages = int(args.max_page_num)

print("\n\n入力された検索文字列：      ", args.search_word, "\n")
print("記事一覧ページが複数ページに及ぶ場合、{}ページまでで処理を打ち切ります。".format(num_of_search_pages))

# outputファイル名
output_file_name = str(datetime.datetime.now()) + "_Search: " + search_word

### メソッド定義 ###
def proceed_each_page(page_num, this_page_html, driver):
	from bs4 import BeautifulSoup
	this_soup = BeautifulSoup(this_page_html, 'lxml')
	print("""
	================================
		   {}ページ目を処理中...	
	===============================
	""".format(page_num))
	results = this_soup.find_all("h1", class_="searchResult_itemTitle")
	# 結果を記事タイトルリストに格納
	this_page_title_list = []
	for result in results:
		title_texts = result.findAll("a")
		title_texts = str(title_texts[0]).replace("<em>", "").replace("</em>", "").split(">")[1:]
		title_texts = title_texts[0]
		pos = title_texts.find('</a')
		title_text = title_texts[:pos]
		this_page_title_list.append(title_text)

	console_message = "検索結果画面の{}ページ目の記事件数:  ".format(pagenum) + str(len(this_page_title_list)) + "\n\n"
	pprint(this_page_title_list)
	
	# 結果をURLリストに格納
	this_page_url_list = []
	for result in results:
		href = result.findAll("a")[0].get("href")
		this_page_url_list.append(str(url + href))

	# 投稿者を投稿者リストに格納
	# <div class="searchResult_header"><a href="/niiku-y">niiku-y</a>が2019/08/07に投稿</div>
	this_page_author_list = []
	
	results = this_soup.findAll(class_="searchResult_header")
	for result in results:
		author = result.findAll("a")[0].get("href")
		author = author.replace("/", "")
		this_page_author_list.append(author)

	# nページ目から取得した記事であることをデータ保存
	this_page_num_list = [page_num]*len(this_page_title_list)

	## 検索結果画面のnページ目の画面スクリーンキャプチャを取得 
	# 画面の縦横サイズのデータを取得
	w = driver.execute_script("return document.body.scrollWidth;")
	h = driver.execute_script("return document.body.scrollHeight;")
	driver.set_window_size(w,h)
	# 画面スクリーンキャプチャファイル（画像ファイル）の保存場所とファイル名を指定
	FILENAME = "./{search_word}_page{number}_screen_{datetime}.png".format(search_word=search_word, number=page_num, datetime=str(datetime.datetime.now()))  
	# 画像を保存
	driver.save_screenshot(FILENAME)
	
	#処理したWebページの情報を格納した各listを返す
	return [this_page_num_list, this_page_author_list, this_page_title_list, this_page_url_list, driver]

### メソッド定義おわり 

### main処理
driver = webdriver.Chrome()

# Qiitaのトップページにアクセス
driver.get(url)

# 記事の検索ボックス欄に、キーワードを入力
search = driver.find_element_by_class_name("st-Header_searchInput")
search.send_keys(search_word)
search.submit()
time.sleep(5)

# 検索結果の記事一覧ページの1ページ目のHTMLを取得
first_page_html = driver.page_source.encode('utf-8')

# 1ページ目を処理
page_num = 1
all_page_num_list = []
all_page_author_list = []
all_page_title_list = []
all_page_url_list = []

this_page_num_list, this_page_author_list, this_page_title_list, this_page_url_list, driver = proceed_each_page(page_num, first_page_html, driver)

all_page_num_list = all_page_num_list + this_page_num_list
all_page_author_list = all_page_author_list + this_page_author_list
all_page_title_list = all_page_title_list + this_page_title_list
all_page_url_list = all_page_url_list + this_page_url_list

# 受け取ったdriverの指示対象のWebページに、次のページがある場合は、次のページに移動する
# next_page_urlの返り値はlist型。次のページが記載された上記のタグが存在しない場合は、空のlistが返る
next_page_url = driver.find_element_by_class_name("js-next-page-link").get_attribute("href")
print("=======")
print(type(next_page_url))
print("=======")

# 2ページ目から(最終ページ目 もしくは、{num_of_search_pages}ページ目までのいずれか小さいページ番号目)までをループ処理する
# (num_of_search_pages)ページ目を最終ページにするためには、{num_of_search_pages -1)回、次のページをめくる
while len(next_page_url) > 0 and page_num <= (num_of_search_pages - 1):
	driver.get(next_page_url)
	#要素がロードされるまでの待ち時間を10秒に設定
	driver.implicitly_wait(10)
	#time.sleep(5)
	next_page_html = driver.page_source.encode('utf-8')
	page_num += 1
	this_page_num_list, this_page_author_list, this_page_title_list, this_page_url_list, driver = proceed_each_page(page_num, next_page_html, driver)
	all_page_num_list = all_page_num_list + this_page_num_list
	all_page_author_list = all_page_author_list + this_page_author_list
	all_page_title_list = all_page_title_list + this_page_title_list
	all_page_url_list = all_page_url_list + this_page_url_list
	next_page_url = driver.find_element_by_class_name("js-next-page-link").get_attribute("href")
	print("=======")
	print(next_page_url)
	print(len(next_page_url))
	print("=======")
else:
	print("\n\n記事検索結果の最後のページの処理が終わりました。\n\n")

# Excelファイル出力
print("\n\n取得した検索結果のデータをExcelファイルに出力します。\n\m")
data = np.array([all_page_num_list, all_page_author_list, all_page_title_list, all_page_url_list]).T

index_list = list(range(len(all_page_num_list)))
column_list = ['検索結果画面内の掲載ページ番号', '投稿者', '記事のタイトル', '記事のURL']
output_df = pd.DataFrame(data, columns=column_list, index=index_list)
pprint(output_df)

# 結果をExcelファイルに出力
output_df.to_excel('./'+output_file_name + '.xlsx', sheet_name='Qiita_Articles_list')

#　Webページに自動アクセスするために生成したdriverインスタンスを閉じて消去（メモリ開放）する
time.sleep(5)
driver.close()
driver.quit()
```

##（ 使い方 ）

```bash:Console
$ python  selenium_python_multi_pages_while.py --help
usage: selenium_python_multi_pages_while.py [-h] [-word SEARCH_WORD]
                                            [-max MAX_PAGE_NUM]

optional arguments:
  -h, --help            show this help message and exit
  -word SEARCH_WORD, --search_word SEARCH_WORD
                        Qiitaの記事検索ページに入力する検索単語を指定してください。
  -max MAX_PAGE_NUM, --max_page_num MAX_PAGE_NUM
                        該当するページが複数ある場合、データ取得するページ数に上限を設定する場合は、上限ページ数を指定してください。
$ 
```

## （ 実行例とその結果 ）

```bash:Console
$ python  selenium_python_multi_pages_while.py -word Haskell -max 5


入力された検索文字列：       Haskell

記事一覧ページが複数ページに及ぶ場合、5ページまでで処理を打ち切ります。

	================================
		   1ページ目を処理中...
	===============================

['HaskellでMD5 #Haskell',
 'stylish-haskellをHexFloatLiteralsやNumericUnderscoresに対応させる',
 'Haskell チュートリアル (Haskell Day 2016)',
 'VSCodeのHaskell拡張を使って最速開発環境構築',
 'stylish-haskellをBlockArgumentsに対応させる',
 'Haskell で Functor を使う',
 'Windows10 HomeでDocker + VSCodeによるhaskellの環境構築',
 'Docker + Haskell の Hello Worldビルド',
 'Haskellの型クラスで遊ぶ',
 'HaskellのEitherについて']
=======
<class 'str'>
=======

	================================
		   2ページ目を処理中...
	===============================

['Haskellの関数の型とかカリー化とか #Haskell',
 'Haskell と SQLite',
 'Haskell 入門',
 'Haskell/GHC 記号の意味を検索するためのリファレンス集',
 'Approaching Haskell',
 'Haskell入門記事備忘録',
 'Typing Haskell in Haskellを読んでみる',
 '[Haskell] Some memo about learning haskell',
 'Haskell入門 - Stackのインストールと設定',
 'Ruby内にHaskellのコード埋め込むHaskellというGem作ったヨ！']
=======
https://qiita.com/search?page=3&q=Haskell
41
=======

	================================
		   3ページ目を処理中...
	===============================

['Typing Haskell in Haskellを読んでみる',
 'VisualStudioCodeでHaskell開発環境を整える',
 'なぜHaskellを学ぶと良いか',
 '[Haskell] Some memo about learning haskell',
 'Haskell インストールメモ',
 "VSCodeでCouldn't start client Haskell IDEが出る（Windows 10）",
 'Stackをhaskell-modeで使ってみよう',
 'Haskellのお勉強その1-Haskell環境構築',
 'HaskellerがRustに入門してみた',
 'Haskellの入門から中級者になるまでの指針']
=======
https://qiita.com/search?page=4&q=Haskell
41
=======

	================================
		   4ページ目を処理中...
	===============================

['Atom EditorでHaskell',
 'Haskellで逆ポーランド記法の計算機を作る',
 'Atomエディタでide-haskellを使うまでの手順',
 'MacでHaskellを触ってみるメモ 0.1',
 'Haskellを始めてみた',
 'ATOMのide-haskell導入手順（MacOS X）',
 '【翻訳】PureScriptとHaskellの違い\u3000＋α',
 'Haskellメモ',
 'Windows10でHaskell開発環境構築',
 'Haskellで食べていけるよ！!']
=======
https://qiita.com/search?page=5&q=Haskell
41
=======

	================================
		   5ページ目を処理中...
	===============================

['Haskell Weekly News 日本語版(お試し) (5/8)',
 '世界のHaskell専門家に向けたメッセージ全文',
 'JSON から各言語のコードを生成する quicktype の Haskell 出力を実装した',
 'haskell-ide-engine導入',
 'macOSでVS CodeのHaskellの環境構築で嵌った点',
 'Go製のToolをHaskellで実装する',
 'Haskellの($)と(.)の違い',
 'Samuel Gélineau からの返信その1(翻訳)',
 'Haskell 環境構築 メモ',
 'Haskellerの1週間Rust入門チャレンジ Day 1 #Rust']
=======
https://qiita.com/search?page=6&q=Haskell
41
=======


記事検索結果の最後のページの処理が終わりました。




取得した検索結果のデータをExcelファイルに出力します。
\m
   検索結果画面内の掲載ページ番号                投稿者  \
0                1          Tatsuki-I
1                1          mod_poppo
2                1           hiratara
3                1             sgmryk
4                1      sparklingbaby
5                1         oskats1987
6                1     atsuyoshi-muta
7                1             dd0125
8                1         oskats1987
9                1             Izawa_
10               2          Tatsuki-I
11               2        satosystems
12               2            a163236
13               2        takenobu-hs
14               2         pumbaacave
15               2               F_cy
16               2              nka0i
17               2          zhupeijun
18               2      sparklingbaby
19               2         gogotanaka
20               3              nka0i
21               3          legokichi
22               3              arowM
23               3          zhupeijun
24               3             tnoda_
25               3            yutasth
26               3        t-mochizuki
27               3       CPyRbJvCHlCs
28               3            kanimum
29               3           Lugendre
30               4              eielh
31               4       inatatsu_csg
32               4       busyoumono99
33               4       hiroyuki_hon
34               4              Cj-bc
35               4  nakamurau1@github
36               4         hiruberuto
37               4             sahara
38               4       kitsukitsuki
39               4         reotasosan
40               5          imokurity
41               5         reotasosan
42               5              algas
43               5         dyoshikawa
44               5                dsm
45               5        kwhrstr1206
46               5         TTsurutani
47               5         reotasosan
48               5              1ain2
49               5          Tatsuki-I

                                              記事のタイトル  \
0                                HaskellでMD5 #Haskell
1   stylish-haskellをHexFloatLiteralsやNumericUnders...
2                  Haskell チュートリアル (Haskell Day 2016)
3                        VSCodeのHaskell拡張を使って最速開発環境構築
4                stylish-haskellをBlockArgumentsに対応させる
5                               Haskell で Functor を使う
6       Windows10 HomeでDocker + VSCodeによるhaskellの環境構築
7                   Docker + Haskell の Hello Worldビルド
8                                     Haskellの型クラスで遊ぶ
9                                  HaskellのEitherについて
10                      Haskellの関数の型とかカリー化とか #Haskell
11                                   Haskell と SQLite
12                                         Haskell 入門
13                   Haskell/GHC 記号の意味を検索するためのリファレンス集
14                                Approaching Haskell
15                                     Haskell入門記事備忘録
16                    Typing Haskell in Haskellを読んでみる
17         [Haskell] Some memo about learning haskell
18                        Haskell入門 - Stackのインストールと設定
19            Ruby内にHaskellのコード埋め込むHaskellというGem作ったヨ！
20                    Typing Haskell in Haskellを読んでみる
21                   VisualStudioCodeでHaskell開発環境を整える
22                                   なぜHaskellを学ぶと良いか
23         [Haskell] Some memo about learning haskell
24                                   Haskell インストールメモ
25  VSCodeでCouldn't start client Haskell IDEが出る（Wi...
26                          Stackをhaskell-modeで使ってみよう
27                         Haskellのお勉強その1-Haskell環境構築
28                              HaskellerがRustに入門してみた
29                            Haskellの入門から中級者になるまでの指針
30                                Atom EditorでHaskell
31                            Haskellで逆ポーランド記法の計算機を作る
32                       Atomエディタでide-haskellを使うまでの手順
33                            MacでHaskellを触ってみるメモ 0.1
34                                      Haskellを始めてみた
35                      ATOMのide-haskell導入手順（MacOS X）
36                       【翻訳】PureScriptとHaskellの違い　＋α
37                                          Haskellメモ
38                            Windows10でHaskell開発環境構築
39                                  Haskellで食べていけるよ！!
40                Haskell Weekly News 日本語版(お試し) (5/8)
41                           世界のHaskell専門家に向けたメッセージ全文
42    JSON から各言語のコードを生成する quicktype の Haskell 出力を実装した
43                               haskell-ide-engine導入
44                    macOSでVS CodeのHaskellの環境構築で嵌った点
45                              Go製のToolをHaskellで実装する
46                                 Haskellの($)と(.)の違い
47                       Samuel Gélineau からの返信その1(翻訳)
48                                    Haskell 環境構築 メモ
49               Haskellerの1週間Rust入門チャレンジ Day 1 #Rust

                                               記事のURL
0   http://qiita.com/Tatsuki-I/items/6d4a2d9f767ae...
1   http://qiita.com/mod_poppo/items/418da906f6621...
2   http://qiita.com/hiratara/items/169b5cb83b0adb...
3   http://qiita.com/sgmryk/items/bc99efe36ad1c910...
4   http://qiita.com/sparklingbaby/items/a46f299dd...
5   http://qiita.com/oskats1987/items/30f9078c5096...
6   http://qiita.com/atsuyoshi-muta/items/9dd10d48...
7   http://qiita.com/dd0125/items/a141000ead36b382...
8   http://qiita.com/oskats1987/items/dcd46780ff5e...
9   http://qiita.com/Izawa_/items/ed0579a0e7d93e5c...
10  http://qiita.com/Tatsuki-I/items/d1d122107da8c...
11  http://qiita.com/satosystems/items/32bf104a041...
12  http://qiita.com/a163236/items/5e0d0e373e87ca8...
13  http://qiita.com/takenobu-hs/items/b95f0a4409c...
14  http://qiita.com/pumbaacave/items/17e6699d4db8...
15   http://qiita.com/F_cy/items/9c49e351196943e38ad9
16  http://qiita.com/nka0i/items/d44f0c6d4df1ef582fd3
17  http://qiita.com/zhupeijun/items/4abcc5fa1cdce...
18  http://qiita.com/sparklingbaby/items/a901cb3a7...
19  http://qiita.com/gogotanaka/items/78a3ffd04abc...
20  http://qiita.com/nka0i/items/d44f0c6d4df1ef582fd3
21  http://qiita.com/legokichi/items/8e7a68ffee522...
22  http://qiita.com/arowM/items/0305d4f439752f285438
23  http://qiita.com/zhupeijun/items/4abcc5fa1cdce...
24  http://qiita.com/tnoda_/items/22b265fe9ad8ee1e...
25  http://qiita.com/yutasth/items/28af2eb0371f645...
26  http://qiita.com/t-mochizuki/items/d831df3a920...
27  http://qiita.com/CPyRbJvCHlCs/items/9da9b43b55...
28  http://qiita.com/kanimum/items/d89547235070038...
29  http://qiita.com/Lugendre/items/70e517e59698e0...
30  http://qiita.com/eielh/items/b2e85f8ea4c6cdb8012d
31  http://qiita.com/inatatsu_csg/items/b035c76ec6...
32  http://qiita.com/busyoumono99/items/220bd3c30f...
33  http://qiita.com/hiroyuki_hon/items/3eb41a16fe...
34  http://qiita.com/Cj-bc/items/583fa82805775cf17dd6
35  http://qiita.com/nakamurau1@github/items/7feae...
36  http://qiita.com/hiruberuto/items/3eb21ef81b3d...
37  http://qiita.com/sahara/items/7c7ef646fb3e9b08...
38  http://qiita.com/kitsukitsuki/items/a56cbfc0de...
39  http://qiita.com/reotasosan/items/e80ab706baef...
40  http://qiita.com/imokurity/items/f90e4c35c74fe...
41  http://qiita.com/reotasosan/items/2b37fdef025a...
42  http://qiita.com/algas/items/1ebb9b8c77fc5f344708
43  http://qiita.com/dyoshikawa/items/a1789bf7ff1d...
44    http://qiita.com/dsm/items/861d08844b1fba32f07b
45  http://qiita.com/kwhrstr1206/items/fdf460f2a9a...
46  http://qiita.com/TTsurutani/items/201200c1f288...
47  http://qiita.com/reotasosan/items/cce796d32105...
48  http://qiita.com/1ain2/items/09ad8b0e4992f7ceae0f
49  http://qiita.com/Tatsuki-I/items/e19953c051e55...
$ 
```

### （ 出力ファイル群 ）
![スクリーンショット 2020-11-08 0.27.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/862466/530c435d-95aa-bb4d-c6fa-672b73ff63b8.png)

### （ Excelファイル ）
![スクリーンショット 2020-11-08 0.29.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/862466/b9445aab-c897-5798-c8c3-39d8650607dc.png)

### （ pngファイル ）

![スクリーンショット 2020-11-08 0.30.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/862466/ab951206-5283-854e-5240-6c62523796d6.png)

（ 途中ページの画面キャプチャ画像ファイルは、掲載省略）

![スクリーンショット 2020-11-08 0.31.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/862466/dbedb49c-de04-4e93-882f-3d7e95683b09.png)

# その他：記事の検索文字列は、漢字カタカナかなもOK

```{bash:Console}
$ python  selenium_python_multi_pages_while.py -word 圏論 -max 20
```