0

0

如何从网页中安全提取并解析嵌入的 JSON 数据(如 App = {...})

霞舞

霞舞

发布时间:2026-02-05 12:30:01

|

791人浏览过

|

来源于php中文网

原创

如何从网页中安全提取并解析嵌入的 JSON 数据(如 App = {...})

本文介绍如何从 html 页面的 `

在现代动态网站中,许多新闻列表、产品数据或配置信息并非通过传统 DOM 元素渲染,而是以 JavaScript 对象字面量(如 App = { ... }; 或 window.DATA = {...};)的形式内联在

以下是一个健壮、通用的解析流程,适用于 App = {...}; 类型的嵌入式数据:

✅ 步骤详解与推荐代码

import requests
from bs4 import BeautifulSoup
import json
import re

def extract_json_from_script(html_content: str, var_name: str = "App") -> dict:
    """
    从 HTML 文本中提取指定变量名的 JS 对象,并解析为 Python 字典。

    Args:
        html_content: 完整 HTML 字符串
        var_name: 目标 JS 变量名(默认 'App')

    Returns:
        解析后的字典对象

    Raises:
        ValueError: 未找到变量或 JSON 格式无效
    """
    soup = BeautifulSoup(html_content, "html.parser")

    # 方法1:精确匹配 script 标签中包含 "var_name = {" 的文本节点(推荐)
    script_tag = soup.find("script", string=re.compile(rf"{var_name}\s*=\s*\{{"))
    if not script_tag:
        raise ValueError(f"未找到包含 '{var_name} = {{' 的 script 标签")

    script_text = script_tag.string

    # 使用正则提取最外层 { } 包裹的 JSON 内容(支持嵌套)
    # 注意:此正则可处理多层嵌套花括号,避免被内部 `{` 误截断
    match = re.search(rf"{var_name}\s*=\s*(\{{(?:[^{{}}]|(?R))*\}});", script_text, re.DOTALL | re.VERBOSE)
    if not match:
        # 回退方案:尝试简单匹配到第一个完整闭合的 }
        match = re.search(rf"{var_name}\s*=\s*(\{{.*?\}});", script_text, re.DOTALL)

    if not match:
        raise ValueError(f"无法从 script 中提取有效的 {var_name} JSON 对象")

    json_str = match.group(1)

    try:
        return json.loads(json_str)
    except json.JSONDecodeError as e:
        raise ValueError(f"JSON 解析失败:{e.msg} (位置: {e.pos})\n上下文: {json_str[max(0, e.pos-30):e.pos+30]}")

# 使用示例
if __name__ == "__main__":
    url = "https://polymetalinternational.com/en/investors-and-media/news/press-releases/"
    response = requests.get(url, timeout=10)
    response.raise_for_status()

    try:
        app_data = extract_json_from_script(response.text, "App")

        # 提取新闻标题列表(路径根据实际 JSON 结构调整)
        press_items = app_data.get("components", {}).get("press-release", {}).get("items", [])

        print(f"共获取 {len(press_items)} 条新闻:\n")
        for i, item in enumerate(press_items[:5], 1):  # 仅打印前5条示例
            name = item.get("name", "N/A")
            date_ts = item.get("date", 0)
            link = item.get("link", "")
            themes = ", ".join(item.get("theme", []))
            print(f"{i}. [{name}] ({themes}) — {date_ts} → {link}")

    except Exception as e:
        print(f"解析失败:{e}")

⚠️ 关键注意事项

  • 不要使用 str.replace() 替换 null/false:JS 的 null 和 Python 的 None 语义不同,且 json.loads() 本身不接受 null;但更重要的是,盲目全局替换(如 'null'.replace('null', 'None'))会污染真实字段值(例如 "filename": "null_report.pdf" 会被错误修改)。
  • 避免硬编码切片(如 [:-1] 或 split("};")[0]):原始答案中 app_content.split("};")[0] + "}" 在存在多层嵌套或注释时极易失效(如 {"a": {"b": {}}}; 中 }; 出现在内部)。正则递归匹配((?R))或使用 ast.literal_eval() 是更可靠的选择(见下文备选方案)。
  • 处理编码与特殊字符:网页返回内容需确保正确解码(response.encoding 或 response.content.decode("utf-8")),尤其当页面含 Unicode(如俄文 \u041f\u0440\u0435\u0441\u0441-\u0440\u0435\u043b\u0438\u0437\u044b)时,json.loads() 原生支持 UTF-8,无需额外解码。
  • 异常防御:始终检查 HTTP 状态码

? 备选方案:使用 ast.literal_eval()(适用于纯 JS 对象字面量)

若确认目标内容是无函数、无 undefined、无注释的纯对象字面量(如 App = {"a": 1, "b": null};),可借助 ast.literal_eval() 安全执行(比 eval() 安全,仅允许基本字面量):

超能文献
超能文献

超能文献是一款革命性的AI驱动医学文献搜索引擎。

下载
import ast

# 将 JS null/true/false 映射为 Python None/True/False
js_to_py = {"null": "None", "true": "True", "false": "False"}
cleaned = script_text.split("App = ", 1)[1].split(";", 1)[0]
for js, py in js_to_py.items():
    cleaned = cleaned.replace(js, py)

try:
    data = ast.literal_eval(cleaned)  # 安全等价于 json.loads(),但支持 JS 布尔/空值
except (ValueError, SyntaxError) as e:
    raise ValueError(f"ast.literal_eval 解析失败: {e}")
✅ 推荐主流程使用 re + json.loads()(更标准、可控性强);ast.literal_eval() 作为补充方案,适合 JS 语法极简的场景。

✅ 总结

从网页

遵循此方法,即可稳定解析 Polymetal 等网站的 App 数据,亦可轻松适配其他类似结构(如 window.__INITIAL_STATE__、dataLayer 等)。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

426

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

540

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

313

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

78

2025.09.10

Python爬虫获取数据的方法
Python爬虫获取数据的方法

Python爬虫可以通过请求库发送HTTP请求、解析库解析HTML、正则表达式提取数据,或使用数据抓取框架来获取数据。更多关于Python爬虫相关知识。详情阅读本专题下面的文章。php中文网欢迎大家前来学习。

293

2023.11.13

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

238

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

560

2024.03.01

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

381

2023.08.03

java return合集
java return合集

本专题整合看java中return关键词的用途,语句的使用等等内容,阅读专题下面的文章了解更多详细内容。

0

2026.02.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.6万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.7万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号