如何用Node.js获取指定URL下所有元素的CSS?并编写爬虫检测页面字体
嘿,我来帮你搞定这两个Node.js相关的问题!
1. 如何用Node.js获取指定URL下所有元素的CSS样式?
首先得明确:Node.js本身没有浏览器的渲染环境,像cheerio这类HTML解析库只能拿到元素的内联样式,没法获取最终计算后的CSS样式(比如外部样式表、继承的样式、媒体查询生效后的样式)。所以最靠谱的方案是用无头浏览器工具(比如Puppeteer),它能模拟真实浏览器渲染页面,完美获取每个元素的最终样式。
具体实现步骤
- 先安装依赖:
npm install puppeteer
- 编写脚本:
const puppeteer = require('puppeteer'); async function getAllElementStyles(url) { // 启动无头浏览器 const browser = await puppeteer.launch(); const page = await browser.newPage(); // 访问目标URL,等待网络空闲确保样式加载完成 await page.goto(url, { waitUntil: 'networkidle2' }); // 在浏览器上下文执行代码,获取所有元素的计算样式 const elementStyles = await page.evaluate(() => { const elements = Array.from(document.querySelectorAll('*')); return elements.map(element => { const computedStyle = window.getComputedStyle(element); // 生成元素的简易选择器,方便识别 const selector = element.id ? `#${element.id}` : element.className ? `.${element.className.replace(/\s+/g, '.')}` : element.tagName.toLowerCase(); // 提取所有计算后的样式属性 const styles = Object.fromEntries( Array.from(computedStyle).map(prop => [prop, computedStyle[prop]]) ); return { tagName: element.tagName, selector, styles }; }); }); await browser.close(); return elementStyles; } // 使用示例 getAllElementStyles('http://example.com') .then(styles => console.log('所有元素的计算样式:', styles)) .catch(err => console.error('出错了:', err));
如果只需要特定样式属性(比如font-family),可以在styles里只提取需要的字段,减少返回的数据量。
2. 完善遍历链接并检查Helvetica字体的脚本
你原来用request和cheerio的思路没问题,但这两个工具没法处理CSS渲染,根本拿不到元素实际使用的字体。同样得换成Puppeteer,它能准确获取每个元素计算后的字体。我帮你完善了完整脚本:
步骤1:安装依赖
npm install puppeteer url-parse
步骤2:完整脚本
const puppeteer = require('puppeteer'); const URL = require('url-parse'); const START_URL = "http://example.com/"; const SEARCH_FONT = "helvetica"; const MAX_PAGES_TO_VISIT = 100000; const pagesVisited = new Set(); // 用Set存储已访问页面,避免重复爬取 let numPagesVisited = 0; const pagesToVisit = [START_URL]; async function checkPageForFont(pageUrl) { const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); try { // 访问页面,设置超时避免卡住 await page.goto(pageUrl, { waitUntil: 'networkidle2', timeout: 30000 }); console.log(`正在检查页面: ${pageUrl}`); // 检查页面是否有元素使用Helvetica字体 const hasHelvetica = await page.evaluate((targetFont) => { const elements = Array.from(document.querySelectorAll('*')); return elements.some(element => { const computedFont = window.getComputedStyle(element).fontFamily.toLowerCase(); return computedFont.includes(targetFont.toLowerCase()); }); }, SEARCH_FONT); // 输出检查结果 if (hasHelvetica) { console.log(`✅ 页面 ${pageUrl} 发现使用了 ${SEARCH_FONT} 字体`); } else { console.log(`❌ 页面 ${pageUrl} 未发现使用 ${SEARCH_FONT} 字体`); } // 提取页面中所有有效链接 const pageLinks = await page.evaluate(() => { return Array.from(document.querySelectorAll('a[href]')).map(a => a.href); }); await browser.close(); return pageLinks; } catch (err) { console.error(`访问页面 ${pageUrl} 出错:`, err.message); await browser.close(); return []; } } async function crawl() { while (numPagesVisited < MAX_PAGES_TO_VISIT && pagesToVisit.length > 0) { const currentUrl = pagesToVisit.shift(); // 跳过已访问页面或非HTTP链接 if (pagesVisited.has(currentUrl) || !currentUrl.startsWith('http')) { continue; } pagesVisited.add(currentUrl); numPagesVisited++; // 检查当前页面字体,并提取新链接 const links = await checkPageForFont(currentUrl); // 过滤同域名链接(可选,避免爬取范围过大) const parsedStartUrl = new URL(START_URL); links.forEach(link => { const parsedLink = new URL(link); if (parsedLink.host === parsedStartUrl.host && !pagesVisited.has(parsedLink.href)) { pagesToVisit.push(parsedLink.href); } }); } console.log(`爬取完成!共访问了 ${numPagesVisited} 个页面`); } // 启动爬取 crawl();
脚本说明
- 用
Set存储已访问页面,比普通对象更高效,避免重复爬取 - 加入超时设置,防止某个页面加载过慢导致脚本卡住
- 可选过滤同域名链接,避免无限制爬取整个互联网(如果需要跨域名,去掉这个逻辑即可)
- 每个页面检查后会清晰输出结果,方便你快速定位使用Helvetica的页面
内容的提问来源于stack exchange,提问作者Alexander Solonik
相关产品推荐
相关产品推荐

