如何使用 Python 提取在 HTML 页面 javascript 块中定义的 JSON 对象?

2024-03-27

我正在下载其中定义了数据的 HTML 页面,方法如下:

... <script type= "text/javascript">    window.blog.data = {"activity":{"type":"read"}}; </script> ...

我想提取“window.blog.data”中定义的 JSON 对象。 有没有比手动解析更简单的方法? (我正在研究 Beautiful Soap,但似乎找不到一种无需解析即可返回确切对象的方法)

Thanks

Edit:使用 python 无头浏览器(例如 Ghost.py)来执行此操作是否可能且更正确?


BeautifulSoup 是一个 html 解析器;这里你还需要一个 javascript 解析器。顺便说一句,一些 javascript 对象文字不是有效的 json (尽管在您的示例中文字也是有效的 json 对象)。

在简单的情况下,您可以:

  1. extract <script>使用 html 解析器的文本
  2. 假使,假设window.blog...是单行或者没有';'在对象内部并使用简单的字符串操作或正则表达式提取 javascript 对象文字
  3. 假设字符串是有效的 json 并使用 json 模块解析它

Example:

#!/usr/bin/env python
html = """<!doctype html>
<title>extract javascript object as json</title>
<script>
// ..
window.blog.data = {"activity":{"type":"read"}};
// ..
</script>
<p>some other html here
"""
import json
import re
from bs4 import BeautifulSoup  # $ pip install beautifulsoup4
soup = BeautifulSoup(html)
script = soup.find('script', text=re.compile('window\.blog\.data'))
json_text = re.search(r'^\s*window\.blog\.data\s*=\s*({.*?})\s*;\s*$',
                      script.string, flags=re.DOTALL | re.MULTILINE).group(1)
data = json.loads(json_text)
assert data['activity']['type'] == 'read'

如果假设不正确,则代码将失败。

为了放宽第二个假设,可以使用 JavaScript 解析器代替正则表达式,例如,slimit http://slimit.readthedocs.org/ (由@approximatenumber 建议 https://ru.stackoverflow.com/questions/501556/%d0%9a%d0%b0%d0%ba-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b8%d1%82%d1%8c-%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8e-%d0%b8%d0%b7-%d1%81%d1%82%d1%80%d0%be%d0%ba%d0%b8-json-%d0%ba%d0%be%d1%82%d0%be%d1%80%d0%b0%d1%8f-%d1%83%d0%ba%d0%b0%d0%b7%d0%b0%d0%bd%d0%b0-%d0%b2-javascript-%d0%ba%d0%be%d0%b4%d0%b5-%d0%b2%d0%bd%d1%83%d1%82%d1%80%d0%b8/501630#comment598944_501562):

from slimit import ast  # $ pip install slimit
from slimit.parser import Parser as JavascriptParser
from slimit.visitors import nodevisitor

soup = BeautifulSoup(html, 'html.parser')
tree = JavascriptParser().parse(soup.script.string)
obj = next(node.right for node in nodevisitor.visit(tree)
           if (isinstance(node, ast.Assign) and
               node.left.to_ecma() == 'window.blog.data'))
# HACK: easy way to parse the javascript object literal
data = json.loads(obj.to_ecma())  # NOTE: json format may be slightly different
assert data['activity']['type'] == 'read'

不需要处理对象字面量(obj) 作为 json 对象。为了获得必要的信息,obj可以像其他 ast 节点一样递归访问。它将允许支持任意 javascript 代码(可以通过以下方式解析)slimit http://slimit.readthedocs.org/).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Python 提取在 HTML 页面 javascript 块中定义的 JSON 对象? 的相关文章

随机推荐