Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
113
Help us understand the problem. What are the problem?

posted at

updated at

Organization

Python を活用しながら Web サイトのデータ収集を効率化(2)【実装編】

はじめに

みなさん、こんにちは。
株式会社キカガクの機械学習講師 藏野です。
キカガクは、「AI を含めた先端技術の研修」を行っている会社です。

この記事は、「Web スクレイピングで特定のデータを取得して CSV で出力」までの実務的な内容を取り扱います。

スクレイピングの記事は多くありますが、活用を見据えてデータを取得し保存するところまで取り組みたいという方は、ぜひ参考にされてください。

この記事は、Python を活用しながら Web サイトのデータ収集を効率化(1)【環境構築編】の続きとなっています。

必ず読む必要はありませんが、スクレイピングの仕組みを復習したい方は一読をオススメします。

目次

  1. スクレイピングの手法
  2. 環境構築
  3. 実践
  4. おわりに
  5. お知らせ

Web スクレイピングの手法

スクレイピングには、以下の 2 つの手法があります。

  • Selenium を使用して、ブラウザを自動操作することでデータを取得する手法
  • Beautiful Soup という Python パッケージを使用して、データを取得する手法

各手法の特徴として、Selenium はデータ取得とログイン処理などのブラウザ自動操作を行うことができ、 Beautiful Soup は HTML を解析してデータ取得を行うことができます。

スクレイピングを行うには両方の手法を扱えること理想ですが、今回は Selenium を使用してスクレイピングを行います。

環境構築

環境構築は、はじめに共有したこちらと同じなので、細かい説明は割愛します。

  • ブラウザ:Google Chrome
  • 実行環境:Google Colaboratory(以下 Colab )

パッケージのインストール

Colab でノートブックを作成後に、Selenium と WebDriver( ChromeDriver )をインストールしてインポートまで行います。

SeleniumとWebDriverのインストール
!apt-get update
!apt install chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver/usr/bin
!pip install selenium
webdriverとopitonsのインポート
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
Headlessモードに設定
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
browser = webdriver.Chrome('chromedriver',options=options)

Headless モード

Selenium は、ブラウザの自動操作を行うことができるので、自動操作用のブラウザを立ち上げて様々な処理を行います。

流れとしては、webdriver.Chrome()でブラウザを立ち上げて、browserという変数に格納し、この browserに対して、メソッドを使用していきます。

通常モードでは、webdriver.Chrome()を実行後に別ウィンドウでブラウザが立ち上がります。
Headless モードは、この自動で立ち上がるブラウザを非表示の状態でコードを実行していくことを意味します。

通常モードの場合は、以下の Gif を参考にしてください。
「ブラウザの立ち上げ > Google にアクセス > 株式会社キカガクを自動入力 > ブラウザを閉じる」 までの処理を行っています。

ezgif.com-gif-maker.gif

確認

最後に環境構築ができているか、下記のコードを実行して確認します。私と同じようにソースコードが取得できていれば問題ありません。

ソースコードを取得
browser.get('https://scraping-for-beginner.herokuapp.com/')
print(browser.page_source) 

source_get.gif

確認ができたら、ブラウザを閉じることを忘れないようにしましょう。

ブラウザを閉じる
browser.quit()

実践

環境構築ができたので、こちらの Web サイトでスクレイピングを行っていきましょう。

Web スクレイピング入門

※ 本サイトは、サイトの所有者に事前に許可を得てアクセスしておりますので、皆様も安心してご使用いただけます。
ただし、繰り返しアクセスをしてしまうとサイトに負荷がかかってしまうため、アクセスのしすぎにはご注意ください。

実装の流れ

実装は、以下の3つの流れで行います。

  1. サイトの構成を把握
  2. 特定のデータを取得
  3. CSVファイルで出力

ここでは、抽象的に挙げましたが各章で詳しく解説していくので、今はイメージを持つだけで問題ありません。

1. サイトの構成を把握

環境構築ができたので、すぐにスクレイピングを行いたいところですが、まずはサイトの構成を把握するところから行いましょう。
理由としては、作業が途中で進まなくなったり非効率な順番でデータを取得してします可能性があるからです。
このようなことを避ける為にも、一番始めにサイトの構成をしっかりと把握しておきます。

