Найти вложенное JS значение объекта из указанного тега скрипта c с Beautiful Soup - PullRequest
0 голосов
/ 17 марта 2020

Я собираю сайт с красивым супом, чтобы получить изображения / изображения, до сих пор это работало нормально для каждого сайта, и мне даже удалось создать несколько пользовательских типов дел. Но один конкретный сайт вызывает у меня проблемы, так как iit возвращает все изображения в JavaScript объекте, встроенном в тег скрипта. Объект довольно большой, поскольку в нем содержится вся информация о продукте. Указанный c бит, который я ищу, достаточно глубоко вложен в productArticleDetails> [идентификатор продукта]> normalImages> thumbnail> [путь к изображению]. Вот так:

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

Так что я хочу просто извлечь путь к изображению.

Это также не единственная вещь, завернутая в тег сценария в возвращенном 'супе', есть загружает другие теги javascript в коде. Итак, я сохранил HTML в переменной и затем запустил:

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

Итак, у меня остался объект, который содержит все элементы <script> из html

Каким-то образом в этом объекте scripts мне нужно найти указанный узел c в правильном фрагменте JS и вернуть значение узла thumbnail, который вложен в узел normalImages, который, в свою очередь, будет вложенный в строку чисел, которая в конечном итоге все сохраняется в productArticleDetails var.

Я полагаю, мне нужно сделать for l oop над scripts объектом, но мне не повезло, вычисляя как извлечь этот указанный c бит данных. Все остальное, что я видел, работает при условии, что есть только 1 бит javaScript, а искомое значение не является вложенным.

Кто-нибудь может помочь? Приветствия.

Ответы [ 2 ]

0 голосов
/ 17 марта 2020
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
0 голосов
/ 17 марта 2020

Если вы можете сделать упрощающее предположение, скажем, что объект, который вы хотите проанализировать, имеет окончательный } flu sh с началом строки, это довольно просто:

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 У объекта нет кавычек вокруг его ключей, поэтому вам, возможно, придется прибегнуть к некоторой подготовке для этого случая. Неясно, нужен ли вам стандартный c разбор в один прием или вы ищете надежное решение, способное противостоять любому объектному формату JS.

json.loads довольно бесполезно здесь, потому что он принимает совершенно правильно JSON. JS объекты почти никогда не находятся в такой форме, как показано здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...