爬虫的思路
-
- 确定爬取对象
-
- 分析页面内容(DOM结构)
-
- 确定开发语言(Nodejs+express+superagent(第三方客户端请求代理模块 做请求)+cheerio(对抓取的数据进行分析)+nightmare(自动化测试整个浏览器,动态请求网站))
-
- 3.1 express启动了一个http服务
-
- 3.2 使用superagent\nightmare请求目标页面
-
- 3.3 使用cheerio获取页面元素,获取元素中的内容
-
- 3.4 将返回的数据给前端浏览器
这里我们的例子是获取百度新闻中热点新闻的新闻标题跟链接
格式为
/*
[
{
title:'风卷红旗过大关',
href:'http://www.xinhuanet.com/2021-01/03/c_1126940730.htm'
},{
}
]
*/
0.准备工作
npm init
cnpm i express -S
1.启动一个http服务
这里使用express搭建服务器
//搭建服务器
const express = require('express')
const app = express();
app.get('/',(req,res)=>{
res.send('启动http服务');
})
let server = app.listen(3000)
2.分析目标页面内容
假设我们要爬取百度新闻里的热点新闻中的每条新闻跟对应的链接
F12打开控制台去查找热点新闻对应的id
查看具体每条新闻的标签
得到了'#pane-news ul li a'
3.使用 superagent来访问目标页面并且获取页面内容
这里要下载superagent
cnpm i superagent -S
superagent作为第三方客户端访问目标页面 详细了解可参考 github.com/visionmedia…
3.1 引入superagent模块
const superagent = require('superagent')
3.2 使用superagent.get()方法来获取百度新闻首页
- 创建一个储存返回回来的数据的数组hotNews
- 让superagent获取的页面内容去getHotNews里去做处理(还没创建getHotNews),返回我们需要的内容
let hotNews = [];
superagent.get('http://news.baidu.com/').end((err,res)=>{
if(err){
console.log('热点新闻抓取失败' + err);
}else{
//所返回的数据会包含在res中
hotNews = getHotNews(res);
}
})
github上的代码截图或许能帮助快速理解superagent用法
4.使用cheerio来对页面返回的内容做处理 得到我们目标值
4.1 创建getHotNews
创建一个howNews值 后面返回出去
let getHotNews = res=>{
let hotNews = [];
return hotNews;
}
4.2 使用cheeiro处理
cheeiro是为服务器特别定制的,快速、灵活、实施的jQuery核心实现.
4.2.1 下载cheeiro
cnpm i cheeiro -S
4.2.2 引入cheeiro模块
const cheerio = require('cheerio')
4.2.3 获取目标值
- 通过cheerio.load(res.text)得到$
- $查询目标标签 用each方法遍历并且赋值
- 将所有值推到先前创建的数组 最后返回出去
let getHotNews = res=>{
let hotNews = [];
//通过第三方库得到 $
let $ = cheerio.load(res.text);
$('#pane-news ul li a').each((index,ele) => {
let news = {
title: $(ele).text(), //获取新闻标题
href: $(ele).attr('href') //获取新闻的网页链接
}
hotNews.push(news); //存入最终结果数组
})
return hotNews;
}
5.将值传递到前端浏览器
此时hotNews的值已经获得到了我们想要的值 只需传递到前端浏览器即可
完整代码
//搭建服务器
const express = require('express')
const app = express();
//第三方客户端访问目标页面
const superagent = require('superagent')
//为服务器特别定制的,快速、灵活、实施的jQuery核心实现.
const cheerio = require('cheerio')
let hotNews = [];
//使用superagent.get()方法来获取百度新闻首页
superagent.get('http://news.baidu.com/').end((err,res)=>{
if(err){
console.log('热点新闻抓取失败' + err);
}else{
//所返回的数据会包含在res中
// console.log(res.text);
hotNews = getHotNews(res);
}
})
//处理superagent返回的数据 抓取热点新闻的页面
let getHotNews = res=>{
let hotNews = [];
//通过第三方库得到 $
let $ = cheerio.load(res.text);
$('#pane-news ul li a').each((index,ele) => {
let news = {
title: $(ele).text(), //获取新闻标题
href: $(ele).attr('href') //获取新闻的网页链接
}
hotNews.push(news); //存入最终结果数组
})
return hotNews;
}
app.get('/',(req,res)=>{
res.send(hotNews);
})
let server = app.listen(3000)
如何获取百度新闻里的本地新闻
如果按上述步骤去获取百度新闻里的本地新闻是捕获不到的
可以尝试更改下部分代码
let pageRes = {};
superagent.get('http://news.baidu.com/').end((err,res)=>{
if(err){
console.log('热点新闻抓取失败' + err);
}else{
pageRes = res;
}
})
app.get('/',(req,res)=>{
res.send(pageRes.text)
})
会得到
本地新闻(也就是北京新闻那块并没有加载出来)所以不能获取到想要的标签
那么如何获取这种数据呢
1.使用nightmare来获取页面
1.1 下载nightmare
cnpm i nightmare -S
1.2 引入nightmare模块
const Nightmare = require('nightmare')
const nightmare = Nightmare({ show: false })//显示内置模拟浏览器
nightmare例子图
详情参考 github.com/segmentio/n…
1.3 nightmare获取页面
.wait()里最好拿目标的父元素
- .goto()访问目标页面
- .wait()参数可以使时间(毫秒),也可以是标签。表示会等待到这些时间后,或页面加载了这个标签后
- .evaluate()参数是一个回调函数,得到的值是直接传到.then方法里
- .then()参数是一个回调函数,在这里将拿到的值做操作 这里将返回的值htmlStr拿到getLocalNews(还未创建)做操作
let localNews = [];
nightmare.goto('http://news.baidu.com/')
.wait('div#local_news')
.evaluate(() => document.querySelector('div#local_news').innerHTML)
.then(htmlStr=>{
localNews = getLocalNews(htmlStr)
})
.catch(err=>{
console.log(err);
})
2.将拿到的值用cheerio做处理
操作跟获取热点新闻基本一致 唯一不同的是传过来的值在cheerio.load()里不需要.text处理
let getLocalNews = htmlStr => {
/*
#localnews-focus li a 本地新闻
#localnews-zixun ul li a 新闻资讯
*/
let localNews = [];
let $ = cheerio.load(htmlStr);
//本地新闻
$('#localnews-focus li a').each((index,ele) => {
let news = {
title: $(ele).text(),
href: $(ele).attr('href')
};
localNews.push(news);
})
//本地资讯
$('#localnews-zixun ul li a').each((index, ele) => {
let news = {
title: $(ele).text(),
href: $(ele).attr('href')
};
localNews.push(news);
})
return localNews;
}
做完这步就会有localNews的值了 接下来传递到前端浏览器就好了
完整代码
//搭建服务器
const express = require('express')
const app = express();
//第三方客户端访问目标页面
const superagent = require('superagent')
//为服务器特别定制的,快速、灵活、实施的jQuery核心实现.
const cheerio = require('cheerio')
//
const Nightmare = require('nightmare')
const nightmare = Nightmare({ show: false })//显示内置模拟浏览器
//a标签:新闻的标题和连接
/*
[
{
title:'风卷红旗过大关',
href:'http://www.xinhuanet.com/2021-01/03/c_1126940730.htm'
},{
}
]
*/
let hotNews = [];
let localNews = [];
// let pageRes = {};
app.get('/',(req,res)=>{
res.send({
hotNews:hotNews,
localNews:localNews
});
// res.send(pageRes.text)
})
//使用superagent.get()方法来获取百度新闻首页
superagent.get('http://news.baidu.com/').end((err,res)=>{
if(err){
console.log('热点新闻抓取失败' + err);
}else{
//所返回的数据会包含在res中
// console.log(res.text);
hotNews = getHotNews(res);
// localNews = getLocalNews(res);
// console.log(localNews);
// pageRes = res;
}
})
// nigthmare
nightmare.goto('http://news.baidu.com/')
.wait('div#local_news')
.evaluate(() => document.querySelector('div#local_news').innerHTML)
.then(htmlStr=>{
localNews = getLocalNews(htmlStr)
})
.catch(err=>{
console.log(err);
})
// 抓取本地新闻
let getLocalNews = htmlStr => {
/*
#localnews-focus li a
#localnews-zixun ul li a
*/
let localNews = [];
let $ = cheerio.load(htmlStr);
//本地新闻
$('#localnews-focus li a').each((index,ele) => {
let news = {
title: $(ele).text(),
href: $(ele).attr('href')
};
localNews.push(news);
})
//本地资讯
$('#localnews-zixun ul li a').each((index, ele) => {
let news = {
title: $(ele).text(),
href: $(ele).attr('href')
};
localNews.push(news);
})
return localNews;
}
//处理superagent返回的数据 抓取热点新闻的页面
let getHotNews = res=>{
let hotNews = [];
//通过第三方库得到 $
let $ = cheerio.load(res.text);
$('#pane-news ul li a').each((index,ele) => {
let news = {
title: $(ele).text(), //获取新闻标题
href: $(ele).attr('href') //获取新闻的网页链接
}
hotNews.push(news); //存入最终结果数组
})
return hotNews;
// #pane-news ul li a
}
let server = app.listen(3000)