それでは、先ほどのサイトのトップページから構成を確認していきます。(https://scraping-for-beginner.herokuapp.com/)

構成1_修正.jpg

更に細かく分けることはできると思いますが、今回は 4 つに分けて考えていきます。

① ヘッダー
② ページ内リンク
③ メインテキスト
④ ページ内リンクボタン

ページ内リンクがあることがわかったので、 ④ のランキングボタンをクリックしてみます。

クリック後は、「観光地ランキングのページ」に遷移していることがわかりました。
それではこのページの構成も確認していきたいと思います。
ランキング.jpg

① 現在のURL:https://scraping-for-beginner.herokuapp.com/ranking/
② ヘッダー
③ タイトル
④ ランキング + 観光地名
⑤ 総合評価( 5 段階)
⑥ 詳細の評価とコメント

ランキングページは、情報量が多く細かい構成になっていることがわかります。ですが、このように事前に構成を確認することで、どのデータが取得できるかを把握することができます。

2. 特定のデータを取得

サイトの構成を把握が把握できたので、本題のスクレイピングを行います。
今回は、「観光地名・ 総合評価」の 2 つの要素を取得したいと思います。

要素を指定する場合には、HTML で対応付けされている属性( id や class )デベロッパーツールで確認する必要があります。

デベロッパーツールは Google Chrome のデバッグツールで、 Web サイトの HTML 構成や表示スピードなどを確認できます。

「右クリック > 検証」もしくは、「ブラウザのメニュー > その他のツール > デベロッパーツール」で開くことができます。

devtool.gif

観光地名を取得

まずは、トップページにアクセスが必要です。

Selenium はブラウザの自動操作ができるので、トップページにアクセスしてランキングボタンをクリックしてもいいですが、ランキングページの URL がわかっているので、今回は直接アクセスしましょう。

アクセスするためには、webdriver.Chrome オブジェクトを生成して、browser.get() の引数に URL を渡すことでアクセスできます。その URL のソースコードを print() で表示させます。

先ほどブラウザを閉じているので、立ち上げるところから始めていきます。

ブラウザ立ち上げ
#ヘッドレスモードでオブジェクト生成
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
browser = webdriver.Chrome('chromedriver',options=options)

#urlを変数に格納
url = 'https://scraping-for-beginner.herokuapp.com/ranking/'
#アクセス
browser.get(url)
print(browser.page_source)

page_source.gif

ソースコードが出力されてアクセスできたことが確認できたので、「観光地 1」という観光地名を取得していきます。

デベロッパーツールを開き、 ① をクリックすると要素を選択できるようになります。今回は観光地名の属性を確認したいので ② 付近をクリックすると、③ で属性を確認することができます。

観光地 1 は、class 名が u_title の div タグ内に記述されていることがわかりました。

構成1_観光地名.jpg

browser.find_element_by_class_name() を使用して u_title クラス内の要素を取得します。

観光地名の取得
name_elem = browser.find_element_by_class_name('u_title')
name_elem.text

観光地1.jpg

中身を確認すると、「ランキング\n観光地名」で格納されているので、split() を使用して観光地名のみを取得します。

観光地名のみを取得
elem = name_elem.text.split('\n')
print(elem)
elem = elem[1]
print(elem)
# elem = name_elem.text.split('\n')[1] ←1行でも書けます

観光地スプリット.jpg

elem を確認すると、観光地名のみを取得できていることが確認できました。

次は複数の観光地名を取得していきます。
同じ class 名の要素を複数取得する場合には、browser.find_elements_by_class_name( ) のように複数形(elements)を使用します。

複数取得して要素数を確認
elems = browser.find_elements_by_class_name('u_title')
print(len(elems))

スクリーンショット 2021-02-10 23.37.32.jpg

最初の要素を確認
elems[0].text

スクリーンショット 2021-02-10 23.37.39.jpg

先ほどと同じ用に、観光地名のみを取得します。

観光地名のみを取得
name_elems = []
for e in elems:
  name_elems.append(e.text.split('\n')[1])

# name_elem = [e.text.split('\n')[1] for e in elems] ←1行でも書けます
print(name_elems)

観光地名_複数.jpg

ページ内の 10 件の観光地名を取得することができました。

総合評価

次に総合評価を取得していきます。先ほどと同じように、デベロッパーツールを使用して確認します。

総合評価は、 class 名が u_rankBox の div タグ内に記述されていることがわかります。
総合評価.jpg

それでは、取得していきましょう。取得方法は先ほどと同じなので、できる方はこれまでのコードを参考に自分で挑戦してみてください。

総合評価を取得
evl_elem = browser.find_element_by_class_name('u_rankBox')
evl_elem.text

総合評価が取得できていることが確認できたので、複数取得していきます。

複数取得して要素数を確認
elems = browser.find_elements_by_class_name('u_rankBox')
print(len(elems))

スクリーンショット 2021-02-10 23.44.14.jpg

観光地名と同じように 10 件取得できました。あとは、for 文で各要素のテキストを取得します。

テキストのみを取得
evl_elems = [e.text for e in elems]
print(evl_elems)

スクリーンショット 2021-02-10 23.44.25.jpg

これで 2 つの要素は取得できたので、browser を閉じます。

ブラウザを閉じる
browser.quit()

【補足】ランキングボタンをクリック

今回はランキングページに直接アクセスしましたが、Selenium はブラウザを自動操作することができるので、トップページのランキングボタンをクリックしてページ遷移後にデータを取得することもできます。

まずは、トップページへアクセスをします。クリック後に遷移できているかを確認したいので現在の URL を出力しておきます。

Headlessモードでブラウザ立ち上げ
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
browser = webdriver.Chrome('chromedriver',options=options)

#urlを変数に格納
url = 'https://scraping-for-beginner.herokuapp.com/'
#アクセス
browser.get(url)
#現在のURLを確認
print(browser.current_url)

スクリーンショット 2021-02-10 23.06.41.jpg

ランキングボタンは、これまでと同じようにデベロッパーツールで確認すると、 id 名が card-action の div タグ内の a タグで記述されていることがわかります。

ランキングボタンクリックの流れは、以下の通りです。

  1. 要素を指定
  2. インデックスを指定
  3. クリック
要素を指定
elem = browser.find_element_by_id('card-action')
buttons = elem.find_elements_by_tag_name('a')
print(len(buttons))

スクリーンショット 2021-02-10 23.05.53.jpg

a タグが3つあるので、要素数も3と出力されています。

a タグには属性が無いので、インデックスでランキング要素を指定してクリックします。

インデックスを指定してクリック
buttons[1].click()
#現在のURLを確認
print(browser.current_url)

クリック後.jpg

URL がランキングページの URL と一致しているので、クリックできていることが確認できました。

3. CSV ファイルで出力

最後に取得したデータを CSV 形式で出力していきます。スクレイピングとは関係はありませんが、実務の場合はデータを取得して保存しておかないとデータを利用できないので、CSV 形式で出力していきます。

まずは、Python パッケージの Pandas を使用して、各データを DataFrame に格納します。

DataFrameを作成
import pandas as pd

#カラムを定義
columns = ['観光地名', '総合評価']
#DataFrameを作成
df = pd.DataFrame(columns=columns)

#確認
df

各データが格納されている変数を df に格納して、中身の確認をします。

データを格納
df['観光地名'] = name_elems
df['総合評価'] = evl_elems

#上位3件を確認
df.head(3)

df_確認.jpg

確認もできたので、CSV 形式で出力をします。

CSVで出力
df.to_csv('sample.csv')

コードを実行すると、サイドバーに sample.csv が作成できていることがわかります。

csv出力.gif

作成ができたら、 サイドバーの sample.csv にカーソルを合わせて、︙ -> ダウンロードをクリックすると CSV ファイルがダウンロードされます。

スクリーンショット 2021-02-10 23.31.12.jpg

おわりに

このように、簡単にスクレイピングから CSV 形式で出力まで行うことができました。
スクレイピングと聞くと難しいイメージを持ちますが、実際のコードを書いてみると似たようなコードが多く覚えることも少ないと思います。

次回の記事では、ログイン処理やタイムアウトなどの処理も含めたデータの取得をやっていきましょう!

お知らせ

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_130181_36206be5-499a-66df-a401-a28a66f2b3d2.jpeg

動画を通じて、ディープラーニングが一から学習できる大人気コースの脱ブラックボックスが無料になりました。

手書きの数学とハンズオン形式のプログラミングによって、初学者でも安心して一から学習できます。

機械学習やディープラーニングを基礎から実践を学びたい方は、ぜひ教材の1つとしてご利用ください!

▶︎ 脱ブラックボックスコースを無料で学び始めたい方はこちら!



Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
113
Help us understand the problem. What are the problem?