当前位置: 首页 > news >正文

【JavaScript】读取商品页面中的结构化数据(JSON-LD),在不改动服务端情况下,实现一对一跳转

前端实践:从商品页面读取 mpn 并实现一对一跳转

在实际开发中,我们经常会遇到这样一种需求:
用户浏览 A 网站的商品页面后,点击按钮能够直接跳转到 B 网站的对应商品。

表面看似只是一个按钮跳转,但如果不同商品需要精确映射,就必须找到每个商品的唯一标识。这时,很多电商页面都会通过 结构化数据(JSON-LD) 提供关键信息,例如 mpn(Manufacturer Part Number,制造商零件号)。


1. 问题背景

  • 我需要在商品详情页中获取唯一标识 mpn,并基于它拼接目标商店的跳转链接。
  • 页面本身是第三方的,不能直接改动服务端返回的数据。
  • 目标效果:隐藏原始「加入购物车 / 立即购买」按钮,替换为一个自定义按钮,点击后跳转到另一个电商平台(例如 DHgate)的对应商品。

2. 数据获取的波折

一开始,我尝试直接在页面 DOM 中寻找 mpn

  • document.querySelector() 去找标签 → 失败
  • meta 标签里查找 → 失败
  • 在页面可见文本里搜索 → 失败

直到我注意到页面 <head> 区域存在大量 <script type="application/ld+json"> 标签,这是用于 SEO 的结构化数据。
里面通常包含:

{"@context": "https://schema.org/","@type": "Product","name": "Luxury Custom Handmade Watch","mpn": "123456789","brand": {"@type": "Brand","name": "Artisan Watches"}
}

注解:
JSON-LD(JavaScript Object Notation for Linked Data)是 Google 推荐的结构化数据标注方式。
电商网站会用它向搜索引擎说明商品属性,比如:名称、价格、库存、SKU、MPN 等。

这意味着 最佳的获取方式是解析 JSON-LD,而不是从 DOM 树中“扒值”。


3. 解决方案:解析 JSON-LD 提取 mpn

代码实现如下:

// 获取所有 JSON-LD 脚本标签
const ldJsonScripts = document.querySelectorAll('script[type="application/ld+json"]');let mpnValue = null;// 遍历解析 JSON,找到 Product 类型的 mpn
ldJsonScripts.forEach(script => {try {const jsonData = JSON.parse(script.textContent);if (jsonData["@type"] === "Product" && jsonData.mpn) {mpnValue = jsonData.mpn;}} catch (e) {console.error("解析 JSON-LD 出错:", e);}
});

这样就能稳健地提取出 mpn 值。


4. 替换默认按钮并添加跳转逻辑

由于目标是 一对一跳转,我需要屏蔽原有的购物入口,改为跳转到目标链接。

4.1 隐藏原有按钮

原始按钮 ID 具有统一前缀(如 add-cart-xxxbuynow-xxx),所以通过前缀匹配批量隐藏:

function hideElementsWithPrefix(prefix) {const allElements = document.getElementsByTagName('*');for (let element of allElements) {if (element.id && element.id.startsWith(prefix)) {element.style.display = 'none';}}
}

并且定时执行,防止异步加载的按钮漏网:

setInterval(() => {hideElementsWithPrefix('add-cart-');hideElementsWithPrefix('buynow-');
}, 1000);

4.2 添加自定义按钮

const customButton = document.createElement('button');
customButton.textContent = 'Buy Now on DHgate';
customButton.style.cssText = `background-color: #D4AF37;color: white;border: none;padding: 12px 24px;font-size: 16px;font-weight: bold;border-radius: 6px;cursor: pointer;margin: 10px 0;transition: background-color 0.3s ease;
`;// 悬停效果
customButton.addEventListener('mouseover', () => customButton.style.backgroundColor = '#C89A2E');
customButton.addEventListener('mouseout', () => customButton.style.backgroundColor = '#D4AF37');// 点击跳转
customButton.addEventListener('click', () => {const targetUrl = `https://www.dhgate.com/product/french-artisanal-luxury-exquisite-custom/${mpnValue}.html?`;window.location.assign(targetUrl);// 备份方案:防止 assign 失败setTimeout(() => {if (window.location.href !== targetUrl) {window.location.href = targetUrl;}}, 100);
});

插入到页面:

