LoginSignup
3
2

More than 1 year has passed since last update.

【Python】WebスクレイピングでHTML内のscriptタグにあるJavaScriptの変数(JSON)を抽出したい

Last updated at Posted at 2022-06-28

Webスクレイピングでは通常、クローラーで取得したHTMLの中から、metaタグにあるページのメタ情報やtableタグにある表形式のデータなどを抽出する。
scriptタグの中に埋め込まれた動的スクリプト内で、varで宣言されたJavaScriptの変数(JSON)に欲しい情報が入っている場合、下記のような方法で抽出できる。

環境

Python 3.9
macOS

コード

sample.py
import json
import re
from bs4 import BeautifulSoup as bs


def extract_js_var(soup, js_var):
    script = soup.find('script', text=re.compile(js_var, re.DOTALL))
    regex = '(?:var ' + js_var + ' = )({.*?})(?:;)'
    json_str = re.search(regex, script.string).group(1)
    return json.loads(json_str)


if __name__ == "__main__":
    html = '''
    <script>var initialResponse = {"publishDate":"2022-06-28","author":"cgshimo","category":"Python"};</script>
    '''
    soup = bs(html, 'html.parser')
    initial_response = extract_js_var(soup, 'initialResponse')
    print(initial_response)

実行結果

$ python3 sample.py
{'publishDate': '2022-06-28', 'author': 'cgshimo', 'category': 'Python'}

extract_js_var 関数をちょこっと解説

1行目

Beautiful Soupのfindメソッドは、第一引数(name)で指定されたタグ名「script」を検索し、最初に見つけた要素を返す。
textで検索対象の正規表現を渡している。ここでは、JavaScriptの変数名を正規表現オブジェクトにコンパイルしている。

2行目

varで宣言された変数(JSON)を抽出するための正規表現を定義している。
抽出(キャプチャ)対象は、2番目に丸括弧で囲われた({.*?})にマッチする文字列。
丸括弧内の冒頭に?:をつけることでキャプチャ対象としないことができ、余計な文字列を簡単に除ける。

この正規表現は、実際のHTMLのscriptタグ内の変数の定義のされ方によって適宜修正する。

3行目

2行目で定義した正規表現パターンで、1行目で見つけたscriptタグ要素内の文字列からJSONの抽出を試みる。
末尾のgroupメソッドで、正規表現内の({.*?})でキャプチャした文字列を選択している。

4行目

3行目で抽出したJSON文字列をPythonの辞書型にパースして、関数の返り値とする。

このコードの懸念点

ここで使用している正規表現では、下記のようなJSONをパースするときにエラーが出てしまう。
key2のvalueに、};が入っており、これにマッチしてしまう。
JSONにデコードできない文字列として抽出してしまう。
このようなパターンは、JSONの中にスクリプト言語のソースコードが文字列として入ってきた場合などが考えられる。

# エラーとなるケース
var initialResponse = {"key1": "value1", "key2": "val};ue2"};

正規表現をもう少し工夫して、汎用的な関数にできそう。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2