Python-如何使用bs4抓取JavaScript代码)?

时间:2018-12-17 21:42:16

标签: python beautifulsoup

因此,我一直在尝试从javascript的html中抓取一个值。代码中有很多javascript,但是我只想能够打印出这一个:

var spConfig=newProduct.Config({
  "attributes": {
    "531": {
      "id": "531",
      "options": [
        {
          "id": "18",
          "hunter": "0",
          "products": [
            "128709"
          ]
        },
        {
          "label": "40 1\/2",
          "hunter": "0",
          "products": [
            "120151"
          ]
        },
        {
          "id": "33",
          "hunter": "0",
          "products": [
            "120152"
          ]
        },
        {
          "id": "36",
          "hunter": "0",
          "products": [
            "128710"
          ]
        },
        {
          "id": "42",
          "hunter": "0",
          "products": [
            "125490"
          ]
        }
      ]
    }
  },

  "Id": "120153",

});

因此,我首先编写了如下代码:

test = bs4.find_all('script', {'type': 'text/javascript'})
print(test)

我得到的输出非常巨大,因此我无法将其全部发布到此处,但是其中之一就是我在顶部提到的javascript,我只想打印出var spConfig=newProduct.Config

如何做到这一点,以便能够打印出var spConfig=newProduct.Config....,以后我可以使用json.loads将其转换为json,以后我可以更轻松地对其进行抓取了?

对于任何问题或我没有很好解释的问题。我会在注释中说明所有内容,在这里我可以在stackoverflow中提高自己! :)

编辑:

bs4为javascript打印出的更多示例

<script type="text/javascript">varoptionsPrice=newProduct.Options({
  "priceFormat": {
    "pattern": "%s\u00a0\u20ac",
    "precision": 2,
    "requiredPrecision": 2,
    "decimalSymbol": ",",
    "groupSymbol": "\u00a0",
    "groupLength": 3,
    "integerRequired": 1
  },
  "showBoths": false,
  "idSuffix": "_clone",
  "skipCalculate": 1,
  "defaultTax": 20,
  "currentTax": 20,
  "tierPrices": [

  ],
  "tierPricesInclTax": [

  ],
  "swatchPrices": null
});</script>,
<script type="text/javascript">var spConfig=newProduct.Config({
  "attributes": {
    "531": {
      "id": "531",
      "options": [
        {
          "id": "18",
          "hunter": "0",
          "products": [
            "128709"
          ]
        },
        {
          "label": "40 1\/2",
          "hunter": "0",
          "products": [
            "120151"
          ]
        },
        {
          "id": "33",
          "hunter": "0",
          "products": [
            "120152"
          ]
        },
        {
          "id": "36",
          "hunter": "0",
          "products": [
            "128710"
          ]
        },
        {
          "id": "42",
          "hunter": "0",
          "products": [
            "125490"
          ]
        }
      ]
    }
  },

  "Id": "120153"
});</script>,
<scripttype="text/javascript">document.observe('dom:loaded',
function(){
  varswatchesConfig=newProduct.ConfigurableSwatches(spConfig);
});</script>

编辑更新2:

try:
    product_li_tags = bs4.find_all('script', {'type': 'text/javascript'})
except Exception:
    product_li_tags = []


for product_li_tag in product_li_tags:
   try:
        pat = "product.Config\((.+)\);"
        json_str = re.search(pat, product_li_tag, flags=re.DOTALL).group(1)
        print(json_str)
   except:
       pass

#json.loads(json_str)
print("Nothing")
sys.exit()

2 个答案:

答案 0 :(得分:1)

我可以想到3个选项-您使用哪个选项可能取决于项目的规模以及所需的灵活性

  • 使用Regex从脚本中提取对象(最快,最不灵活)

  • 使用ANTLR或类似的语言(例如pyjsparser)来解析js语法

  • 使用Selenium或其他无头浏览器可以为您解释JS。使用此选项,您可以使用selenium执行调用以获取变量like this

  • 的值

正则表达式示例(#1)

>>> script_body = """
    var x=product.Config({
        "key": {"a":1}
});
"""
>>> pat = "product.Config\((.+)\);"
>>> json_str = re.search(pat, script_body, flags=re.DOTALL).group(1)
>>> json.loads(json_str)
{'key': {'a': 1}}
>>> json.loads(json_str)['key']['a']
1

答案 1 :(得分:1)

您可以使用.text函数来获取每个标签中的内容。然后,如果您知道要获取以“ varoptionsPrice”开头的代码,则可以对此进行过滤:

soup = BeautifulSoup(myhtml, 'lxml')

script_blocks = soup.find_all('script', {'type': 'text/javascript'})
special_code = ''
for s in script_blocks:
    if s.text.strip().startswith('varOptionsPrice'):
        special_code = s.text
        break

print(special_code)

编辑:要在评论中回答您的问题,有两种不同的方法来提取文本中具有JSON的部分。您可以通过正则表达式传递它,以获取第一个左括号之间和末尾);之间的所有内容。尽管如果您想完全避免使用正则表达式,则可以执行以下操作:

json_stuff = special_code[special_code.find('(')+1:special_code.rfind(')')]

然后从中制作出可用的字典:

import json
j = json.loads(json_stuff)
print(j['defaultTax'])  # This should return a value of 20