Seleniumでログイン後に、データを自動収集しよう

このチュートリアルの学習内容

  • Seleniumで自動ログイン後に、データを収集できるようになる

全件数を取得する

それでは、すべてのページを自動取得してみましょう。 まずは要件の確認ですが、

  • title:世界のチーズ専門店 オーダーチーズ
  • asp: アクセストレード
  • price:売上報酬9.53%
  • detail:詳細

の値を取得します。以下の画像を参考にしてください。

アクセス

そして、全ページの件数を取得します。 Pagerの、「次へ」が存在しなくなるまで、件数を取得すればいいわけですね。

pagerが存在する

それでは、さっそくコードを書いていきましょう。 この、「次へ」に該当するソースコードは、以下のページャーのHTMLの中に含まれています。 開発者ツールを利用して、みてみましょう。

<div class="pagination-container">
<nav>
<ul class="pagination">
<li class="page-item active">
<a data-remote="false" class="page-link">1</a>
</li>
<li class="page-item">
<a rel="next" class="page-link" href="/?page=2">2</a>
</li>
<li class="page-item">
<a class="page-link" href="/?page=3">3</a>
</li>
<li class="page-item">
<a class="page-link" href="/?page=4">4</a>
</li>
<li class="page-item">
<a class="page-link" href="/?page=5">5</a>
</li>
<li class='page-item disabled'>
<a class="page-link" href="#">...</a>
</li>
<li class="page-item">
<a rel="next" class="page-link" href="/?page=2">次 ›</a>
</li>
<li class="page-item">
<a class="page-link" href="/?page=486">最後 »</a>
</li>
</ul>
</nav>
</div>

ここの中の、

<li class="page-item">
  <a rel="next" class="page-link" href="/?page=2">&rsaquo;</a>
</li>

が「次」となっています。 この次へボタンのhrefを取得すれば、次のページにはいけそうですね。 では、ここの値をどう取得すればいいか。 実は、難しいのが

browser.find_element_by_css_selector("li.page-item a")

のように取得してしまうと、ほかにも複数あるので、しっかりと「次」が含まれたリンクをピンポイントで取得できません。

そこで使うのが、Xpathです。(Xpathの詳細については、こちらの記事が大変参考になります。)

クローラ作成に必須!XPATHの記法まとめ

Xpathを利用すると、class, relなどの要素と、その値のペアで、以下のように検索することができます。

find_element_by_xpath

◆メソッド
  ・find_element_by_xpath(xpath)
◆使用形態
  ・driver.find_element_by_xpath("//div/div/td[1]")
◆備考
  ・引数に取得したい要素のxpathを指定することで要素を取得できる
  ・引数で指定する属性値やインナーテキストなどの「値」はシングルクォーテーションで囲われる必要がある
◆関連項目
  ・id属性から要素を取得する
  ・name属性から要素を取得する

ここは少し難しいので、こちら側でコードを見せちゃいますね。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
options = Options()
options.add_argument('--headless')
browser = webdriver.Chrome(executable_path='./chromedriver',  chrome_options=options)

EMAIL = "sample@sample.com"
PASSWORD = "sample1234"
browser.find_element_by_css_selector("#user_email").send_keys(EMAIL)
browser.find_element_by_css_selector("#user_password").send_keys(PASSWORD)
browser.find_element_by_css_selector("div.actions input").click()
browser.save_screenshot("tmp.png")

while True: 
   #TODO「次」ボタンを、xpathを利用して、選択してみてください
   next_slctr = browser.find_element_by_xpath("//a[@rel='next']")
   if next_slctr:
     next_url = next_slctr.get_attribute("href")
       print ("move to {}".format(next_url))
       browser.get(next_url)
       continue
   break

これで実行すると、最後のページまで行けるのですが、一つエラーが起こります。それは、最後のページで、「次へボタンが見つからない」からです。 その際、要素が見つからないときのために、try exceptでエラーをよけてあげる必要があります。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
#TODO Seleniumのパスを通し、ログインページにアクセスする
options = Options()
options.add_argument('--headless')
browser = webdriver.Chrome(executable_path='./chromedriver',  chrome_options=options)

#TODO ログインしてみる
EMAIL = "sample@sample.com"
PASSWORD = "sample1234"
browser.find_element_by_css_selector("#user_email").send_keys(EMAIL)
browser.find_element_by_css_selector("#user_password").send_keys(PASSWORD)
browser.find_element_by_css_selector("div.actions input").click()
browser.save_screenshot("tmp.png")

# 全件取得する
while True: #次へが存在しなくなるまで、ループする
   try:
      next_slctr = browser.find_element_by_xpath("//a[@rel='next']")
      if next_slctr:
        next_url = next_slctr.get_attribute("href")
          print ("move to {}".format(next_url))
          browser.get(next_url)
          continue
   except:
      break

これで最後のページまでループできるはずなので、次は各案件の情報を取得していきましょう。

