如何将Puppeteer爬取的电商价格结果在HTML服务器中展示?
如何将Puppeteer爬取的数据展示在HTML页面中
核心问题分析
你的代码是Node.js控制台脚本,仅能在终端输出结果。要在HTML页面展示数据,需搭建后端服务执行爬取逻辑,再通过HTTP接口将数据传递给前端页面渲染。
解决方案步骤
1. 修复并重构Scrape函数
先修正原有代码的关键问题,并让函数返回爬取结果(而非直接打印):
- 补充
switch语句中缺失的break,避免配置被覆盖 - 给
browser.close()添加await,确保浏览器正常关闭 - 封装结果对象,包含站点、价格、折扣价和错误信息
修改后的scrape.js:
const puppeteer = require("puppeteer"); const scrape = async (site, value) => { let uSite = "https://www.cosmetica.com.tr/arama/hizliErisim.aspx?tip=U&lang=tr-TR&srt=&text="; let elWay = "#ctl00_u30_ascArama_urun_ascUrunList_rptDestUrun_ctl00_pnlNormal"; let elDiscountWay = "#ctl00_u30_ascArama_urun_ascUrunList_rptDestUrun_ctl00_pnlIndirim"; switch (site) { case "Cosmetica": uSite = "https://www.cosmetica.com.tr/arama/hizliErisim.aspx?tip=U&lang=tr-TR&srt=&text="; elWay = "#ctl00_u30_ascArama_urun_ascUrunList_rptDestUrun_ctl00_pnlNormal"; elDiscountWay = "#ctl00_u30_ascArama_urun_ascUrunList_rptDestUrun_ctl00_pnlIndirim"; break; case "Gratis": uSite = "https://www.gratis.com/search/"; elWay = "div.price.ng-star-inserted > div"; elDiscountWay = "div.price-w-card.ng-star-inserted > div"; break; case "Watsons": uSite = "https://www.watsons.com.tr/search?searchType=manual&text="; elWay = "#products-content-list > e2-content-list > v-root > div > div > v-slot > v-slot-assigned-content > div > div > e2-impression-tracker > div > div.product-tile__details-and-price > div.product-tile__price > div > div > e2-price-badge > div"; elDiscountWay = "#products-content-list > e2-content-list > v-root > div > div > v-slot > v-slot-assigned-content > div > div > e2-impression-tracker > div > div.product-tile__details-and-price > div.product-tile__price > div > div > div > div > e2-price-badge > div"; break; case "Rossmann": uSite = "https://www.rossmann.com.tr/catalogsearch/result/?q="; elWay = "#eln-product-products > div > ol > li:nth-child(1) > div.product-item-info > div > div.price-box.price-final_price > span > span > p > span.price.desktopPrice"; elDiscountWay = "#eln-product-products > div > ol > li:nth-child(1) > div.product-item-info > div > div.price-box.price-final_price > span > div > span.price"; break; default: break; } const url = `${uSite}${value}`; let result = { site, price: null, discountPrice: null, error: null }; try { const browser = await puppeteer.launch({ headless: true, executablePath: './chrome/win64-116.0.5793.0/chrome-win64/chrome.exe' }); const page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle2' }); const element = await page.$(elWay); const dElement = await page.$(elDiscountWay); if (element) result.price = await page.evaluate(el => el.textContent.trim(), element); if (dElement) result.discountPrice = await page.evaluate(el => el.textContent.trim(), dElement); if (!result.price && !result.discountPrice) result.error = "无法找到价格元素"; await browser.close(); } catch (err) { result.error = err.message; console.error(`${site} 爬取失败:`, err); } return result; }; module.exports = scrape;
2. 搭建Express后端服务
安装Express依赖:
npm install express
创建server.js,编写HTTP接口:
const express = require('express'); const scrape = require('./scrape'); const app = express(); const port = 3000; // 允许本地跨域测试 app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET'); next(); }); // 爬取接口:接收商品ID参数 app.get('/scrape', async (req, res) => { const productId = req.query.id; if (!productId) return res.status(400).json({ error: '请提供商品ID' }); // 并行爬取四个站点 const results = await Promise.all([ scrape("Cosmetica", productId), scrape("Gratis", productId), scrape("Watsons", productId), scrape("Rossmann", productId) ]); res.json(results); }); app.listen(port, () => { console.log(`服务器运行在 http://localhost:${port}`); });
3. 编写前端HTML页面
创建index.html,实现交互和数据渲染:
<!DOCTYPE html> <html lang="tr"> <head> <meta charset="UTF-8"> <title>商品价格查询</title> <style> .result-container { margin-top: 20px; display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; } .card { border: 1px solid #ddd; padding: 15px; border-radius: 8px; } .error { color: #dc3545; } </style> </head> <body> <h1>商品价格查询</h1> <div> <input type="text" id="productId" placeholder="输入商品ID(例如:8697432090277)"> <button onclick="fetchPrices()">查询价格</button> </div> <div id="results" class="result-container"></div> <script> async function fetchPrices() { const productId = document.getElementById('productId').value.trim(); const resultsDiv = document.getElementById('results'); resultsDiv.innerHTML = '<p>正在查询...</p>'; if (!productId) { resultsDiv.innerHTML = '<p class="error">请输入商品ID</p>'; return; } try { const response = await fetch(`http://localhost:3000/scrape?id=${productId}`); const data = await response.json(); let html = ''; data.forEach(item => { html += ` <div class="card"> <h3>${item.site}</h3> ${item.error ? `<p class="error">错误: ${item.error}</p>` : ''} ${item.price ? `<p>原价: ${item.price}</p>` : ''} ${item.discountPrice ? `<p>折扣价: ${item.discountPrice}</p>` : ''} </div> `; }); resultsDiv.innerHTML = html; } catch (err) { resultsDiv.innerHTML = `<p class="error">查询失败: ${err.message}</p>`; } } </script> </body> </html>
运行步骤
- 将上述三个文件放在同一目录下
- 启动后端服务:
node server.js - 用浏览器打开
index.html,输入商品ID点击查询即可展示结果
注意事项
- 确保Chrome可执行文件路径正确,或删除
executablePath让Puppeteer自动下载Chromium - 部分站点有反爬机制,可添加用户代理、页面延迟等策略避免被拦截
- 生产环境需替换
Access-Control-Allow-Origin: *为具体域名,保障安全性
内容的提问来源于stack exchange,提问作者Batu A.
相关产品推荐
相关产品推荐

