Как разобрать сценарии с красивым супом? - PullRequest
2 голосов
/ 22 мая 2019

Мне нужно проанализировать некоторые данные в теге script. Первая проблема заключается в том, что на странице есть несколько тегов сценариев без идентификаторов или классов. Тот, который мне нужен, выглядит так:

<script>
    window.runParams = {
        data: {
            "priceModule":{
                "maxActivityAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $28.71",
                    "value":28.71 ***VALUE TO IGNORE***
                },
                "maxAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $52.20",
                    "value":52.2 ***VALUE TO IGNORE***
                },
                "minActivityAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $6.83",
                    "value":6.83 ***THIS IS THE VALUE I NEED***
                },
                "minAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $12.42",
                    "value":12.42 ***THIS IS THE VALUE I NEED***
                },
            },
            "freightItemModule":{
                "commitDay":"60",
                "company":"Standard Shipping",
                "currency":"USD",
                "discount":100,
                "displayType":"deliveryTime",
                "features":{
                },
                "freightAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $0.00",
                    "value":0.0 ***VALUE TO IGNORE***
                },
                "fullMailLine":false,
                "hbaService":false,
                "i18nMap":{
                },
                "id":0,
                "name":"FreightItemModule",
                "notification":"",
                "sendGoodsCountry":"CN",
                "sendGoodsCountryFullName":"China",
                "serviceName":"CAINIAO_STANDARD",
                "standardFreightAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $13.12",
                    "value":13.12 ***VALUE TO IGNORE***
                },
                "time":"17-25",
                "tracking":true
            },
            "skuModule":{
                "categoryId":200001392,
                "features":{
                },"
                forcePromiseWarrantyJson":"{
                }",
                "hasSizeInfo":false,
                "hasSkuProperty":true,
                "id":0,
                "name":"SKUModule",
                "productSKUPropertyList":[{
                    "isShowTypeColor":false,
                    "order":1,
                    "showType":"none",
                    "showTypeColor":false,
                    "skuPropertyId":14,
                    "skuPropertyName":"????",
                    "skuActivityAmount":{
                        "currency":"USD",
                        "formatedAmount":"US $12.38",
                        "value":12.38 ***VALUE TO IGNORE***
                    },
                    "skuAmount":{
                        "currency":"USD",
                        "formatedAmount":"US $22.51",
                        "value":22.51 ***VALUE TO IGNORE***
                    },
                    "skuCalPrice":"22.51",
                    "skuMultiCurrencyCalPrice":"22.51",
                    "skuMultiCurrencyDisplayPrice":"22.51"
                }
            },
        },
    };

    var GaData = {
        pageType: "product",
        productIds: "32955439786",
        totalValue: "US $6.83"
    };

    var PAGE_TIMING = {
        pageType: 'gloDetail'
    };
</script>

Мне нужно проанализировать [value] внутри [data] -> [priceModule] -> [minActivityAmount] & [minAmount] и сохранить их под двумя отдельными переменными: activity_amount = 6.83 и amount = 12.42. Как вы можете видеть, есть несколько «значений» в нескольких «модулях». Поэтому анализ их с помощью регулярных выражений не кажется идеальным. Может быть, есть лучший способ извлечь эти значения из сценария? Заранее спасибо.

Ответы [ 3 ]

2 голосов
/ 22 мая 2019

К сожалению, BeautifulSoup не предоставляет инструмент для извлечения JS-контента.

Способ решить эту проблему - использовать регулярное выражение

import re

from bs4 import BeautifulSoup

data = """
<script>
    window.runParams = {
        data: {
            "priceModule":{
                "maxActivityAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $28.71",
                    "value":28.71 ***VALUE TO IGNORE***
                },
                "maxAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $52.20",
                    "value":52.2 ***VALUE TO IGNORE***
                },
                "minActivityAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $6.83",
                    "value":6.83 ***THIS IS THE VALUE I NEED***
                },
                "minAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $12.42",
                    "value":12.42 ***THIS IS THE VALUE I NEED***
                },
            },
            "freightItemModule":{
                "commitDay":"60",
                "company":"Standard Shipping",
                "currency":"USD",
                "discount":100,
                "displayType":"deliveryTime",
                "features":{
                },
                "freightAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $0.00",
                    "value":0.0 ***VALUE TO IGNORE***
                },
                "fullMailLine":false,
                "hbaService":false,
                "i18nMap":{
                },
                "id":0,
                "name":"FreightItemModule",
                "notification":"",
                "sendGoodsCountry":"CN",
                "sendGoodsCountryFullName":"China",
                "serviceName":"CAINIAO_STANDARD",
                "standardFreightAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $13.12",
                    "value":13.12 ***VALUE TO IGNORE***
                },
                "time":"17-25",
                "tracking":true
            },
            "skuModule":{
                "categoryId":200001392,
                "features":{
                },"
                forcePromiseWarrantyJson":"{
                }",
                "hasSizeInfo":false,
                "hasSkuProperty":true,
                "id":0,
                "name":"SKUModule",
                "productSKUPropertyList":[{
                    "isShowTypeColor":false,
                    "order":1,
                    "showType":"none",
                    "showTypeColor":false,
                    "skuPropertyId":14,
                    "skuPropertyName":"????",
                    "skuActivityAmount":{
                        "currency":"USD",
                        "formatedAmount":"US $12.38",
                        "value":12.38 ***VALUE TO IGNORE***
                    },
                    "skuAmount":{
                        "currency":"USD",
                        "formatedAmount":"US $22.51",
                        "value":22.51 ***VALUE TO IGNORE***
                    },
                    "skuCalPrice":"22.51",
                    "skuMultiCurrencyCalPrice":"22.51",
                    "skuMultiCurrencyDisplayPrice":"22.51"
                }
            },
        },
    };

    var GaData = {
        pageType: "product",
        productIds: "32955439786",
        totalValue: "US $6.83"
    };

    var PAGE_TIMING = {
        pageType: 'gloDetail'
    };
</script>
"""