各案件の情報を取得する

では、案件情報のHTMLを確認してみましょう。

<div class="item">
<div class="item__title"><a target="_blank" href="https://px.a8.net/svt/ejp?a8mat=2TKNDD+8PRGKY+0K+ZSD6A">AGA治療なら大阪梅田のNDクリニック(19-0426)(s00000019937001)</a></div>
<div class="item__info">
<table class="table">
<tbody>
<tr>
<th>ASP</th>
<td>A8.net</td>
</tr>
<tr>
<th>成果報酬</th>
<td></td>
</tr>
<tr>
<th>詳細</th>
<td>◆セールスポイント◆
40年以上にわたり、薄毛治療を専門とした、治療実績を誇るクリニックです。
育毛・発毛注射では、最先端医療であるPRP毛髪再生治療
(ご自身の血液から採り出した血漿を濃縮して作成した高濃度の血小板を含む血漿を頭皮に注入する再生医療)
をおこなって...</td>
</tr>
</tbody>
</table>
<a class="btn btn-block text-center cta" href="https://px.a8.net/svt/ejp?a8mat=2TKNDD+8PRGKY+0K+ZSD6A" target="_blank">A8.netの案件を確認する</a>
</div>
</div><!-- item -->
<div class="item">
<div class="item__title"><a target="_blank" href="https://px.a8.net/svt/ejp?a8mat=2TKNDD+8PRGKY+0K+ZSD6A">業界屈指の高額買取【中古トレカ専門ECサイトカーナベル】(19-0426)(s00000019953001)</a></div>
<div class="item__info">
<table class="table">
<tbody>
<tr>
<th>ASP</th>
<td>A8.net</td>
</tr>
<tr>
<th>成果報酬</th>
<td></td>
</tr>
<tr>
<th>詳細</th>
<td>◆セールスポイント◆
カーナベルでは、「詳細な金額表示で必ず納得できる&quot;&quot;通常買取&quot;&quot;」と
「大量買取で一攫千金を狙える&quot;&quot;まとめ買取&quot;&quot;」の二つから買取方法をお選びいただけます。
またどちらの方法を選んでも、買取専用の梱包キットを無料でプレゼントさせていただいて...</td>
</tr>
</tbody>
</table>
<a class="btn btn-block text-center cta" href="https://px.a8.net/svt/ejp?a8mat=2TKNDD+8PRGKY+0K+ZSD6A" target="_blank">A8.netの案件を確認する</a>
</div>
</div><!-- item -->

それぞれの案件が、itemというタグの中にくくられて、羅列されています。 ですので、まずはそれぞれのitemを取得する必要があります。 この際に必要なのが、複数要素を取得するfind_elements_by_css_selectorメソッドです。

前回に使った、find_element_by_css_selectorメソッドと違い、"elements"になっていることをご確認ください。 つまりこれは、複数のHTML要素を取得することができるメソッドになっています。

TODO:

  1. 複数のitemを、item_slctrとしてリスト形式で取得してください
  2. for文を利用して、itemを一つ一つ取り出してください

答え

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
#TODO Seleniumのパスを通し、ログインページにアクセスする
options = Options()
options.add_argument('--headless')
browser = webdriver.Chrome(executable_path='./chromedriver',  chrome_options=options)

#TODO ログインしてみる
EMAIL = "sample@sample.com"
PASSWORD = "sample1234"
browser.find_element_by_css_selector("#user_email").send_keys(EMAIL)
browser.find_element_by_css_selector("#user_password").send_keys(PASSWORD)
browser.find_element_by_css_selector("div.actions input").click()
browser.save_screenshot("tmp.png")

# 全件取得する
while True: #次へが存在しなくなるまで、ループする
    item_slctrs = browser.find_elements_by_css_selector("div.item")
    for item in item_slctrs:
        #WIP あとで詳細情報を取得する
   try:
      next_slctr = browser.find_element_by_xpath("//a[@rel='next']")
      if next_slctr:
        next_url = next_slctr.get_attribute("href")
          print ("move to {}".format(next_url))
          browser.get(next_url)
          continue
   except:
      break

案件名、成果報酬、ASP、詳細を取得する

それでは、for文で取り出した結果から、案件名、成果報酬、ASP、詳細を取得したいと思います。

案件名

<div class="item__title"><a target="_blank" href="https://px.a8.net/svt/ejp?a8mat=2TKNDD+8PRGKY+0K+ZSD6A">AGA治療なら大阪梅田のNDクリニック(19-0426)(s00000019937001)</a></div>

ASP名

<td>A8.net</td>

成果報酬

<td></td>

詳細

<th>詳細</th> 
<td>◆セールスポイント◆ カーナベルでは、「詳細な金額表示で必ず納得できる&quot;&quot;通常買取&quot;&quot;」と 「大量買取で一攫千金を狙える&quot;&quot;まとめ買取&quot;&quot;」の二つから買取方法をお選びいただけます。 またどちらの方法を選んでも、買取専用の梱包キットを無料でプレゼントさせていただいて...</td> 
<

