Javascript 使用Beauty Soup从特定脚本标记中查找嵌套的JS对象值

Javascript 使用Beauty Soup从特定脚本标记中查找嵌套的JS对象值,javascript,python,django,beautifulsoup,Javascript,Python,Django,Beautifulsoup,我正在用漂亮的汤抓取一个站点的图片,到目前为止,这对每个站点都很有效,我甚至创建了一些自定义案例类型。但是有一个特定的站点引起了我的问题,因为iit返回了一个JavaScript对象中的所有图像,该对象内联包装在一个脚本标记中。该对象非常大,因为它包含所有产品信息,我要查找的特定位嵌套在productArticleDetails>[产品id]>normalImages>缩略图>[图像路径]中相当深。像这样: <script> var productArticleDetails = {

我正在用漂亮的汤抓取一个站点的图片,到目前为止,这对每个站点都很有效,我甚至创建了一些自定义案例类型。但是有一个特定的站点引起了我的问题,因为iit返回了一个JavaScript对象中的所有图像,该对象内联包装在一个脚本标记中。该对象非常大,因为它包含所有产品信息,我要查找的特定位嵌套在productArticleDetails>[产品id]>normalImages>缩略图>[图像路径]中相当深。像这样:

<script>
var productArticleDetails = {
   ...
   '0399310001': {
      ...
      'normalImages': [
         {
            'thumbnail': '//image-path.jpg',
            ...
         }
      ]
   }
}     
因此,我只剩下一个对象,它包含
html
中的所有
元素

不知何故,在
scripts
对象中,我需要在JS的正确块中找到特定节点,并返回嵌套在
normalImages
节点下的
thumbnail
节点的值,反过来,它将嵌套在一个数字字符串下面,这些数字最终全部保存到
productArticleDetails
var

我想我需要在
脚本
对象上执行
for
循环,但我没有找到提取特定数据位的方法。我所看到的其他一切都是基于一个假设,即只有1位javaScript,并且您所寻找的值不是嵌套的


有人能帮忙吗?干杯。

如果你可以做一个简单的假设,比如说,你想要解析的对象的最后一个
}
与行的开头齐平,那么很容易:

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"])
然而,如果你不能做出这个假设,也许你可以做出一个不同的假设,比如“把所有的东西作为对象,直到下一个空行为止”:

如果这仍然太脆弱,并且对象可能是任何形式的,那么我们就会遇到平衡括号检测问题,而regex并不适合这些问题。您可以使用堆栈来确定对象何时结束(如果数据中包含
}
字符串,请小心,但这是一个可导航的解析问题)

请注意,如果JS对象的键周围没有引号,则
ast.literal\u eval()
将失败,因此您可能还需要为这种情况做一些准备。目前还不清楚这是否是您需要的静态一次性解析,或者您是否正在寻找一个能够承受任何JS对象格式的健壮解决方案

json.loads
在这里是非常无用的,因为它假定格式完全正确的json。JS对象几乎从未以这种形式出现,如图所示。

import json
从bs4导入BeautifulSoup
html=”“”
var productArticleDetails={
“@context”:”https://schema.org",
“@type”:“面包屑列表”,
“itemListElement:[{@type:”ListItem“,”缩略图“//image path.jpg“,”项目“:{@id:”https://www.myntra.com/“,”名称“:”Home“}},“{@type:”列表项“,”位置“:”2,“项“:{@id:”https://www.myntra.com/clothing“,”姓名“:”服装“}},“{@type:”列表项“,”位置“:”3,“项目“:{@id:”https://www.myntra.com/men-clothing,“姓名”:“男装”},{@type”:ListItem,“位置”:4,“项目:{@id:”https://www.myntra.com/shirts“,”姓名“:”衬衫“}},“{@type:”列表项“,”位置“:”5,“项目“:{@id:”https://www.myntra.com/formal-shirts-for-men,“姓名”:“男士正式衬衫”}]
}
"""
soup=BeautifulSoup(html,'html.parser')
sc=soup.find(“脚本”).text
数据=sc.split(“=”,1)[1]
ld=json.load(数据)
#打印(json.dumps(ld,缩进=4))
打印(ld[“itemListElement”][0][“缩略图”])
输出:

//image-path.jpg

如果你发布了一个有效的
脚本,我会让你轻松访问它。你能完成匹配直到最后一次出现
}
吗一旦完成,按CTRL+SSORY,你想问什么?如何匹配直到最后一次出现
}
我已经能够匹配到第一次出现
{
,我想完成这个正则表达式,直到结束。我认为这不是很有用,因为脚本几乎肯定会包含多个对象或大括号块,但您可以执行
productArticleDetails\s=\s{(\n |.*)*}
或使用dotall.@ggloren谢谢。明白了。仅供注意。
pyjsparser
可以解析格式错误的
JSON
类似
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"])
pattern = r"^var productArticleDetails = (.+?^\s*$)"