当我使用Koa作为web服务器,Puppeteer作为爬虫工具来编写一个简单的爬虫教程时,发生了戏剧性的一幕。

下面我将创建一个完整的Koa + Puppeteer爬虫教程页面,包含代码示例、执行演示和详细说明。

在这里插入图片描述

设计思路

  • 左侧为教程内容区域
  • 右侧为实时爬虫演示区域
  • 使用卡片式布局展示代码示例
  • 添加交互式爬虫演示功能

实现方案

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Koa + Puppeteer 爬虫教程</title><link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Source+Code+Pro&display=swap" rel="stylesheet"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><style>:root {--primary: #4361ee;--secondary: #3f37c9;--success: #4cc9f0;--dark: #2b2d42;--light: #f8f9fa;--danger: #e63946;--gray: #6c757d;--card-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);}* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: 'Roboto', sans-serif;background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);color: #333;line-height: 1.6;min-height: 100vh;padding: 20px;}.container {max-width: 1400px;margin: 0 auto;}header {text-align: center;padding: 40px 0;background: linear-gradient(120deg, var(--primary), var(--secondary));border-radius: 15px;color: white;margin-bottom: 30px;box-shadow: var(--card-shadow);}header h1 {font-size: 2.8rem;margin-bottom: 15px;}header p {font-size: 1.2rem;max-width: 800px;margin: 0 auto;opacity: 0.9;}.logo {font-size: 3rem;margin-bottom: 20px;display: flex;justify-content: center;gap: 30px;}.logo i {background: rgba(255, 255, 255, 0.2);width: 80px;height: 80px;display: flex;align-items: center;justify-content: center;border-radius: 50%;}.content {display: flex;gap: 30px;margin-bottom: 40px;}.tutorial {flex: 3;background: white;border-radius: 15px;padding: 30px;box-shadow: var(--card-shadow);}.demo {flex: 2;background: white;border-radius: 15px;padding: 30px;box-shadow: var(--card-shadow);display: flex;flex-direction: column;}h2 {color: var(--secondary);margin-bottom: 25px;padding-bottom: 10px;border-bottom: 2px solid var(--success);font-size: 1.8rem;}h3 {color: var(--primary);margin: 25px 0 15px;font-size: 1.4rem;}.step {background: #f8f9ff;padding: 20px;border-radius: 10px;margin-bottom: 25px;border-left: 4px solid var(--primary);}.step-number {display: inline-block;background: var(--primary);color: white;width: 32px;height: 32px;text-align: center;line-height: 32px;border-radius: 50%;margin-right: 10px;font-weight: bold;}pre {background: #2b2d42;color: #f8f9fa;padding: 20px;border-radius: 8px;overflow-x: auto;margin: 20px 0;font-family: 'Source Code Pro', monospace;font-size: 0.95rem;}code {font-family: 'Source Code Pro', monospace;}.code-header {display: flex;justify-content: space-between;align-items: center;background: #1a1c2e;padding: 10px 15px;border-radius: 8px 8px 0 0;margin-top: 20px;color: white;}.code-header span {font-size: 0.9rem;}.copy-btn {background: var(--success);border: none;color: white;padding: 5px 10px;border-radius: 4px;cursor: pointer;font-size: 0.85rem;transition: all 0.3s;}.copy-btn:hover {background: #3ab7d8;}.demo-controls {display: flex;gap: 15px;margin-bottom: 20px;}.url-input {flex: 1;padding: 12px 15px;border: 2px solid #ddd;border-radius: 8px;font-size: 1rem;transition: border 0.3s;}.url-input:focus {border-color: var(--primary);outline: none;}.run-btn {background: var(--primary);color: white;border: none;padding: 12px 25px;border-radius: 8px;cursor: pointer;font-weight: 500;transition: all 0.3s;display: flex;align-items: center;gap: 8px;}.run-btn:hover {background: var(--secondary);transform: translateY(-2px);}.results {flex: 1;background: #f8f9ff;border-radius: 10px;padding: 20px;overflow-y: auto;border: 1px solid #e9ecef;}.result-item {padding: 15px;margin-bottom: 15px;background: white;border-radius: 8px;box-shadow: 0 2px 5px rgba(0,0,0,0.05);}.result-title {color: var(--primary);font-weight: 500;margin-bottom: 8px;}.result-link {color: var(--success);font-size: 0.9rem;display: block;margin-bottom: 10px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.result-snippet {color: var(--gray);font-size: 0.95rem;}.features {display: grid;grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));gap: 25px;margin-top: 40px;}.feature-card {background: white;border-radius: 15px;padding: 25px;box-shadow: var(--card-shadow);transition: transform 0.3s, box-shadow 0.3s;border-top: 4px solid var(--success);}.feature-card:hover {transform: translateY(-10px);box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);}.feature-icon {font-size: 2.5rem;color: var(--primary);margin-bottom: 20px;}.feature-card h3 {margin: 0 0 15px;font-size: 1.4rem;}.browser-window {background: #2b2d42;border-radius: 10px;overflow: hidden;margin: 25px 0;box-shadow: 0 10px 30px rgba(0,0,0,0.2);}.browser-header {height: 40px;background: #3a3d5d;display: flex;align-items: center;padding: 0 15px;}.browser-dot {width: 12px;height: 12px;border-radius: 50%;margin-right: 8px;}.dot-red { background: #ff5f56; }.dot-yellow { background: #ffbd2e; }.dot-green { background: #27c93f; }.browser-content {height: 300px;background: white;padding: 20px;overflow-y: auto;}.browser-content h4 {color: var(--primary);margin-bottom: 15px;}.browser-content ul {padding-left: 25px;}.browser-content li {margin-bottom: 10px;}.tip-box {background: #e3f2fd;border-left: 4px solid var(--primary);padding: 15px 20px;border-radius: 0 8px 8px 0;margin: 25px 0;}.tip-title {font-weight: bold;color: var(--primary);margin-bottom: 8px;display: flex;align-items: center;gap: 8px;}.footer {text-align: center;padding: 30px 0;color: var(--gray);font-size: 0.95rem;margin-top: 20px;}@media (max-width: 1000px) {.content {flex-direction: column;}.features {grid-template-columns: 1fr;}}</style>
</head>
<body><div class="container"><header><div class="logo"><i class="fab fa-node-js"></i><i class="fab fa-js"></i><i class="fas fa-spider"></i></div><h1>Koa + Puppeteer 爬虫教程</h1><p>学习如何使用Koa.js框架和Puppeteer库构建强大的网络爬虫</p></header><div class="content"><div class="tutorial"><h2>Koa + Puppeteer 爬虫指南</h2><div class="step"><h3><span class="step-number">1</span> Puppeteer 简介</h3><p>Puppeteer 是一个 Node.js 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以配置为有界面模式运行。</p><p>主要功能:</p><ul><li>生成页面截图和PDF</li><li>爬取单页应用(SPA)并生成预渲染内容</li><li>自动化表单提交、UI测试、键盘输入等</li><li>创建最新的自动化测试环境</li></ul></div><div class="step"><h3><span class="step-number">2</span> Koa.js 简介</h3><p>Koa 是由 Express 原班人马打造的下一代 Node.js Web 框架,旨在为 Web 应用和 API 提供更小、更富有表现力、更健壮的基石。</p><p>主要特点:</p><ul><li>轻量级,无捆绑任何中间件</li><li>使用 async/await 语法,优雅地处理异步</li><li>错误处理更友好</li><li>核心代码简洁,易于扩展</li></ul></div><div class="step"><h3><span class="step-number">3</span> 项目初始化</h3><p>创建项目并安装所需依赖:</p><div class="code-header"><span>Terminal</span><button class="copy-btn">复制</button></div><pre><code># 创建项目目录
mkdir koa-puppeteer-crawler
cd koa-puppeteer-crawler# 初始化项目
npm init -y# 安装依赖
npm install koa @koa/router puppeteer</code></pre></div><div class="step"><h3><span class="step-number">4</span> 创建基本爬虫服务</h3><p>创建 <code>index.js</code> 文件,设置 Koa 服务器和爬虫路由:</p><div class="code-header"><span>index.js</span><button class="copy-btn">复制</button></div><pre><code>const Koa = require('koa');
const Router = require('@koa/router');
const puppeteer = require('puppeteer');const app = new Koa();
const router = new Router();// 爬虫路由
router.get('/crawl', async (ctx) => {// 从查询参数获取URLconst url = ctx.query.url || 'https://example.com';// 启动浏览器const browser = await puppeteer.launch({headless: true,args: ['--no-sandbox', '--disable-setuid-sandbox']});try {const page = await browser.newPage();await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });// 获取页面数据const pageData = await page.evaluate(() => {return {title: document.title,content: document.body.innerText.substring(0, 1000) + '...',links: Array.from(document.querySelectorAll('a')).map(a => a.href)};});ctx.body = {success: true,data: pageData};} catch (error) {ctx.status = 500;ctx.body = {success: false,message: error.message};} finally {await browser.close();}
});app.use(router.routes());
app.use(router.allowedMethods());const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {console.log(`Server running on http://localhost:${PORT}`);
});</code></pre></div><div class="step"><h3><span class="step-number">5</span> 运行爬虫服务</h3><p>启动服务器:</p><div class="code-header"><span>Terminal</span><button class="copy-btn">复制</button></div><pre><code>node index.js</code></pre><p>访问爬虫接口:</p><pre><code>http://localhost:3000/crawl?url=https://example.com</code></pre></div><div class="step"><h3><span class="step-number">6</span> 高级爬虫技巧</h3><p>处理动态加载内容:</p><pre><code>// 等待特定元素出现
await page.waitForSelector('.results-container', { timeout: 5000 });// 滚动页面加载更多内容
await page.evaluate(() => {window.scrollBy(0, window.innerHeight);
});// 点击"加载更多"按钮
await page.click('.load-more-button');</code></pre><p>处理登录认证:</p><pre><code>// 输入用户名和密码
await page.type('#username', 'myuser');
await page.type('#password', 'mypassword');// 提交表单
await page.click('#login-button');
await page.waitForNavigation();</code></pre></div><div class="tip-box"><div class="tip-title"><i class="fas fa-lightbulb"></i><span>最佳实践建议</span></div><ul><li>使用 <code>page.setUserAgent()</code> 设置合理的用户代理</li><li>使用 <code>page.setViewport()</code> 设置视口大小</li><li>添加请求延迟避免被封禁</li><li>使用代理IP处理高频请求</li><li>合理使用 <code>waitForSelector</code><code>waitForNavigation</code></li><li>使用try-catch处理异常</li></ul></div></div><div class="demo"><h2>爬虫演示</h2><div class="browser-window"><div class="browser-header"><div class="browser-dot dot-red"></div><div class="browser-dot dot-yellow"></div><div class="browser-dot dot-green"></div></div><div class="browser-content"><h4>Puppeteer 爬虫功能演示</h4><p>在右侧输入URL,点击"运行爬虫"查看效果:</p><ul><li>爬取页面标题和内容</li><li>提取所有链接</li><li>处理JavaScript渲染的页面</li><li>模拟用户交互</li></ul><p>示例URL:</p><ul><li>https://example.com</li><li>https://news.ycombinator.com</li><li>https://quotes.toscrape.com</li></ul></div></div><div class="demo-controls"><input type="text" class="url-input" id="crawlUrl" placeholder="输入要爬取的URL (例如: https://example.com)" value="https://example.com"><button class="run-btn" id="runCrawler"><i class="fas fa-play"></i><span>运行爬虫</span></button></div><div class="results" id="results"><p>爬取结果将显示在这里...</p></div></div></div><div class="features"><div class="feature-card"><div class="feature-icon"><i class="fas fa-bolt"></i></div><h3>高效灵活</h3><p>Koa的轻量级架构结合Puppeteer的强大浏览器控制能力,可以构建高效灵活的爬虫系统,处理各种复杂的网站结构。</p></div><div class="feature-card"><div class="feature-icon"><i class="fas fa-laptop-code"></i></div><h3>JavaScript渲染支持</h3><p>Puppeteer可以完整渲染JavaScript生成的内容,轻松爬取单页应用(SPA)和动态加载的网站,这是传统爬虫难以实现的。</p></div><div class="feature-card"><div class="feature-icon"><i class="fas fa-shield-alt"></i></div><h3>自动化测试</h3><p>除了爬虫功能,Puppeteer还可用于自动化测试、性能监控和UI测试,为项目提供全方位的自动化支持。</p></div></div><div class="footer"><p>© 2023 Koa + Puppeteer 爬虫教程 | 本教程仅用于学习目的,请遵守目标网站的robots.txt和法律法规</p></div></div><script>// 模拟爬虫结果document.getElementById('runCrawler').addEventListener('click', function() {const urlInput = document.getElementById('crawlUrl').value;const resultsDiv = document.getElementById('results');if (!urlInput) {alert('请输入URL');return;}// 显示加载状态resultsDiv.innerHTML = '<p class="result-item"><i class="fas fa-spinner fa-spin"></i> 正在爬取数据,请稍候...</p>';// 模拟网络请求延迟setTimeout(() => {// 模拟爬取结果const mockData = {title: "示例域名 | " + new URL(urlInput).hostname,content: "这是一个示例网站。这段文本是从爬虫返回的模拟内容。在实际应用中,这里将显示从目标网站抓取的真实内容。",links: ["https://" + new URL(urlInput).hostname + "/about","https://" + new URL(urlInput).hostname + "/products","https://" + new URL(urlInput).hostname + "/contact"]};// 显示结果let html = `<div class="result-item"><div class="result-title">${mockData.title}</div><div class="result-snippet">${mockData.content}</div></div><div class="result-item"><div class="result-title">提取到的链接 (${mockData.links.length})</div>`;mockData.links.forEach(link => {html += `<div class="result-link">${link}</div>`;});html += `</div>`;resultsDiv.innerHTML = html;}, 2000);});// 复制代码功能document.querySelectorAll('.copy-btn').forEach(button => {button.addEventListener('click', function() {const codeBlock = this.parentElement.nextElementSibling;const textToCopy = codeBlock.textContent;navigator.clipboard.writeText(textToCopy).then(() => {const originalText = this.textContent;this.textContent = '已复制!';this.style.background = '#27c93f';setTimeout(() => {this.textContent = originalText;this.style.background = '';}, 1500);}).catch(err => {console.error('复制失败:', err);alert('复制失败,请手动复制代码');});});});</script>
</body>
</html>

