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

2024-04-20 00:25:17 发布

您现在位置:Python中文网/ 问答频道 /正文

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

<script>
var productArticleDetails = {
   ...
   '0399310001': {
      ...
      'normalImages': [
         {
            'thumbnail': '//image-path.jpg',
            ...
         }
      ]
   }
}     

所以我只想提取图像路径

在返回的“soup”中,它不是封装在脚本标记中的唯一内容,代码中还有大量其他javascript标记。到目前为止,我已将HTML保存到变量中,然后运行:

soup = BeautifulSoup(html)
scripts = soup.find_all('script')

因此,我只剩下一个对象,它包含来自html的所有<script>元素

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

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

有人能帮忙吗?干杯


Tags: 对象标记图像gt路径脚本节点产品
2条回答

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

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*$)"

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

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

json.loads在这里是非常无用的,因为它假定格式完全正确的JSON。JS对象几乎从来没有这样的形式,如图所示

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

相关问题 更多 >