2 回答
TA贡献1796条经验 获得超7个赞
如果您可以做一个简化的假设,例如,您要解析的对象}与行首的最终齐平,这很容易:
import ast
import re
from bs4 import BeautifulSoup
html = """
<script>
// we don't care about this script tag
</script>
<script>
var productArticleDetails = {
'0399310001': {
'normalImages': [
{
'thumbnail': '//image-path.jpg',
}
]
}
}
var someOtherThing = 42;
</script>
"""
soup = BeautifulSoup(html, "lxml")
for script in soup.find_all("script"):
pattern = r"^var productArticleDetails = (.+?^})"
if m := re.search(pattern, script.text, re.M | re.S):
data = ast.literal_eval(m.group(1))
break
print(data["0399310001"]["normalImages"][0]["thumbnail"])
输出:
//image-path.jpg
但是,如果你不能做出这个假设,也许你可以做出不同的假设,比如“把所有东西都拿起来,直到下一个空行作为对象”:
pattern = r"^var productArticleDetails = (.+?^\s*$)"
如果这仍然太脆弱并且对象可能是任何形式,那么我们就会遇到正则表达式不适合的平衡括号检测问题。您可以使用堆栈来确定对象何时结束(如果数据包含}内部字符串,请小心,但这是一个可导航的解析问题)。
请注意,ast.literal_eval()如果 JS 对象的键周围没有引号,则会失败,因此您可能还需要为这种情况做一些准备。目前尚不清楚这是否是您需要的静态一次性解析,或者您是否正在寻找可以承受任何 JS 对象格式的强大解决方案。
json.loads在这里非常没用,因为它假定 JSON 格式完美。JS 对象几乎从不采用这种形式,如此处所示。
TA贡献1864条经验 获得超6个赞
import json
from bs4 import BeautifulSoup
html = """<script type="application/ld+json">
var productArticleDetails = {
"@context" : "https://schema.org",
"@type" : "BreadcrumbList",
"itemListElement": [ {"@type":"ListItem","thumbnail":"//image-path.jpg","item":{"@id":"https://www.myntra.com/","name":"Home"}},{"@type":"ListItem","position":2,"item":{"@id":"https://www.myntra.com/clothing","name":"Clothing"}},{"@type":"ListItem","position":3,"item":{"@id":"https://www.myntra.com/men-clothing","name":"Men Clothing"}},{"@type":"ListItem","position":4,"item":{"@id":"https://www.myntra.com/shirts","name":"Shirts"}},{"@type":"ListItem","position":5,"item":{"@id":"https://www.myntra.com/formal-shirts-for-men","name":"Formal Shirts For Men"}} ]
}
</script>"""
soup = BeautifulSoup(html, 'html.parser')
sc = soup.find("script").text
data = sc.split("=", 1)[1]
ld = json.loads(data)
# print(json.dumps(ld, indent=4))
print(ld["itemListElement"][0]["thumbnail"])
输出:
//image-path.jpg
添加回答
举报