2017-10-08

【Python】Webスクレイピングチュートリアル -「次へ」ボタンが存在するページをすべて取得する場合 -

PythonのSeleniumを利用して、「次へ」ボタンが存在するページをすべて取得する方法を解説します。

目次

  • 挙動を確認する
  • 日本語でアルゴリズムを考える
  • 実装する
  • サンプルコード



挙動を確認する

実際にはてなブックマークの検索ページに行きまして、「R」と検索してみてください。そうすると、以下のようなURLに飛びます。

http://b.hatena.ne.jp/search/text?q=R

検索語句ですが、実は検索語句のtext?q=Rの中に、検索語句が含まれています。このように、q=[]の中に検索語句を入れれば、検索結果が取得できるようになるというわけです。



さて、次のページに移って、新たな情報を取得するので、ページ最下部へ行き、次の40件
というボタンを見つけます。そうすると、次の40件を取得してくれます。これを何度も繰り返すと、最後のページにつきます。そうすると、次の40件のボタンがなくなります。


次の40件のボタンのXpathを取得します。
こちらを、前の記事で紹介したように、xpathで位置を保存してください。

【Python】Webスクレイピングチュートリアル -ログインが必要なサイトの場合-

Pythonの Selenium を利用して、ログインが必要なサイトにアクセスし、データを取得する方法を解説します


日本語でアルゴリズムを考える



さて、これらの動作を実際のプログラミングに落とし込んでいくわけですが、日本語で一度アルゴリズムを考えていきます。



  • 検索語句を格納する変数を用意する (例)query = "R"
  • http://b.hatena.ne.jp/search/text?q=QueryとなるようなURLを用意する
  • そのURLにアクセスする
  • そのページに存在する各記事をXpathで複数取得する
  • 記事からそれぞれ以下の情報を取得し、csvに追加する
    • タイトル
    • 作成日時
    • ブックマーク数
  • もし次の40件のボタンがあれば
    • 次の40件ボタンをクリックし、ページの情報を再度printする
  • もし次の40件のボタンがなければ
    • 処理を終了する


実装する


まず、各モジュールをインポートします。

from selenium import webdriver #Seleniumを動かすもの
from pandas import * #CSVやデータを取り扱うもの
import time #処理を一度待つもの

そして、検索語句を設定し、そのページにアクセスします。

browser = webdriver.PhantomJS()  # DO NOT FORGET to set path
query = "R"
url = "http://b.hatena.ne.jp/search/text?safe=on&q=" + query + "&users=50"
browser.get(url)

そして、すでに作ってあるCSVを読み込みます。

df = pandas.read_csv('trend.csv', index_col=0)

後々「次へ」を押した数を計算したいので、countという変数を設定します。

page = 1 #This number shows the number of current page later

もし、ページに「次の40件」ボタンが存在したときは、記事を取得し、存在しないときは処理を終わるようにします。

while True: #continue until getting the last page
    if len(browser.find_elements_by_css_selector(".pager-next")) > 0:
        print("######################page: {} ########################".format(page))
        print("Starting to get posts...")
        #get all posts in a page
        posts = browser.find_elements_by_css_selector(".search-result")
 :
    else: #if no pager exist, stop.
        print("no pager exist anymore")
        break


次の40件ボタンが存在する場合、すべての記事を取得して、一つ一つ記事名(title)、作成日(date)、ブックマーク数(bookmarks)を取得し、pandasのSeriesオブジェクトの中に挿入し、そしてもともと定義しておいたdfというデータフレームに挿入します。これをすべてのページ内のすべての記事分行います。


posts = browser.find_elements_by_css_selector(".search-result")
     
        for post in posts:
            title = post.find_element_by_css_selector("h3").text
            date = post.find_element_by_css_selector(".created").text
            bookmarks = post.find_element_by_css_selector(".users span").text
            se = pandas.Series([title, date, bookmarks],['title','date','bookmarks'])
            df = df.append(se, ignore_index=True)
            print(df)


これらの処理が終わったら、今度は下の「次の40件」のURLを取得し、次のページに移ります。なお、ページの移動の際には、はてなさんのサーバーを重くさせないように、10秒待つメソッドを実行します。


#after getting all posts in a page, click pager next and then get next all posts again
        
        btn = browser.find_element_by_css_selector("a.pager-next").get_attribute("href")
        print("next url:{}".format(btn))
        browser.get(btn)
        page+=1
        browser.implicitly_wait(10)
        print("Moving to next page......")
        time.sleep(10)

かくして、記事名、更新日時、ブックマーク数を取得したテーブルが完成したので、csvに落とし込みます。


df.to_csv(query + ".csv")
print("DONE")


これで処理は完了します。

サンプルコード

完成したものをこちらに置いておきます。(ところどころ不必要なコードが書いてありますが、気にしないでください。)

from selenium import webdriver
import requests # for slack  
from pandas import * 
import time

#Access to page

browser = webdriver.PhantomJS()  # DO NOT FORGET to set path
query = "R"
url = "http://b.hatena.ne.jp/search/text?safe=on&q=" + query + "&users=50"
browser.get(url)

df = pandas.read_csv('trend.csv', index_col=0)

#Insert title,date,bookmarks into CSV file

page = 1 #This number shows the number of current page later

while True: #continue until getting the last page
    if len(browser.find_elements_by_css_selector(".pager-next")) > 0:
        print("######################page: {} ########################".format(page))
        print("Starting to get posts...")
        #get all posts in a page
        posts = browser.find_elements_by_css_selector(".search-result")
        
        for post in posts:
            title = post.find_element_by_css_selector("h3").text
            date = post.find_element_by_css_selector(".created").text
            bookmarks = post.find_element_by_css_selector(".users span").text
            se = pandas.Series([title, date, bookmarks],['title','date','bookmarks'])
            df = df.append(se, ignore_index=True)
            print(df)

        #after getting all posts in a page, click pager next and then get next all posts again
        
        btn = browser.find_element_by_css_selector("a.pager-next").get_attribute("href")
        print("next url:{}".format(btn))
        browser.get(btn)
        page+=1
        browser.implicitly_wait(10)
        print("Moving to next page......")
        time.sleep(10)
    else: #if no pager exist, stop.
        print("no pager exist anymore")
        break

df.to_csv(query + ".csv")
print("DONE")

Python データ分析入門マニュアルに戻る

注目の投稿

 PythonのTweepyを利用して、Twitter APIを利用している。 その中で、ハマったポイントをメモしておく。 まず、Searchに関して。 Twitter検索は、クライアントアプリ側では、全期間の検索が可能になっている。 一方で、APIを利用する際は、過去1週間しか...