【问题标题】:My data from <script> returns None: AttributeError: 'NoneType' object has no attribute 'group'我的 <script> 数据返回 None: AttributeError: 'NoneType' object has no attribute 'group'
【发布时间】:2021-04-12 19:12:35
【问题描述】:

我尝试从

这里有什么问题?

html_doc = """
    <script>
      var modelData = {
        "hlsUrl": "null",
        "account": "4LH7J44IYPAGEZEY6E3UL"
      }
  </script>
"""

soup = BeautifulSoup(html_doc, "html.parser")
# locate the script, get the contents
script_text = soup.select_one("script").contents[0]

# get javascript object inside the script
model_data = re.search(r"modelData = ({.*?});", script_text, flags=re.S)
print(model_data) # RETURNS None - why?
model_data = model_data.group(1)

# "convert" the javascript object to json-valid object
model_data = re.sub(
    r"^\s*([^:\s]+):", r'"\1":', model_data.replace("'", '"'), flags=re.M
)

# json decode the object
model_data = json.loads(model_data)

# print the data
print(model_data["account"])

更新问题:

在接受与给定响应有效的答案后,我发现我遗漏了一条重要信息。

完整的回应是这样的:

{
        "hlsUrl": "null",
        "account": "1V2FO4K7ME78RV09VXNEC",
        "packageName": "null",
        isActive: false
      }

这里显示 isActive 不是一个类似 json 的对象或它的名字,所以它现在给了我以下错误:

obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 5 column 9 (char 111)

【问题讨论】:

  • group(0)?它是基于 0 索引的
  • 嗯,好的,谢谢你:),但它仍然不会改变'model_data'返回无。
  • 因为正则表达式模式不正确
  • 你能详细说明一下,也许能帮我把它做好吗?
  • 您确定响应没有引号?如果没有引号不是有效的 JSON。

标签: python python-3.x beautifulsoup


【解决方案1】:

你把它弄得太复杂了。

使用.string 而不是.contents[0]。由于后者也有效,.string 方法不需要索引,可以直接传递给re.search()。另外,恕我直言,它更具可读性。

修正你的正则表达式。

这行得通:

modelData = ({.*?})

虽然没有:

modelData = ({.*?});

注意,不需要;

最后,你不必做这一切:

# "convert" the javascript object to json-valid object
model_data = re.sub(
    r"^\s*([^:\s]+):", r'"\1":', model_data.replace("'", '"'), flags=re.M
)

只需将正则表达式 group(1) 转储为 json.loads

完整代码:

import json
import re

from bs4 import BeautifulSoup

html_doc = """
    <script>
      var modelData = {
        "hlsUrl": "null",
        "account": "4LH7J44IYPAGEZEY6E3UL"
      }
  </script>
"""

soup = BeautifulSoup(html_doc, "html.parser")
script_text = soup.select_one("script").string
model_data = re.search(r"modelData = ({.*?})", script_text, re.S).group(1)
print(json.loads(model_data)["account"])

输出:

4LH7J44IYPAGEZEY6E3UL

【讨论】:

  • 你能看看我在原始问题中的更新吗?
【解决方案2】:

这看起来像是您可以搜索 HTML 内容以获得您正在寻找的内容,而不是进行任何中间解析

html_doc = """
    <script>
      var modelData = {
        "hlsUrl": "null",
        "account": "4LH7J44IYPAGEZEY6E3UL"
      }
  </script>
"""
import re
next(re.finditer(r'"account":\s*"([\dA-Z]{21})"', html_doc)).group(1)
# '4LH7J44IYPAGEZEY6E3UL'

这可以通过查找字面意义上的"account": 的第一个实例,后跟任意数量的空格\s*,然后是包含正好21 个大写数字或字母的带引号的字符串(将21 调整到可能的范围)

re.finditer()next() 在这里很有帮助,因为它们会

  • 搜索整个字符串,直到找到匹配项
  • 只获取第一个实例或提高StopIteration
  • 速度惊人

虽然这避免了任何中间解析并且不会尝试使用正则表达式(can only lead to ZA̡͊͠͝LGΌ)解析 html,但请注意,如果类似字段出现在不相关的范围中,它可能会中断!如果您预计会出现这种情况,那么适应 @baduker's answer 可能会更加稳健。相反,如果您希望结构发生变化,但 没有 找到完全匹配的字段 ("account":\s*"([\dA-Z]{21})"),这可能会更健壮(因为它不关心其他 HTML 结构,例如找到&lt;script&gt;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-15
    • 1970-01-01
    • 2017-10-20
    • 2022-01-10
    • 2018-05-25
    • 2017-03-08
    • 2021-04-06
    相关资源
    最近更新 更多