Koa+Puppeteer爬虫教程页面设计

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

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

设计思路

左侧为教程内容区域

右侧为实时爬虫演示区域

使用卡片式布局展示代码示例

添加交互式爬虫演示功能

实现方案

<!DOCTYPE html>

<htmllang="zh-CN">

<head>

<metacharset="UTF-8">

<metaname="viewport"content="width=device-width, initial-scale=1.0">

<title>Koa + Puppeteer 爬虫教程</title>

<linkhref="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Source+Code+Pro&display=swap"rel="stylesheet">

<linkrel="stylesheet"href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">

<scriptsrc="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:04px20pxrgba(0,0,0,0.1);

       }


       * {

margin:0;

padding:0;

box-sizing:border-box;

       }


body{

font-family:'Roboto',sans-serif;

background:linear-gradient(135deg,#f5f7fa0%,#e4edf5100%);

color:#333;

line-height:1.6;

min-height:100vh;

padding:20px;

       }


.container{

max-width:1400px;

margin:0auto;

       }


header{

text-align:center;

padding:40px0;

background:linear-gradient(120deg,var(--primary),var(--secondary));

border-radius:15px;

color:white;

margin-bottom:30px;

box-shadow:var(--card-shadow);

       }


headerh1{

font-size:2.8rem;

margin-bottom:15px;

       }


headerp{

font-size:1.2rem;

max-width:800px;

margin:0auto;

opacity:0.9;

       }


.logo{

font-size:3rem;

margin-bottom:20px;

display:flex;

justify-content:center;

gap:30px;

       }


.logoi{

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:2pxsolidvar(--success);

font-size:1.8rem;

       }


h3{

color:var(--primary);

margin:25px015px;

font-size:1.4rem;

       }


.step{

background:#f8f9ff;

padding:20px;

border-radius:10px;

margin-bottom:25px;

border-left:4pxsolidvar(--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:20px0;

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:10px15px;

border-radius:8px8px00;

margin-top:20px;

color:white;

       }


.code-headerspan{

font-size:0.9rem;

       }


.copy-btn{

background:var(--success);

border:none;

color:white;

padding:5px10px;

border-radius:4px;

cursor:pointer;

font-size:0.85rem;

transition:all0.3s;

       }


.copy-btn:hover{

background:#3ab7d8;

       }


.demo-controls{

display:flex;

gap:15px;

margin-bottom:20px;

       }


.url-input{

flex:1;

padding:12px15px;

border:2pxsolid#ddd;

border-radius:8px;

font-size:1rem;

transition:border0.3s;

       }


.url-input:focus{

border-color:var(--primary);

outline:none;

       }


.run-btn{

background:var(--primary);

color:white;

border:none;

padding:12px25px;

border-radius:8px;

cursor:pointer;

font-weight:500;

transition:all0.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:1pxsolid#e9ecef;

       }


.result-item{

padding:15px;

margin-bottom:15px;

background:white;

border-radius:8px;

box-shadow:02px5pxrgba(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:transform0.3s,box-shadow0.3s;

border-top:4pxsolidvar(--success);

       }


.feature-card:hover{

transform:translateY(-10px);

box-shadow:012px30pxrgba(0,0,0,0.15);

       }


.feature-icon{

font-size:2.5rem;

color:var(--primary);

margin-bottom:20px;

       }


.feature-cardh3{

margin:0015px;

font-size:1.4rem;

       }


.browser-window{

background:#2b2d42;

border-radius:10px;

overflow:hidden;

margin:25px0;

box-shadow:010px30pxrgba(0,0,0,0.2);

       }


.browser-header{

height:40px;

background:#3a3d5d;

display:flex;

align-items:center;

padding:015px;

       }


.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-contenth4{

color:var(--primary);

margin-bottom:15px;

       }


.browser-contentul{

padding-left:25px;

       }


.browser-contentli{

margin-bottom:10px;

       }


.tip-box{

background:#e3f2fd;

border-left:4pxsolidvar(--primary);

padding:15px20px;

border-radius:08px8px0;

margin:25px0;

       }


.tip-title{

font-weight:bold;

color:var(--primary);

margin-bottom:8px;

display:flex;

align-items:center;

gap:8px;

       }


.footer{

text-align:center;

padding:30px0;

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>

<divclass="container">

<header>

<divclass="logo">

<iclass="fab fa-node-js"></i>

<iclass="fab fa-js"></i>

<iclass="fas fa-spider"></i>

</div>

<h1>Koa + Puppeteer 爬虫教程</h1>

<p>学习如何使用Koa.js框架和Puppeteer库构建强大的网络爬虫</p>

</header>


<divclass="content">

<divclass="tutorial">

<h2>Koa + Puppeteer 爬虫指南</h2>


<divclass="step">

<h3><spanclass="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>


<divclass="step">

<h3><spanclass="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>


<divclass="step">

<h3><spanclass="step-number">3</span>项目初始化</h3>

<p>创建项目并安装所需依赖:</p>

<divclass="code-header">

<span>Terminal</span>

<buttonclass="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>


<divclass="step">

<h3><spanclass="step-number">4</span>创建基本爬虫服务</h3>

<p>创建<code>index.js</code>文件,设置 Koa 服务器和爬虫路由:</p>

<divclass="code-header">

<span>index.js</span>

<buttonclass="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) => {

   // 从查询参数获取URL

   const 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>


<divclass="step">

<h3><spanclass="step-number">5</span>运行爬虫服务</h3>

<p>启动服务器:</p>

<divclass="code-header">

<span>Terminal</span>

<buttonclass="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>


<divclass="step">

<h3><spanclass="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>


<divclass="tip-box">

<divclass="tip-title">

<iclass="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>


<divclass="demo">

<h2>爬虫演示</h2>


<divclass="browser-window">

<divclass="browser-header">

<divclass="browser-dot dot-red"></div>

<divclass="browser-dot dot-yellow"></div>

<divclass="browser-dot dot-green"></div>

</div>

<divclass="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>


<divclass="demo-controls">

<inputtype="text"class="url-input"id="crawlUrl"placeholder="输入要爬取的URL (例如: https://example.com)"value="https://example.com">

<buttonclass="run-btn"id="runCrawler">

<iclass="fas fa-play"></i>

<span>运行爬虫</span>

</button>

</div>


<divclass="results"id="results">

<p>爬取结果将显示在这里...</p>

</div>

</div>

</div>


<divclass="features">

<divclass="feature-card">

<divclass="feature-icon">

<iclass="fas fa-bolt"></i>

</div>

<h3>高效灵活</h3>

<p>Koa的轻量级架构结合Puppeteer的强大浏览器控制能力,可以构建高效灵活的爬虫系统,处理各种复杂的网站结构。</p>

</div>


<divclass="feature-card">

<divclass="feature-icon">

<iclass="fas fa-laptop-code"></i>

</div>

<h3>JavaScript渲染支持</h3>

<p>Puppeteer可以完整渲染JavaScript生成的内容,轻松爬取单页应用(SPA)和动态加载的网站,这是传统爬虫难以实现的。</p>

</div>


<divclass="feature-card">

<divclass="feature-icon">

<iclass="fas fa-shield-alt"></i>

</div>

<h3>自动化测试</h3>

<p>除了爬虫功能,Puppeteer还可用于自动化测试、性能监控和UI测试,为项目提供全方位的自动化支持。</p>

</div>

</div>


<divclass="footer">

<p>© 2023 Koa + Puppeteer 爬虫教程 | 本教程仅用于学习目的,请遵守目标网站的robots.txt和法律法规</p>

</div>

</div>

<script>

// 模拟爬虫结果

document.getElementById('runCrawler').addEventListener('click',function() {

consturlInput=document.getElementById('crawlUrl').value;

constresultsDiv=document.getElementById('results');


if(!urlInput) {

alert('请输入URL');

return;

           }


// 显示加载状态

resultsDiv.innerHTML='<p class="result-item"><i class="fas fa-spinner fa-spin"></i> 正在爬取数据,请稍候...</p>';


// 模拟网络请求延迟

setTimeout(()=>{

// 模拟爬取结果

constmockData={

title:"示例域名 | "+newURL(urlInput).hostname,

content:"这是一个示例网站。这段文本是从爬虫返回的模拟内容。在实际应用中,这里将显示从目标网站抓取的真实内容。",

links: [

"https://"+newURL(urlInput).hostname+"/about",

"https://"+newURL(urlInput).hostname+"/products",

"https://"+newURL(urlInput).hostname+"/contact"

                   ]

               };


// 显示结果

lethtml=`

<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() {

constcodeBlock=this.parentElement.nextElementSibling;

consttextToCopy=codeBlock.textContent;


navigator.clipboard.writeText(textToCopy).then(()=>{

constoriginalText=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文件即可查看完整的教程页面,我们可以通过右侧的演示区域模拟爬虫运行效果。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容