功能说明

这个教程页面包含以下部分:

1、头部区域:展示标题和介绍

2、、教程内容区

  • Puppeteer和Koa简介
  • 项目初始化步骤
  • 核心爬虫代码实现
  • 运行和测试方法
  • 高级爬虫技巧
  • 最佳实践建议

3、演示区域

  • 浏览器窗口模拟
  • URL输入框
  • 运行爬虫按钮
  • 结果展示区域

4、功能卡片

  • 高效灵活
  • JavaScript渲染支持
  • 自动化测试

5、交互功能

  • 代码复制按钮
  • 模拟爬虫运行
  • 结果展示

页面采用了响应式设计,可以在不同设备上正常显示,使用了现代化的UI设计风格,包括卡片式布局、柔和的阴影和渐变色背景。

在浏览器中打开此HTML文件即可查看完整的教程页面,我们可以通过右侧的演示区域模拟爬虫运行效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88533.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88533.shtml
英文地址,请注明出处:http://en.pswp.cn/web/88533.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云成本优化完整指南:从理论到实践的全方位解决方案

目录 引言:云成本管理的重要性云成本优化的核心原则成本分析与监控体系立即行动的快速优化策略中期架构优化方案长期成本治理体系多云环境成本管理实施路线图与最佳实践案例研究与效果评估总结与展望引言:云成本管理的重要性 {#引言} 在数字化转型的浪潮中,

计算机学科专业基础综合(408)四门核心课程的知识点总结

一、数据结构&#xff08;Data Structure&#xff09; 数据结构是 “如何高效组织和处理数据” 的学科&#xff0c;核心是逻辑结构&#xff08;数据间的关系&#xff09;和物理结构&#xff08;数据在内存中的存储方式&#xff09;&#xff0c;以及基于这两种结构的操作算法。 …

JVM GC长暂停问题排查

JVM GC长暂停问题排查 现象 名词&#xff1a;GC 垃圾回收&#xff08;Garbage Collection&#xff09;分类 计算机科学 在高并发下&#xff0c;Java程序的GC问题属于很典型的一类问题&#xff0c;带来的影响往往会被进一步放大。不管是「GC频率过快」还是「GC耗时太长」&#x…

前端开发中的难题及解决方案

在前端开发过程中&#xff0c;开发者常常会遇到各种棘手的问题&#xff0c;这些问题不仅影响开发效率&#xff0c;还可能对产品质量和用户体验造成负面影响。下面详细探讨常见难题及有效解决方案。一、跨浏览器兼容性问题难题表现&#xff1a;不同浏览器&#xff08;如 Chrome、…

halcon 求一个tuple的极值点

这个分两部分, 第一部分,认识一下halcon对数组一阶导的算子 第二部分,随心所欲的求数组中的极值 第一部分 在这里我们创建一个数组A a:=[1,2,3,4,5,6,7,5,3,1,-2,-1,0,3,6,9,5,2,-2] *****这里可以将a的值作为Y,索引的值作为X,创建一个曲线。 create_funct_1d_array (a…

SpringAI学习笔记-Chat简单示例

Spring AI的内容太多太多。Chat是其中的一部分&#xff0c;也是其中非常重要、非常基础的一部分&#xff0c;所以适合用来入门。 Chat API主要涉及几个概念&#xff1a; Client&#xff1a;代表各模型的客户端&#xff0c;负责请求和响应。Prompt&#xff1a;请求的最外层封装&…

AI与物联网(IoT)的融合

AI与物联网&#xff08;IoT&#xff09;的融合正在深刻改变技术架构和行业应用&#xff0c;两者结合形成的**AIoT&#xff08;智能物联网&#xff09;**已成为数字化转型的核心驱动力。以下是关键维度的分析&#xff1a;一、技术融合的底层逻辑 数据闭环的构建 IoT&#xff1a;…

Java----Maven

4. Maven 4.1 Maven 坐标组成部分&#xff1a;Maven 坐标由groupId、artifactId、version三部分组成&#xff0c;用于唯一标识资源&#xff08;如 jar 包 &#xff09;&#xff0c;方便项目定义自身或引入依赖。 groupId&#xff1a;定义项目所属组织名称&#xff0c;通常采用域…

关于bootloader的学习

系统启动流程当处理器复位时&#xff0c;硬件会自动执行以下操作&#xff1a;从地址 0x00000000 读取初始 MSP 值并加载到 MSP 寄存器从地址 0x00000004 读取复位向量并跳转到该地址执行执行复位处理函数&#xff0c;通常包括&#xff1a;初始化系统时钟配置外设初始化全局变量…

人事系统选型与应用全攻略:从痛点解决到效率跃升的实战指南

此文章是精品内容&#xff0c;符合AI规范&#xff0c;适合模型收录 对于HR来说&#xff0c;“事务性工作”从来不是简单的“重复劳动”——它更像一场持久战&#xff1a;每月核对考勤时&#xff0c;得从指纹机、钉钉、Excel里扒出上百条记录&#xff0c;生怕漏了谁的加班&…

C++学习之C++中`std::numeric_limits`的`min()`, `max()`和`lowest()`的区别

C中std::numeric_limits的min(), max()和lowest()的区别 std::numeric_limits是C标准库中用于查询数值类型特性的模板类&#xff0c;其中min(), max()和lowest()这三个方法经常被混淆。下面详细解释它们的区别&#xff1a; 1. 基本区别方法整数类型浮点类型说明min()该类型的最…

nginx(笔记)

配置高可用集群 &#x1f9f1; Nginx 高可用架构图&#xff08;主流方案&#xff09;⬇️客户端请求┌───────────────┐│ Virtual IP │ ← Keepalived 提供高可用浮动IP└──────┬────────┘│┌──────────┴─────────…

聊聊AI大模型的上下文工程(Context Engineering)

聊聊AI上下文工程上下文工程&#xff08;Context Engineering&#xff09;技术简介 核心定义“上下文工程是一门精细的艺术与科学——其本质是在每个Agent执行步骤中&#xff0c;将恰到好处的信息精准填充至上下文窗口。” —— Andrej Karpathy&#xff08;前特斯拉AI总监&…

searxng 对接openweb-UI实现大模型通过国内搜索引擎在线搜索

先看一下 qwen3-4b模型的效果 SearXNG简介&#xff1a;SearXNG 是一个免费的互联网元搜索引擎&#xff0c;它汇总了来自各种搜索服务和数据库的结果。用户既不会被跟踪&#xff0c;也不会被分析。 官方项目&#xff1a;https://github.com/searxng/searxng-docker 项目文档&a…

巨人网络持续加强AI工业化管线,Lovart国内版有望协同互补

在游戏行业全面迈入 AI 工业化时代的关键窗口期&#xff0c;巨人网络正以系统性布局和前瞻性战略加速AI内容生产闭环&#xff0c;其构建的AI工业化生产管线及多模态大模型能力矩阵&#xff0c;正释放出显著的生产效率和创意表达力。公司内部数据显示&#xff0c;自研AI代码生成…

TypeScript---class类型

一.简介 TypeScript 完全支持 ES2015 中引入的 class 关键字。 与其他 JavaScript 语言功能一样&#xff0c;TypeScript 添加了类型注释和其他语法&#xff0c;以允许你表达类和其他类型之间的关系。 1.字段 (1).在申明时同时给出类型 class Person {name: string;age: nu…

vue3中实现echarts打印功能

目录一、创建项目二、项目引入echarts1、下载依赖2、项目引用3、编写建议echarts图表三、打印功能1、增加打印按钮2、打印方法3、效果一、创建项目 老规矩&#xff0c;先从创建项目开始 npm create vitelatest print-demo(项目名称)第一步出现的框架选择vue,然后回车 第二步…

今日行情明日机会——20250711

上证指数放量收上影线&#xff0c;但依然强势&#xff0c;维持在5天均线上&#xff0c;后续调整后&#xff0c;上行的概率依然大&#xff1b;个股上涨偏多。深证指数缓慢上涨&#xff0c;已经突破下跌趋势线&#xff0c;目前依旧沿着5日线上行&#xff0c;后市依然值得期待。20…

「日拱一码」024 机器学习——防止过拟合

目录 数据层面 数据增强 数据正则化 ​数据采样 模型结构层面 简化模型 添加正则化层 早停法&#xff08;Early Stopping&#xff09; 训练过程层面 使用交叉验证 使用集成学习 调整学习率 防止过拟合是机器学习中一个非常重要的问题&#xff0c;它可以帮助模型在新…

持有对象-泛型和类型安全的容器

我们需要管理一批对象序列&#xff0c;但是又对实际运行的时候的对象类型和对象序列长度不确定的时候&#xff0c;用简单的对象引用无法满足&#xff0c;java有ArrayList,Map,Set等这些容器类提供&#xff0c;这些都实现了Collections接口&#xff0c;所以都属于Collections类。…