const insertionPoint = document.querySelector('.product-cart-group') ||document.querySelector('.main_btn').parentNode ||document.body;insertionPoint.appendChild(customButton);

5. 最终效果

  • 页面原有的「加入购物车 / 立即购买」按钮被隐藏。
  • 出现一个新的金色按钮 “Buy Now on DHgate”
  • 点击时,根据当前页面解析到的 mpn 值,自动拼接跳转链接并跳转。

例如:

https://www.dhgate.com/product/french-artisanal-luxury-exquisite-custom/123456789.html

非常好 👍
你提到的这一点非常关键:作为后端,很多人会觉得前端拿个值“应该很简单”,但实际落到细节上,经常会踩坑。
你经历 mpn 的抓取,就是一个典型的前端数据获取思路问题。

下面我以“从一个商品页面获取关键数据”为引,系统整理前端常见的数据抓取手段,带例子和注解。


前端数据抓取手段

前端里,想要拿到一个页面的数据,不一定总是 document.querySelector("#id") 那么直白。


1. 直接 DOM 查询

最直观的方法就是 通过选择器直接查找元素

// 通过 ID
const price = document.querySelector("#product-price").textContent;// 通过 class
const title = document.querySelector(".product-title").innerText;// 通过标签层级
const stock = document.querySelector("div.product-info span.stock").innerText;

注解:

  • 如果页面是 SSR(服务端渲染),DOM 一开始就有数据,这是最快捷的方式。
  • 但对于 SPA(单页应用),很多内容是后续 JS 渲染的,需要等 window.onloadMutationObserver

2. 结构化数据(JSON-LD、Microdata、RDFa)

之前遇到的 mpn,就是嵌在 <script type="application/ld+json"> 里的。

const scripts = document.querySelectorAll('script[type="application/ld+json"]');
scripts.forEach(s => {try {const json = JSON.parse(s.textContent);if (json["@type"] === "Product") {console.log(json.mpn, json.sku, json.brand?.name);}} catch (e) {}
});

注解:

  • 这种方式对 SEO 友好,Google / Bing / 电商比价插件都会用。
  • 如果在做 商品比对 / 跨站跳转 / 爬虫,这是最可靠的切入点。

3. 隐藏在 meta 标签 / 属性中

一些页面会把关键数据放在 <meta>data-* 属性里,给搜索引擎或前端脚本用。

例子:meta 标签

<meta property="product:price:amount" content="99.99">
<meta property="product:sku" content="A12345">

获取:

const price = document.querySelector('meta[property="product:price:amount"]').content;
const sku = document.querySelector('meta[property="product:sku"]').content;

例子:data-* 属性

<button id="buyBtn" data-sku="A12345" data-stock="20">Buy Now</button>

获取:

const btn = document.getElementById("buyBtn");
console.log(btn.dataset.sku);   // "A12345"
console.log(btn.dataset.stock); // "20"

注解:

  • data-* 是 HTML5 规范推荐的“私有数据通道”,比 id / class 更稳定。
  • 在电商、新闻站、CMS 里很常见。

4. 页面内嵌 JSON 配置(window 变量 / inline script)

有些网站在 <script> 里会直接挂一个全局对象,供页面其他 JS 使用。

例子:

<script>window.__INITIAL_STATE__ = {product: {id: "12345",name: "Luxury Watch",price: 299.99,mpn: "XYZ987"}};
</script>

获取:

console.log(window.__INITIAL_STATE__.product.mpn);

注解:

  • SPA 框架(React/Vue/Next.js)经常这么做,把后端数据注入到页面里。
  • 在 f12 → Console 输入 window,多翻几页,常能挖到完整的数据结构。

5. Ajax / Fetch 请求拦截

很多页面并不是直接渲染,而是前端在加载时通过 Ajax/FETCH 请求接口。
这类数据可以直接抓接口,而不是“扒 DOM”。

例子:

商品页打开时,浏览器可能会请求:

GET https://api.shop.com/product/12345

返回:

{"id": "12345","title": "Luxury Watch","price": "299.99","mpn": "XYZ987"
}

在前端可以这样拦截:

// 重写 fetch
const originalFetch = window.fetch;
window.fetch = async (...args) => {const response = await originalFetch(...args);if (args[0].includes("/product/")) {response.clone().json().then(data => {console.log("抓到商品数据:", data);});}return response;
};

