【Python】Requests、Beautiful Soupでスクレイピングした結果をスプレッドシート、Excelに出力しよう

python

みなさんこんにちは。zak-papaです。

以前に「Google スプレッドシート」を操作する「gspread」と「Excel」を操作する「OpenPyXL」の基本的な操作方法についてお伝えしました。

python【Python】「gspread」で「 Googleスプレッドシート」のワークブック、ワークシートを操作してみよう python【Python】「OpenPyXL」で「Excel」のワークブック、ワークシートを操作してみよう

 

今回はPythonが得意とする「スクレイピング」の方法と、その結果を「Google スプレッドシート」と「Excel」に出力する方法をお伝えしたいと思います。

なお、今回スクレイピングするのは次のものです。

スクレイピングする対象

私のサイト(zak-papa)の直近の記事「5つ」の中からそれぞれ次の「4つ」

  1. 「タイトル」
  2. 「記事のURL」
  3. 「記事の画像」 ※ スプレッドシートのみ
  4. 「記事の画像のURL」

 

イメージはこちら(最初の2つ目まで表示)
※ 今回はデータ量も少ないのでリクエスト回数は無視して1つずつセルに出力しています。

requests_bs4

 

 

今回スクレイピングする方法として「Requests」「Beautiful Soup」モジュールをインストールして使っていきます。

なお、「ログイン」が必要なWebサイトや「JavaScript」が使われているWebサイトは「Selenium」モジュールを使って画面を自動操作してスクレイピングすることができます。こちらは別の機会にお伝えできればと思います。

では、スクレイピングの方法を順に見ていきましょう。

 

 

 

 

「スクレイピング」する準備をしよう

事前準備

今回もデスクトップに「python_scraping」ディレクトリ(フォルダ)、その中に「scraping_bs4.py」ファイルを作成してコードを書いていきます。

私の動作環境は次の通りです。ご自身の使い慣れているものをお使いいただければと思います。
Windowsでも同じように動作すると思います。

OS macOS Catalina 10.15.3 Version Python 3.7.4
エディタ Visual Studio Code ブラウザ Google Chrome
ディレクトリ Desktop/python_scraping ファイル scraping_bs4.py

 

今回はスクレイピングした結果を「スプレッドシート」と「Excel」に出力するので、次の2点も同じフォルダに入れておきましょう。

①「秘密鍵(JSONファイル:spreadsheet-sample.json)」
②「Excelファイル(scraping_excel.xlsx)」 ※ 新規作成する場合は不要

 

python_scraping

 

※ Pythonからスプレッドシートを操作する「初期設定」が完了している前提で説明します。初期設定が完了していない場合はこちらを参考に設定をお願いします。

gspread【Python】「gspread」で「Google スプレッドシート」を操作するための「初期設定」をしよう

 

 

下記のコードは「スプレッドシート」を操作する際に毎回同じ内容のものであるとお伝えしましたね。今回もこの後に続けてコードを書いていきます。

7行目には取得した「秘密鍵(JSONファイル)」の「ファイル名(私の場合は「spreadsheet-sample.json」)」を入力してください。

 

 

「Requests, Beautiful Soup」のインストール

今回スクレイピングに使用するのは「Requests」と「Beautiful Soup」モジュールです。

上記2つは簡単にいうと次の通りです。

「Requests」は、Webページをダウンロードするためのモジュール
「Beautiful Soup」は、HTML、XMLファイルからデータを抽出するためのモジュール

 

標準ライブラリの「urllib.request」モジュールでも取得はできますが、「requests」モジュールを使った方がより簡単に取得することができます。

使い方は後ほど説明しますが、どちらもPython付属ではないためインストールが必要です。次のようにターミナルに入力してインストールしましょう。

※ インストール時は「beautifulsoup4」なので注意

 

 

「インストール」が完了したら、次のように「インポート」して事前準備完了です。この後にスクレイピングするコードを書いていきましょう。

※ インポート時は「bs4」なので注意

 

 

「Requests」でWebページをダウンロードしよう

まずは、「Requests」モジュールでWebページをダウンロードします。

「Webページ」をダウンロード

Webページのダウンロードは、「requests.get()」関数を使い、取得したい「URL」を渡します。
※「get()」はHTTPメソッドでいう「GET」ですね。他にも「POST」や「PUT」などもありますが今回はデータ取得の説明のため割愛します。

 

では、「本ブログ(zak-papa)」のWebページを取得してみましょう。 

 

たったこれだけで、Webページのダウンロードができます。わかりやすいし簡単ですね。

 

 

「ダウンロードファイル」の確認

さて、ダウンロードしたページは変数「res(Responseオブジェクト)」に格納されているわけですが、その中身を確認してみましょう。

例えば、「status_code」属性によってWeb ページのリクエストが成功したかどうかを確認することができます。

 

