Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Javascript] node爬虫来一份 #24

Open
zgfang1993 opened this issue Jul 8, 2018 · 0 comments
Open

[Javascript] node爬虫来一份 #24

zgfang1993 opened this issue Jul 8, 2018 · 0 comments

Comments

@zgfang1993
Copy link
Owner

zgfang1993 commented Jul 8, 2018

自己写的小项目可能需要一些数据,自己写mock数据又麻烦,可以通过爬虫来获取一些数据。

  • 需要的模块,及简单讲解
  • 一个简单的爬虫demo

需要使用的模块

  • superagent 获取页面数据
  • cheerio 解析页面数据
  • fs 数据保存本地文件 node自带文件系统模块
npm install superagent cheerio --save

superagent 页面数据下载

超级代理,是一个http请求模块,常用于get、post等请求,可以实现请求操作,还有一些表单post操作,模拟ajax请求等,支持链式调用。

superagent.post(url)
    .set(headers)  //设置请求头
    .set('Cookie', cookie)  // 设置cookie
    .type('form')
    .send({
        //表单数据
    })
    .end(function(err, res) {
        //数据与错误处理
    })

扩展:superagent-charset
superagent只支持UTF-8,用了这个库可以指定编码,当用superagent爬出乱码时可以用它。

superagent.get(url)
    .set(headers) 
    .charset('gbk') //指定编码
    .end(function(err, res) {
        if (err) {
            return console.err(err);
        }
    })
    

cheerio 页面数据解析

可以使用大量jQuery的语法来获取你爬虫请求到的数据

$ = cheerio.load(res.text);
// $(".XXX")选中class
// $("#XXX")选中id

demo 下厨房里面的菜谱数据

  1. 引入工具模块
const superagent = require('superagent');
const cheerio = require('cheerio');

2.发请求获取数据

const reptileUrl = "www.xiachufang.com/explore";

superagent
  .get(reptileUrl)
  .end(function (err, res) {
     if(err){
        throw Error(err);
     }
    // 处理数据
});

现在可以运行 node app.js看一下请求。此时会报错。获得了一个Forbidden错误。网站对于访问进行了检查,我们复制请求头,重写网络请求。

superagent
  .get(reptileUrl)
  .set('Connection','keep-alive')
  .set('User-Agent','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36')
  .set('Host', 'www.xiachufang.com')
  .end(function (err, res) {
     if(err){
        throw Error(err);
     }
    // 处理数据
});

3.解析数据

superagent
  .get(reptileUrl)
  .set('Connection','keep-alive')
  .set('User-Agent','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36')
  .set('Host', 'www.xiachufang.com')
  .end(function (err, res) {
     if(err){
        throw Error(err);
     }
    // 处理数据
   /**
      * res.text 包含未解析前的响应内容
      * 通过cheerio的load方法解析整个文档,就是html页面所有内容.
      */
   let $ = cheerio.load(res.text);
   // console.log($.html());
});

4.分析页面结构,拼接数据
现在需要打开下厨房网站本周最受欢迎页面,列表展示的信息都是服务端渲染的。爬虫就是获取服务端渲染的数据,ajax获取的数据的话,直接调api接口即可。我们就以获取第一列数据为例子。

// 列表数据都存在$('.normal-recipe-list')这个容器里面,只需要遍历
const list = $('.normal-recipe-list .list li');
list.each((i, elem)=>{
  // 拼接数据
})

定义数据结构

{
  "id": "100519211", // 菜谱id
  "name": "超级无敌好吃的奥利奥牛奶雪糕!!", // 菜谱名字
  "exclusive": true, // 是否独家
  "img": "", 
  "material": "", // 菜谱材料
  "author": {
    "id": "",
    "name": ""
  }
}
 function replaceText(text){
   return text.replace(/\n/g, "").replace(/\s/g, ""); // 去除回车符/n和空格符/s
 }
  list.each((i, elem)=>{
    const $this = $(elem);
    const item = {
      "id": $this.children('a').attr('href').replace(/\/recipe\//, '').replace(/\/$/, ''),
      "name": replaceText($this.find('.info .name').text()), // 名字
      "exclusive": !!$this.find('.info .exclusive-icon'), // 是否独家
      "img": $this.find('.cover img').attr('src'),
      "material": replaceText($this.find('.info .ing').text()),
      "author": {
        "id": $this.find('.info .author a').attr('href').replace(/\/cook\//, "").replace(/\/$/, ''),
        "name": replaceText($this.find('.info .author a').text())
      }
    }
    data.push(item);
  });

5.保存数据到本地文件

  // 写入数据
  fs.writeFile(__dirname + `/data/${new Date().getTime()}.json`, JSON.stringify({
    status: 0,
    data: data
  }), function (err) {
    if (err) throw err;
    console.log('写入完成');
  });

完整代码

const fs = require('fs');
const superagent = require('superagent');
const cheerio = require('cheerio');

const reptileUrl = "www.xiachufang.com/explore";

// 去除回车符/n和空格符/s
function replaceText(text){
  return text.replace(/\n/g, "").replace(/\s/g, "");
}

superagent
  .get(reptileUrl)
  .set('Connection','keep-alive')
  .set('User-Agent','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36')
  .set('Host', 'www.xiachufang.com')
  .end(function (err, res) {
  // 抛错拦截
   if(err){
      throw Error(err);
   }
  /**
  * res.text 包含未解析前的响应内容
  * 通过cheerio的load方法解析整个文档,就是html页面所有内容.
  */
  let $ = cheerio.load(res.text);
  // console.log($.html());
  const data = [];
  const list = $('.normal-recipe-list .list li .recipe');
  list.each((i, elem)=>{
    const $this = $(elem);
    const item = {
      "id": $this.children('a').attr('href').replace(/\/recipe\//, '').replace(/\/$/, ''),
      "name": replaceText($this.find('.info .name').text()), // 名字
      "exclusive": !!$this.find('.info .exclusive-icon'), // 是否独家
      "img": $this.find('.cover img').attr('src'),
      "material": replaceText($this.find('.info .ing').text()),
      "author": {
        "id": $this.find('.info .author a').attr('href').replace(/\/cook\//, "").replace(/\/$/, ''),
        "name": replaceText($this.find('.info .author a').text())
      }
    }
    data.push(item);
  });
  
  // 创建data文件夹
  if (!fs.existsSync('data')) {
    fs.mkdirSync('data');
  }
  // 写入数据
  fs.writeFile(__dirname + `/data/${new Date().getTime()}.json`, JSON.stringify({
    status: 0,
    data: data
  }), function (err) {
    if (err) throw err;
    console.log('写入完成');
  });
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant