我正在下载其中定义了数据的 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 对象)。
在简单的情况下,您可以:
- extract
<script>
使用 html 解析器的文本
- 假使,假设
window.blog...
是单行或者没有';'
在对象内部并使用简单的字符串操作或正则表达式提取 javascript 对象文字
- 假设字符串是有效的 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(使用前将#替换为@)