上記の結果のように「200」であればリクエストに成功したことになります。ちなみによく見る“Not Found”は「404」になります。

【参考】HTTPステータスコード − フリー百科事典『ウィキペディア(Wikipedia)』

 

 

続いて、「text」属性で「文字列」として出力してみましょう。
次のように文字数をカウントしてみると約50,000字だったので、最初の「500文字」だけ出力してみます。

 

なんとか「タイトル」らしきものまで表示できました。

 

 

「ダウンロードファイル」のエラーチェック

最後に、「エラーチェック」のコードを確認しておきましょう。

Webページがダウンロードできたかどうかを、毎回「status_code」属性で「200」かどうか確認するのは手間であり、もっと簡単にエラーチェックをするための「raise_for_status() 」メソッドがあります。

このメソッドは、ファイルのダウンロードが失敗すればエラーを起こしますが、成功したときは何もしません。

例えば、次のような場合はURLが存在しないのでエラーとなり処理が止まります。

 

一番下の行に「HTTPError: 404」の記載があり、ページが取得できず処理が止まっています。
「raise_for_status()」メソッドも毎回コードに入れておくようにしましょう。

raise_for_status

 

 

 

「Beautiful Soup」でデータを取得しよう

続いて、「Beautiful Soup」モジュールで先ほどダウンロードしたWebページのHTMLから取得したい情報を探して取得してみましょう。

「Beautiful Soup」オブジェクトの生成

次のように、「bs4.BeautifulSoup()」関数の引数に「HTML文字列(res.text)」と「パーサー(html.parser)」を指定して「BeautifulSoupオブジェクト」を生成します。そして、生成されたオブジェクトを変数「soup」に格納します。

 

「パーサー」とは、HTMLを解析するための機能のことで「lxml」や「html5lib」などもありますが、それらを使用するためには「インポート」する必要があります。
今回はPythonに標準で付属している「html.parser」を指定しています。何か処理に困り始めたら他の「パーサー」を使用してみるのが良いでしょう。

 

 

では、「soup」の中身を「print(soup)」で出力してみましょう。

すると、大量のデータが出力されますが、下の方にスクロールしていくと「a」タグや「h2」タグなどに囲まれた、今回取得目的である「記事のURL」や「記事のタイトル」を見つけることができます。

BeautifulSoupオブジェクト

 

 

この中から取得していけば良いですが、次のように「h2」タグなどの「タグ名」を付けてあげれば取得したい情報を抽出することができます。ただ、これではそれぞれ「1つ」しか取得することはできません。

 

ブログタイトルと記事タイトルの取得

 

 

実際は、「h2」タグや「a」タグだけでは他の要素も取得できてしまうことが多いため、「id」属性や「class」属性などと一緒に取得することがほとんどです。また、上記から探すのは少し見つけにくいですよね。

そこで便利な機能が、「Google Chrome」の「デベロッパーツール」です。
「デベロッパーツール」を使えば、取得したい情報のHTMLの「構造」や「パターン」が見つけやすくなります。(下図の赤枠)

デベロッパーツール

 

次からその使い方を見ていきましょう。

 

 

「デベロッパーツール」の使い方

まずは「デベロッパーツール」の開き方から説明します。

開きたいWebページ上で「右クリック」→ 「検証」から開くことができます。また、ショートカットキーも用意されています。

【Mac】⌘ command + Option + I
【Windows】Ctrl + Shift + I または F12

デベロッパーツールの開き方

 

 

先ほどと同じような画面が開いたと思います。

では、ここからどのようにHTMLの構造を探すかというと、

①「デベロッパーツール」の左上の「マーク」をクリック
②「取得したい要素」をクリック
③  色が変わって「フォーカス」される

このような流れで取得したい要素を探せます。

 

下記では、「記事のタイトル」である「h2」タグがフォーカスされていますね。

デベロッパーツールの使い方

 

 

「select()」メソッドで要素を取得

では、「デベロッパーツール」から今回取得したい「4つ」を探してみましょう。

要素を取得するには、「select()」メソッドに検索したい要素の 「CSSセレクタ」を渡します。class属性であれば「.(ドット)」、id属性であれば「#」を付けるといった感じですね。

「CSSセレクタ」については下記サイトを参考していただければと思います。
【参考】あなたはいくつ知ってる?CSSのセレクタ40個を総まとめ【チートシート付き】

 

 

まずは、「記事のタイトル」を取得します。
「デベロッパーツール」で確認すると次のような構造になっています。

記事タイトル

 

 

記事のタイトルは「cardtype__article-info」クラスの中の「h2」、つまり「.cardtype__article-info h2」という書き方で取得できそうです。他の記事のタイトルも確認してみると同じ構造になっているのがわかると思います。

記事タイトル

 

コードはこちら。「for」文で1つずつ出力してみます。

 