注解:

  • 这是 最稳定 的方案,因为你直接拿到原始 JSON 数据。
  • 后端开发者更熟悉接口,所以只要能找到 API 请求,比 DOM 抓取更靠谱。
  • 在 DevTools → Network 里找 XHR / Fetch,常能发现目标接口。

6. 监听 DOM 变化(MutationObserver)

如果页面异步渲染(比如 React/Vue 延迟加载),DOM 里可能一开始没有数据。
这时需要用 MutationObserver 来监听节点变化。

const observer = new MutationObserver(mutations => {const priceNode = document.querySelector(".product-price");if (priceNode) {console.log("价格:", priceNode.textContent);observer.disconnect(); // 拿到后停止监听}
});observer.observe(document.body, { childList: true, subtree: true });

注解:

  • 适合异步加载的 SPA。
  • setInterval 更优雅,但逻辑复杂一些。

7. Canvas / Shadow DOM / 加密数据(特殊情况)

一些网站会反爬虫,把数据写在:

  • Canvas 渲染出来(你只能截图识别)
  • Shadow DOM(需要穿透 .shadowRoot
  • Base64 / 加密字符串(要解码/解密)

这种情况属于“反爬虫”范畴,日常不常见,但电商/金融站点有时会遇到。


总结

方法特点适用场景难度
DOM 选择器直观,容易写静态页面、SSR
JSON-LD / Microdata结构化,标准化商品详情、SEO 站点⭐⭐
meta / data-*隐藏但容易读电商、CMS⭐⭐
window 全局变量完整数据,格式化React/Vue 注水页面⭐⭐
Ajax / Fetch原始 JSON,最稳定SPA、电商 API⭐⭐⭐
MutationObserver处理异步渲染Vue/React 延迟加载⭐⭐⭐
Canvas / Shadow DOM反爬虫用金融、电商防护⭐⭐⭐⭐

建议的思路是:

  1. 优先找 API(最干净的 JSON);
  2. 找不到 API → 看 JSON-LD / meta / data-*;
  3. 再不行 → 扫 window 全局变量;
  4. 实在没有 → MutationObserver、模拟渲染、甚至 OCR。

http://www.dtcms.com/a/362976.html

相关文章:

  • 不只是一台玩具车:开源燃料电池机器人HydroBot全揭秘
  • 基金交易量预测比赛_数据分析
  • AI-调查研究-67-具身智能 核心技术构成全解析:感知、决策、学习与交互的闭环系统
  • Caffeine介绍
  • windows docker(二) 启动存在的容器
  • 【芯片良率:半导体制造的生死线,如何避免陷阱并提升竞争力?】
  • OpenCV计算机视觉实战(23)——目标检测详解
  • 在Docker中安装MySQL时3306端口占用问题
  • 广度优先搜索(BFS, Breadth-First Search)
  • 书写腾讯天气遇到的问题
  • LeetCode 777.在LR字符串中交换相邻字符
  • PyTorch 面试题及详细答案120题(106-115)-- 理论与拓展
  • LeetCode 刷题【61. 旋转链表】
  • SAP-MM 配置工厂的名称时候,容易疏忽的点
  • Linux操作系统(6)
  • 《驾驭云原生复杂性:隐性Bug的全链路防御体系构建》
  • 线程安全问题及解决方案
  • STM32 - Embedded IDE - GCC - 如何在工程中生成.bin格式固件
  • 从API到AI Agent:落地模型上下文协议(MCP)的设计模式与核心步骤
  • 【提示词】...(后续单元)在Prompt 的作用
  • [Dify 专栏] 如何通过 Prompt 在 Dify 中模拟 Persona:即便没有专属配置,也能让 AI 扮演角色
  • 【51单片机】【protues仿真】基于51单片机呼叫系统
  • 【Qt】QToolBar、QToolButton的常用用法
  • VR智慧楼宇技术:打造智能办公空间的卓越方案​
  • 【Linux笔记】命令行与vim基础
  • qt使用笔记三之 QGraphicsView、QGraphicsScene 和 QGraphicsPixmapItem 详解
  • 深度学习——基于卷积神经网络实现食物图像分类(数据增强)
  • 教资科三【信息技术】— 教学知识(18~21题): 课程理论知识 教学评价 教学实施 教学设计
  • think
  • Ansible角色:高效开发与管理的秘密