ということで、ざっと見てましたが、実は取得するの、大変そうに見えませんか? なぜかというと、今まではIDやCLASSを利用して、HTML要素を指定できたのですが、 今回の場合だとtd要素に名前が全くついていません。なので、個別の指定ができないのです。 そこで、今回は、nth-child(n)という、CSS Selectorを利用します。 取得したい要素は、以下のように、table要素の中に並列でtd要素が並んでいます。

table
└td: ①タイトル
└td: ②成果報酬
└td: ③ASP名
└ts: ④詳細

これを,

table td:nth-child(1)

のようにすると、最初のタイトルの要素がとれます。

TODO

  1. nth-childを利用して、タイトル、成果報酬、ASP名、詳細を取得してください。

答え

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
#TODO Seleniumのパスを通し、ログインページにアクセスする
options = Options()
options.add_argument('--headless')
browser = webdriver.Chrome(executable_path='./chromedriver',  chrome_options=options)
browser.get("http://affisearch.herokuapp.com/users/sign_in")

#TODO ログインしてみる
EMAIL = "sample@sample.com"
PASSWORD = "sample1234"
browser.find_element_by_css_selector("#user_email").send_keys(EMAIL)
browser.find_element_by_css_selector("#user_password").send_keys(PASSWORD)
browser.find_element_by_css_selector("div.actions input").click()
browser.save_screenshot("tmp.png")

# 全件取得する
while True: #次へが存在しなくなるまで、ループする
    item_slctrs = browser.find_elements_by_css_selector("div.item")
    #nth-childを利用して、データを取得してください
    for item in item_slctrs:
        title = item.find_element_by_css_selector("div.item__title").text
        asp = item.find_element_by_css_selector("table tr:nth-child(1) td").text
        price = item.find_element_by_css_selector("table tr:nth-child(2) td").text
        detail = item.find_element_by_css_selector("table tr:nth-child(3) td").text
        print (title, asp, price, detail)


   try:
      next_slctr = browser.find_element_by_xpath("//a[@rel='next']")
      if next_slctr:
        next_url = next_slctr.get_attribute("href")
          print ("move to {}".format(next_url))
          browser.get(next_url)
          continue
   except:
      break

CSVに保存する

さて、最後にCSVに保存していきましょう。 CSVに保存する方法は、過去のチュートリアルで何度も実践しているので、特に解説しません。 もしやり方が分からなければ、以下のチュートリアルに沿って復習してみてください!

TODO

  1. Pandasをインストールしてください
  2. Pandasをインポートしてください
  3. 列名が["title", "price", "asp", "detail"]である、データフレームを作成してください
  4. DataFrameに、スクレイピングした結果を追加してください
  5. to_csvメソッドで、CSVをエクスポートしてください

回答

まず、Pandasをインストールします

pip install pandas

そしてコードがこちらになります。

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

#TODO Pandasをインポートしてください
import pandas as pd

#TODO 列名が["title", "price", "asp", "detail"]である、データフレームを作成してください
columns = ["title", "price", "asp", "detail"]
df = pd.DataFrame(columns=columns)

options = Options()
options.add_argument('--headless') 
browser = webdriver.Chrome(executable_path='./chromedriver', chrome_options=options) 
browser.get("http://affisearch.herokuapp.com/users/sign_in")

EMAIL = "sample@sample.com"
PASSWORD = "sample1234"
browser.find_element_by_css_selector("#user_email").send_keys(EMAIL)
browser.find_element_by_css_selector("#user_password").send_keys(PASSWORD)
browser.find_element_by_css_selector("div.actions input").click()
browser.save_screenshot("tmp.png")

while True:
    item_slctrs = browser.find_elements_by_css_selector("div.item")
    for item in item_slctrs:
        title = item.find_element_by_css_selector("div.item__title").text
        asp = item.find_element_by_css_selector("table tr:nth-child(1) td").text
        price = item.find_element_by_css_selector("table tr:nth-child(2) td").text
        detail = item.find_element_by_css_selector("table tr:nth-child(3) td").text
        #TODO DataFrameに、スクレイピングした結果を追加してください
        se = pd.Series([title, asp, price, detail], columns)
        df = df.append(se, ignore_index=True)
        print (df)

   try:
      next_slctr = browser.find_element_by_xpath("//a[@rel='next']")
      if next_slctr:
        next_url = next_slctr.get_attribute("href")
          print ("move to {}".format(next_url))
          browser.get(next_url)
          continue
   except:
      break
#TODO to_csvメソッドで、CSVをエクスポートしてください
df.to_csv("result.csv")

こちらを実行すると、スクレイピングが開始され、全件のデータを取得できるかと思います。

次のチュートリアル

お疲れさまでした!今回のチュートリアルは以上となります。

ノートをとる

メモが保存されました
メモ一覧を見る