ターミナルで実行してみると、記事のタイトルが取得できましたね。ただ、「h2」タグも一緒に付いてきてしまっています。

記事タイトルの取得_タグ付き

 

 

純粋に「記事タイトルのみ」を取得したい場合は、「getText()」メソッドで取得することができます。

 

無事、記事タイトルのみ取得できましたね。

記事タイトルの取得_タグなし

 

 

 

最終的には、「スプレッドシート」と「Excel」に出力したいので、記事タイトルをいったんリストに格納しておきたいと思います。
空の「titles」リストをまずは作成し、そこに「append()」メソッドで追加していきます。

 

 

記事タイトルがリストに格納されましたね。これでまずは「記事のタイトル」の取得は完了です。

タイトル記事をリストに格納

 

 


続いて、「記事のURL」を取得してみましょう。

「記事のタイトル」と同じように「デベロッパーツール」を確認してみると、「cardtype__article」クラスの中の「a」タグの中の「href」属性に「記事のURL」があるため、「.cardtype__article a」と記述すれば良さそうです。

記事のURLの取得

 

 

ただ、今回はそのままではうまくいきません。
なぜなら、「cardtype__article」クラスの中に「a」タグが「2つ」あり両方取得してしまうからです。どうやら、2つ目は「カテゴリー」のURLのようですね。

記事のURLの取得_2つ

 

 

なので、今回は親要素は使わずに、「a」タグの中にあるクラス名の「cardtype__link」を使えば良さそうです。「.cardtype__link」とすればいいですね。「.(ドット)」の前に「a」は付けても付けなくても結果は同じです。

また、「href」のような「属性」を取得する場合は、先ほどの「getText()」メソッドではなく、「get()」メソッドに「属性」を渡してあげて取得します。

コードはこちら。

 

記事のURLが取得できました。

記事URLの取得

 

 

こちらも同じようにリストに格納しておきましょう。

 

 


最後に「記事の画像のURL」を取得してみましょう。
※「記事の画像(スプレッドシートへの出力のみ)」については、「記事の画像のURL」があれば「関数」で表示できます。

「デベロッパーツール」で確認してみます。

記事の画像のURL

 

 

今回は親要素の「p」タグの中にあるクラス名の「cardtype__img」を使って、「.cardtype__img img」とすれば良さそうです。今回取得したいのは「src」属性のため、先ほどと同じように「get()」メソッドに「属性(src)」を渡して取得します。

コードはこちら。

 

 

記事の画像のURLも取得できました。

記事の画像のURLの取得

 

 

もう1つ応用で、スプレッドシートの「IMAGE関数」で実際の画像も表示させてみたいと思います。下図の「C列」に表示させます。

IMAGE関数

 

先ほど取得した「記事の画像のURL」を「image」に渡してあげればいいだけですね。コードをプラスで連結しましょう。

 

これで関数も出来上がりました。

IMAGE関数の出力

 

 

最後に先ほど出力した2つを同じようにリストに格納しておきます。

 

 

以上で、取得したいデータ4つは揃いました。

 

 

「スクレイピング」結果を出力してみよう

では、最後に取得したデータを出力してみましょう。

「Google スプレッドシート」に出力

まずは、「Google スプレッドシート」に出力します。これまでのコードを表示しつつ、スプレイピング結果を出力するコードを追記します。(44行目以降)

セルの扱い方については前回説明しているので割愛します。

python【Python】「gspread」で「 Googleスプレッドシート」のセルの値を取得・入力するなどセルを操作してみよう

 

もし、他のスプレッドシートに出力する場合は、スプレッドシートの「共有」設定を行い、下記コードの「スプレッドシートキー」の部分を変更して出力していただければと思います。

 

 

 

冒頭のイメージのように順に出力され、直近の記事5つの4項目が出力されたと思います。

スプレイピング出力結果_スプレッドシート

 

 

「Excel」に出力

続いて、「Excel」に出力します。「Excel」に出力するためには「OpenPyXL」モジュールを使えば良かったですね。こちらも以前の記事をご参考いただければと思います。

python【Python】「OpenPyXL」で「Excel」のセルの値を取得・入力するなどセルを操作してみよう

 

では、こちらは「Excel」に出力するコードのみ表示します。

 

 

こちらも無事「Excel」に出力されました。

スプレイピング出力結果_Excel

 

 

  終わりに

以上、「Requests」「Beautiful Soup」モジュールを使ったスクレイピングの方法をお伝えしました。

スクレイピングした結果を「Google スプレッドシート」と「Excel」にも出力できましたね。

冒頭にもお伝えした通り、「ログイン」が必要なWebサイトや「JavaScript」が使われているWebサイトは「Selenium」モジュールを使って画面を自動操作してスクレイピングすることができます。

こちらについては次回お伝えしたいと思います。

 

以上となります。最後まで読んでいただきありがとうございました!