【Python】Javascriptでレンダリングされるサイトをスクレイピングする方法

Python

サイトのスクレイピングはBeautifulSoupやSeleniumといったライブラリを利用して行うことができますが、中には簡単にはスクレイピングできないようなサイトもあります。

例えばJavascriptで制御されているサイト、いわゆる動的なサイトはブラウザでサイトが開かれた後にJavascriptが実行され、そこではじめてHTMLが生成・描写されるためBeatifulSoupでは取得できません。React.jsやAngular.js、JQueryといったフレームワークを利用して作られたサイトなど、Javascriptで制御されているサイトは数多くあり、増加傾向にあります。

Seleniumでブラウザを開き、ゴリゴリにやっていくことも不可能ではありませんが、いまいち動作が安定しないのと、何かと不具合が多いのでこちらも簡単ではありません。

今回はBeautifulSoupよりもシンプルに、Seleniumよりも安定してJavascriptでレンダリングされるサイトをスクレイピングできるAPIを発見したので紹介したいと思います。

その名はScrapingBee

ScrapingBeeではJavascriptで制御されたページで何かしらの操作(クリックやスクロールなど)をした後しか表示されないような内容まで簡単にスクレイピングすることができます。以下ではScrapingBeeの使い方を解説していきます。

APIキーを取得

まずはScrapingBeeを利用するためにAPIキーが必要ですので、公式サイトから取得します。

リンクをクリックすると上のような画面が表示されると思いますので、Try ScrapingBee for Freeをクリックしてください。

その後、メールアドレスまたはGoogleアカウントまたはGithubアカウントで登録するかを選べますので、お好きな方法で登録してください。

登録が完了したら以下のダッシュボード画面が表示されると思います。(されない場合はもう一度トップページがTry ScrapingBee for Freeをクリックするとダッシュボードに飛びます)

右上にYour API Keyセクションがあるので、CopyをクリックしてAPIキーを保存しておいてください。

Pythonコードを書く

ScrapingBeeライブラリを利用しますので、以下のコマンドでインストールします。

pip install scrapingbee
from scrapingbee import ScrapingBeeClient

client = ScrapingBeeClient(api_key='YOUR-API-KEY')

response = client.get("YOUR-URL")


print('Response HTTP Response Body: ', response.content)

Pythonコードは上記のたった4行です。

以下のような結果が返ってきます。

<html>
  <head>
     ...
  </head>
  <body>
     <content>
     </content>
     <content>
     </content>
     <content>
     </content>
      <content>
     </content>
     <content>
     </content>
  </body>
</html>   

ScrapingBeeClientオブジェクトを自分のAPIキーで作成したらgetメソッドにスクレイピングしたいサイトのURLを渡すだけです。getメソッドにparamsに辞書型のパラメーターを渡すことで様々な動作を指定することができます。下のrender_jsというパラメーターはデフォルトではTrueになっており、これによりJavascriptで描写されるサイトでもスクレイピングできるようになっています。

response = client.get('YOUR-URL',
    params = { 
        'render_js': 'False',
    }
)

render_jsをFalseにした場合の結果は以下のようになります。

<html>
  <head>
  ..
  </head>
  <body>
  </body>
</html>  

Javascriptが描写されない状態で取得しているので、bodyタグの中身が空になってしまっています。

クリックやスクロールをさせてスクレイピングする

ScrapingBeeAPIはスクレイピングしたいサイトに対して何かしらのアクションをさせなければいけない場合でもパラメーターにjs_scenarioを渡すことによって実際のブラウザを操作しているかのような挙動を実現できます。

たとえばページ内のあるボタンをクリックしないと表示されないデータがある場合、そのボタンをクリックさせなければいけません。その場合、以下のコードで実現できます。


from scrapingbee import ScrapingBeeClient

client = ScrapingBeeClient(api_key='YOUR-API-KEY')

response = client.get('YOUR-URL',
    params = { 
        'js_scenario': '{"instructions": [{"click": "#buttonId"}]}',
    }
)

print('Response HTTP Status Code: ', response.status_code)
print('Response HTTP Response Body: ', response.content)

js_scenario’: ‘{“instructions”: [{“click”: “#buttonId”}]}の#buttonId部分にクリックしたいボタンのIDを指定するだけです。

便利なものとして以下のようなものがあります。他にもありますので、もっと知りたい方は公式ドキュメントを参考にしてください。

{"click": "#button_id"} # 要素をクリックさせる
{"wait": 1000} # 指定した時間(ミリ秒)待機
{"wait_for": "#slow_div"} # CSSで指定された要素が描写されるまで待機
{"wait_for_and_click": "#slow_div"} # CSSで指定された要素が描写されるまで待機し、その後要素をクリック
{"scroll_x": 1000} # 指定したpx分水平方向にスクロール
{"scroll_y": 1000} # 指定したpx分垂直方向にスクロール
{"fill": ["#input_1", "value_1"]} # input_1のIDを持つ要素に"value_1"を入力
{"evaluate": "console.log('toto')" # 指定したJavascriptコードを実行

javascriptで描写されるサイトの中には要素が描写されるまで時間がかかるものもあり、描写が終わる前にスクレイピングしてしまうと中身が取得できていないことも多々あります。秒数指定でもいいのですが、描写までどれくらいかかるかわからないので安定しませんし、だからといって長く待ちすぎるのも嫌なので、wait_forはかなり便利です。秒数指定ではなく要素指定なので、その要素が描写されてから確実にスクレイピングしてくれます。

その他にも便利な機能がたくさんあるので、スクレイピングを極めたいならScrapingBeeは利用しない手はないでしょう。

プロフィール

プロフィール
コードラボJP

大学卒業後SEに就職、現在は退職しフリーランスとして活動中。
『初心者でも挫折せずに一人でプログラミングを学べる』をモットーに、コードラボJPを開設
お問い合わせ等はcodelabsjp@gmail.comまで

コードラボJPをフォローする
タイトルとURLをコピーしました