Nodejs写一个网页爬虫
Nodejs写一个网页爬虫
需求背景
喜欢唯美的句子,喜欢抒发情感的文章,经常去短文学网上看别人些的优美词句。有时候想找特定关键词的文章,避免一篇一篇滚动查找,然后用Node写了一个简单的爬虫工具。
功能需求
- 输入域名,点击“确定”按钮列出当前域名下的文章标题列表
- 可以选择是否输入关键字,输入了关键字,可以查找出文章标题包含该关键字的列表
功能演示
使用技术
- Nojejs+Koa框架 搭建项目
- koa-ejs模板引擎 渲染页面
项目结构
api
index.js
router
home.js
static
js
css
index.css
utils
request.js
view
home.html
index.js
项目大致结构按上述文件夹划分,api(前台页面发送ajax请求的路由地址)、router(页面路由)、static(静态文件)、utils(工具类)、view(模板文件)、index.js(入口文件)
模板引擎 koa-ejs
koa-ejs是中间件,它支持ejs所有的特性。
npm install --save-dev koa-ejs
用法:
const ejs = require('koa-ejs');
const Koa = require('koa');
const app = new Koa();
ejs(app,{
root:'./view',
layout:false,
viewExt:'html'
});
koa-ejs参数配置
- root:模板文件根目录
- layout:全局模板文件,设置为false禁用全局布局
- viewExt:指定模板文件后缀名
- cache:缓存编译模板,默认为true
- debug:是否开启debug调试,默认为false
语法:
-
判断语句
<% if(...){ %><% } %> -
变量输出
<%= 变量名 %> -
循环语句
<% list.forEach(function(item){ %> <p><%= item.title %></p> <% }) %>
路由 koa-router
npm install --save-dev koa-router
用法:
const Koa = require('koa');
const Router = require('koa-router');
const router = new Router();
const app = new Koa();
router.get('/',async (ctx,next) => {
ctx.body = {
msg:'hello'
}
})
app.use(router.routes())
API:
- router.get()
- router.post()
- router.put()
- router.del()
- router.all()
传递参数和接收参数
router.all('/a/:id',(ctx,next) => {
console.log(ctx.params) //ctx.params接收参数
ctx.body = 'dso';
})
网络请求 request
npm install --save-dev request
用法:
request('http://www.google.com',(err,response,body) => {
if(response.statusCode === 200){
console.log(body)
}else{
console.error(error)
}
})
如上代码可以很方便的请求一个域名的信息
使用promise特性封装请求,解决异步回调的问题,在utils文件下创建request.js文件,输入以下代码
const request = require('request');
const iconv = require('iconv-lite');
const requestPromise = (url) => {
return new Promise((resolve,reject) => {
request(url,{encoding:null},(err,response,body) => {
if(response.statusCode === 200){
const bufs = iconv.decode(body,'gb2312');
const html = bufs.toString('uft8');
resolve(html);
}else{
reject(err)
}
})
})
}
module.exports = requestPromise;
上述代码中有一行const iconv = require('iconv-lite');这里所使用到的npm包是解决请求回来的数据可能出现乱码问题的。 既然我们使用到了它,当然需要先引入它
npm install --save-dev iconv-lite
有可能元网站的charset设置的不是utf8编码,那么我们取回来的页面信息,中文会是乱码的。 此时我们需要使用这个包来处理取回来的网页信息。
const bufs = iconv.decode(body,'gb2312');
const html = bufs.toString('uft8');
cheerio
cheerio可以想jquery一样操作DOM元素,需要对网页信息进行分析,哪些信息是我们所需要的,比如我们需要 文章的标题信息、文章列表等等。我们就可以使用cheerio操作DOM元素进行筛选。
npm install --save-dev cheerio
用法:
const cheerio = require('cheerio');
const $ = cheerio.load(html);
//选择器 找对目标元素 遍历
$("body > div.row.inner-row > div.row-left > div.list-base-article > ul > li a").each((i,item) => {
const textStr = $(item).text()
})
需求代码
上面篇幅介绍了完成该需求所涉及到的一些技能点后,下面就开始正式撸代码啦。
流程
- 确定爬取目标域名
- 查看所需要爬取的信息所在的DOM元素信息标识
- 根据DOM元素信息标识筛选目标信息
- ajax请求得到目标信息渲染页面
入口文件index.js,配置静态文件,引入页面路由,api接口路由
const koa = require('koa')
const path = require('path')
const render = require('koa-ejs');
const static = require('koa-static');
const parser = require('koa-bodyparser');
const home = require('./router/home');
const qinggan = require('./api/index')
// koa
const server = new koa();
server.use(parser());
render(server,{
root:path.join(__dirname,'view'),
layout:false,
viewExt:'html'
});
server.use(static(__dirname+'/static'));
// router
server.use(home.routes());
server.use(qinggan.routes());
server.listen(3000);
api 接口index.js,定义前端请求的接口地址,处理爬取的目标信息
const Router = require('koa-router');
const cheerio = require('cheerio');
const requestPromise = require('../utils/request');
const router = new Router({
prefix:'/api'
});
const host = 'https://www.duanwenxue.com'
// https://www.duanwenxue.com/sanwen/shuqing/
// https://www.duanwenxue.com/jingdian/shenghuo/
// https://www.duanwenxue.com/qinggan/meiwen/
// https://www.duanwenxue.com/sanwen/suibi/
//https://www.duanwenxue.com/shanggan/ganrengushi/
router.post('/getQinggan',async (ctx,next) => {
const {website,keywords} = ctx.request.body;
const html = await requestPromise(website);
const $ = cheerio.load(html);
let arr = []
$("body > div.row.inner-row > div.row-left > div.list-base-article > ul > li a").each((i,item) => {
const textStr = $(item).text()
if(textStr.indexOf(keywords) > -1){
arr.push({
src:host + $(item).attr('href'),
name:$(item).text()
})
}
})
ctx.body = {
data:arr
}
})
module.exports = router;
模板文件home.html,模板文件中使用ajax技术请求接口地址
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<% if(name){ %>
<h1><%= name %></h1>
<% } %>
<% list.forEach(function(item){ %>
<p><%= item.title %></p>
<% }) %>
<div class="wrapper">
<p class="input-item">
<input type="text" class="website" placeholder="请输入网址">
</p>
<p class="input-item">
<input type="text" class="keywords" placeholder="请输入关键词">
</p>
<p class="input-item">
<button class="btn">点击</button>
</p>
</div>
<div class="wrapper-data">
</div>
<script src='js/jquery.1.8.2.min.js'></script>
<script>
$('.btn').click(function(){
const param = {
website:$('.website').val()
}
$('.wrapper-data').html('');
$.ajax({
url:'http://localhost:3000/api/getQinggan',
type:'post',
data:{
website:$('.website').val(),
keywords:$('.keywords').val()
},
dataType:'json',
success:function(res){
var html = '';
res.data.forEach(item => {
html += `<p><a href="${item.src}">${item.name}</a></p>`
})
$(".wrapper-data").append(html)
}
})
})
</script>
</body>
</html>
以上,把自己学习的知识点做个总结,实现一个简单的网页爬虫,不足之处请各位大佬指正。虚心学习,快乐进步。
点击这里看项目源代码 欢迎star
浙公网安备 33010602011771号