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
添加回答
舉報