soup = BeautifulSoup(data, features='html.parser')
script = soup.find('script')

values = []
keys = ['minActivityAmount', 'minAmount']
for key in keys:
    value = re.search(r'(?<=\"%s\":{)([^]]+?)(?=\})' % key, script.text)
    value = re.search(r'(?<="value":)([0-9.,]+)', value.group())
    values.append(value.group())

print(values)

Выход:

['6.83', '12.42']
1 голос
/ 24 мая 2019

Еще одно регулярное выражение

import re

html = '''
<script>
    window.runParams = {
        data: {
            "priceModule":{
                "maxActivityAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $28.71",
                    "value":28.71 ***VALUE TO IGNORE***
                },
                "maxAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $52.20",
                    "value":52.2 ***VALUE TO IGNORE***
                },
                "minActivityAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $6.83",
                    "value":6.83 ***THIS IS THE VALUE I NEED***
                },
                "minAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $12.42",
                    "value":12.42 ***THIS IS THE VALUE I NEED***
                },
            },
            "freightItemModule":{
                "commitDay":"60",
                "company":"Standard Shipping",
                "currency":"USD",
                "discount":100,
                "displayType":"deliveryTime",
                "features":{
                },
                "freightAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $0.00",
                    "value":0.0 ***VALUE TO IGNORE***
                },
                "fullMailLine":false,
                "hbaService":false,
                "i18nMap":{
                },
                "id":0,
                "name":"FreightItemModule",
                "notification":"",
                "sendGoodsCountry":"CN",
                "sendGoodsCountryFullName":"China",
                "serviceName":"CAINIAO_STANDARD",
                "standardFreightAmount":{
                    "currency":"USD",
                    "formatedAmount":"US $13.12",
                    "value":13.12 ***VALUE TO IGNORE***
                },
                "time":"17-25",
                "tracking":true
            },
            "skuModule":{
                "categoryId":200001392,
                "features":{
                },"
                forcePromiseWarrantyJson":"{
                }",
                "hasSizeInfo":false,
                "hasSkuProperty":true,
                "id":0,
                "name":"SKUModule",
                "productSKUPropertyList":[{
                    "isShowTypeColor":false,
                    "order":1,
                    "showType":"none",
                    "showTypeColor":false,
                    "skuPropertyId":14,
                    "skuPropertyName":"????",
                    "skuActivityAmount":{
                        "currency":"USD",
                        "formatedAmount":"US $12.38",
                        "value":12.38 ***VALUE TO IGNORE***
                    },
                    "skuAmount":{
                        "currency":"USD",
                        "formatedAmount":"US $22.51",
                        "value":22.51 ***VALUE TO IGNORE***
                    },
                    "skuCalPrice":"22.51",
                    "skuMultiCurrencyCalPrice":"22.51",
                    "skuMultiCurrencyDisplayPrice":"22.51"
                }
            },
        },
    };

    var GaData = {
        pageType: "product",
        productIds: "32955439786",
        totalValue: "US $6.83"
    };

    var PAGE_TIMING = {
        pageType: 'gloDetail'
    };
</script>
'''
p1 = re.compile(r'"minActivityAmount":(.*?),[\n\t\s]+"freightItemModule"', re.DOTALL)
text = p1.findall(html)[0]
p2 = re.compile(r'value":\d+\.?\d+')
results = p2.findall(text)
print(results)
1 голос
/ 24 мая 2019

Существует способ сделать это без регулярных выражений (и без BeautifulSoup, если на то пошло);это несколько запутанно, но это должно работать.Он в основном разбивает скрипт на более мелкие порции до тех пор, пока все целевые данные не будут выделены в своем собственном порции, а затем извлекает цель из порции.

data = [your script above]

items = ' '.join(data.split()).split('}, "')

for item in items:
if ("minAmount" in item or "minActivityAmount" in item):        
    print(item.split('"value":')[1].replace('},',''))

Вывод:

 6.83 ***THIS IS THE VALUE I NEED*** 
12.42 ***THIS IS THE VALUE I NEED***  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...