猿问

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

我正在用漂亮的汤抓取一个网站来抓取图像,到目前为止,这对每个网站都很好,我什至设法创建了一些自定义案例类型。但是一个特定的站点给我带来了问题,因为它返回了一个 JavaScript 对象中的所有图像,该对象内嵌在一个脚本标记中。该对象非常大,因为它包含所有产品信息,我正在寻找的特定位嵌套在 productArticleDetails > [产品 id] > normalImages > thumbnail > [图像路径] 中。像这样:


<script>

var productArticleDetails = {

   ...

   '0399310001': {

      ...

      'normalImages': [

         {

            'thumbnail': '//image-path.jpg',

            ...

         }

      ]

   }

}     

所以我只想提取图像路径。


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


soup = BeautifulSoup(html)

scripts = soup.find_all('script')

所以我留下了一个包含所有<script>元素的对象html


不知何故,在该scripts对象中,我需要在正确的 JS 块中找到该特定节点并返回thumbnail嵌套在该节点下的normalImages节点的值,该节点又将嵌套在一串数字下方,最终全部保存到productArticleDetailsvar .


我想我需要对对象进行for循环,scripts但没有运气弄清楚如何提取特定的数据位。我所看到的其他所有内容都假设只有 1 位 javaScript 并且您要查找的值不是嵌套的。


任何人都可以帮忙吗?干杯。


蛊毒传说
浏览 349回答 2
2回答

芜湖不芜

如果您可以做一个简化的假设,例如,您要解析的对象}与行首的最终齐平,这很容易:import astimport refrom bs4 import BeautifulSouphtml = """<script>// we don't care about this script tag</script><script>var productArticleDetails = {&nbsp; &nbsp;'0399310001': {&nbsp; &nbsp; &nbsp; 'normalImages': [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'thumbnail': '//image-path.jpg',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; ]&nbsp; &nbsp;}}var someOtherThing = 42;</script>"""soup = BeautifulSoup(html, "lxml")for script in soup.find_all("script"):&nbsp; &nbsp; pattern = r"^var productArticleDetails = (.+?^})"&nbsp; &nbsp; if m := re.search(pattern, script.text, re.M | re.S):&nbsp; &nbsp; &nbsp; &nbsp; data = ast.literal_eval(m.group(1))&nbsp; &nbsp; &nbsp; &nbsp; breakprint(data["0399310001"]["normalImages"][0]["thumbnail"])输出://image-path.jpg但是,如果你不能做出这个假设,也许你可以做出不同的假设,比如“把所有东西都拿起来,直到下一个空行作为对象”:pattern = r"^var productArticleDetails = (.+?^\s*$)"如果这仍然太脆弱并且对象可能是任何形式,那么我们就会遇到正则表达式不适合的平衡括号检测问题。您可以使用堆栈来确定对象何时结束(如果数据包含}内部字符串,请小心,但这是一个可导航的解析问题)。请注意,ast.literal_eval()如果 JS 对象的键周围没有引号,则会失败,因此您可能还需要为这种情况做一些准备。目前尚不清楚这是否是您需要的静态一次性解析,或者您是否正在寻找可以承受任何 JS 对象格式的强大解决方案。json.loads在这里非常没用,因为它假定 JSON 格式完美。JS 对象几乎从不采用这种形式,如此处所示。

慕尼黑的夜晚无繁华

import jsonfrom bs4 import BeautifulSouphtml = """<script type="application/ld+json">var productArticleDetails = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "@context" : "https://schema.org",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "@type" : "BreadcrumbList",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "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"}} ]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </script>"""soup = BeautifulSoup(html, 'html.parser')sc = soup.find("script").textdata = sc.split("=", 1)[1]ld = json.loads(data)# print(json.dumps(ld, indent=4))print(ld["itemListElement"][0]["thumbnail"])输出://image-path.jpg
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答