爬虫快速入门(有实例)

423 阅读4分钟

爬虫的思路

    1. 确定爬取对象
    1. 分析页面内容(DOM结构)
    1. 确定开发语言(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)