文档章节

[Nodejs] 用node写个爬虫

o
 osc_a22drz29
发布于 2019/03/22 18:03
字数 1452
阅读 20
收藏 0

精选30+云产品,助力企业轻松上云!>>>

寻找爬取的目标

首先我们需要一个坚定的目标,于是找个一个比较好看一些网站,将一些信息统计一下,比如 url/tag/title/number...等信息

1

init(1, 2); //设置页数,现在是1-2页

async function init(startPage, endPage) {
  for (let i = startPage; i <= endPage; i++) {
    await getAndSaveImg(i);
  }
    .....
}

一般网站都会进行一些反爬虫处理,这时候就需要一个 ip 代理池进行 ip 伪装了.

网络请求

使用一个 nodejs 的模块 request,这个模块可以让 node 的 http 请求变的更加简单,同时支持 http/https 请求还可以将任何请求输出到文件流.

request.post({url:'http://service.com/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
  if (err) {
    return console.error('upload failed:', err);
  }
  console.log('Upload successful!  Server responded with:', body);
});

使用 request 封装个方法进行请求

新建 utils/ajax.js

let request = require("request");

module.exports = {
  handleRequestByPromise
};

function handleRequestByPromise(options) {
  let op = Object.assign(
    {},
    {
      url: "",
      method: "GET",
      encoding: null,
      header: {
        "User-Agent":
          "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
        Referer: "https://www.meituri.com"
      }
    },
    options
  );

  if (op.url === "") {
    throw new Error("请求的url地址不正确");
  }

  const promise = new Promise(function(resolve, reject) {
    request(op, (err, response, body) => {
      if (err) reject(err);

      if (response && response.statusCode === 200) {
        resolve(body);
      } else {
        reject(`请求✿✿✿${url}✿✿✿失败`);
      }
    });
  });

  return promise;
}

cheerio

官网

爬虫需要抓取页面上特定的信息.需要依据一些标识符去拿到想要的信息,不如 id.比如 class.cheerio 就是这么一个工具,将网站信息转化成可以直接用 jquery 的 dom 进行提取的一个模块.cheerio 的出现就是用于服务端需要对 dom 进行操作的地方.

基本使用

let cheerio = require('cheerio');
let $ = cheerio.load("<div id='helloworld'>hello world</div>", {ignoreWhitespace: true...})

options 用来进行一些特别的定制更多

选择器

基本和 jquery 一样

  • $( selector, [context], [root] )
$(".helloworld").text();

属性操作

  • .attr(name, value)
  • .removeAtrr(name)
  • .hasClass(className)
  • .addClass(className)
  • .remoteClass([className])

遍历

  • .find(selector)
  • .parent()
  • .next()
  • .prev()
  • .siblings()
  • .children( selector )
  • .each( function(index, element) )
  • .map( function(index, element) )
  • .filter( selector )
  • .filter( function(index) )
  • .first()
  • .last()
  • .eq(i)

操作 DOM

  • .append( content, [content, ...] )
  • .prepend( content, [content, ...] )
  • .after( content, [content, ...] )
  • .before( content, [content, ...] )
  • .remove( [selector] )
  • .replaceWith( content )
  • .empty()
  • .html( [htmlString] )
  • .text( [textString] )

其他

  • $.html()
  • $('ul').text()
  • .toArray()
  • .clone()
  • $.root()
  • $.contains( container, contained )

在项目中使用

  let homeBody = await handleRequestByPromise({ url: pageImgSetUrl });
  let $ = cheerio.load(homeBody);
  let lis = $(".hezi li");

上面就是将获取的 html 数据通过 cheerio 转化后,可以直接使用$符号进行类似 dom 的使用方法.特别适合前端使用

iconv-lite

有些时候,获取到的数据是一些乱码,尤其是中文的情况.所以我们需要解决乱码的问题,iconv-lite 模块就可以解决这一问题.

homeBody = iconv.decode(homeBody,"GBK"); //进行gbk解码

如果乱码就在 cheerio.load()之前进行解码.(这次用的网站并没有乱码).原因是

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> //这里是utf-8

如果是 gbk 或者 gbk2312 等就需要解码了

爬取流程

  1. 找寻目标
  2. 控制台查看 dom 的信息存放或标识符(id,class,element)
  3. 爬取 title,url,tag,num 等信息进行存放
  4. 进行下载(如果只需要链接其实可以不下载,不过许多网站对图片外部引入有限制)
  5. 入库(mysql)
  6. 出个 html 进行图片查看(简易写真集网站)

初始化

还是创建一个本地服务器,异步没有使用 async 模块,而是直接使用 es6 的 async/await 语法.

let http = require("http");
let url = require("url");
let Extend = require("./Extend");
let xz = new Extend(1, 2);

http
  .createServer((request, response) => {
    let pathname = url.parse(request.url).pathname;
    if (pathname !== "/favicon.ico") {
      router(pathname)(request, response);
    }
  })
  .listen(9527);
console.log("server running at http://127.0.0.1:9527/");

function router(p) {
  let router = {
    "/": (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
      response.end();
    },
    "/xz": async (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
      await xz.init(response);
      response.end();
    },
    "/404": (request, response) => {
      response.writeHead(404, { "Content-Type": "text/plain;charset=utf-8" });
      response.end("404找不到相关文件");
    }
  };
  !Object.keys(router).includes(p) && (p = "/404");
  return router[p];
}

分析页面

直接右键在控制台中查看就好了,看看 class,id 什么,cheerio 实现的 jquery 的 dom 相关的 api 十分强大,直接$("")就行

进行网站的分析和抓取

开始进行网站数据的分析和爬取,如果乱码就在 cheerio 操作之前进行解码就行了,这样通过一个变量将爬取的数据全部保存起来.也可以创建相应的文件夹和 txt 文件进行保存(writeFile),还可以直接在这里就将数据保存到数据库.(看心情)

async getAndSaveImg(page) {
    let pageImgSetUrl = ``;

    if (page === 1) {
      pageImgSetUrl = `${this.siteUrl}`;
    } else {
      pageImgSetUrl = `${this.siteUrl}${page}.html`;
    }

    let homeBody = await handleRequestByPromise({ url: pageImgSetUrl });
    let $ = cheerio.load(homeBody);
    let lis = $(".hezi li");

    for (let i = 0; i < lis.length; i++) {
      let config = {
        href: lis
          .eq(i)
          .find("a")
          .eq(0)
          .attr("href"),
        num: lis
          .eq(i)
          .find(".shuliang")
          .text(),
        title: lis
          .eq(i)
          .find(".biaoti a")
          .text()
          .replace(/\//, "")
      };

      config.childs = [];

      let num = Number(config.num.substr(0, 2));
      for (let j = 1; j <= num; j++) {
        let link = config.href.replace(
          this.collectUrl,
          "https://ii.hywly.com/a/1/"
        );
        let a_link = `${link}${j}.jpg`;
        config.childs.push(a_link);
      }
      this.all.push(config);
    }
  }

3

进行图片的下载

开始进行图片的下载,并且创建相应的文件夹进行保存

async downloadAllImg() {
    let length = this.all.length;

    for (let index = 0; index < length; index++) {
      let childs = this.all[index].childs;
      let title = this.all[index].title;

      if (childs) {
        let c_length = childs.length;
        for (let c = 0; c < c_length; c++) {
          if (!fs.existsSync(`mrw`)) {
            fs.mkdirSync(`mrw`);
          }

          if (!fs.existsSync(`mrw/${title}`)) {
            fs.mkdirSync(`mrw/${title}`);
          }

          await super.downloadImg(
            childs[c],
            `mrw/${title}/${title}_image${c}.jpg`
          );

          console.log(
            "DownloadThumbsImg:",
            title,
            "SavePath:",
            `mrw/${title}/${title} image${c}.jpg`
          );
        }
      }
    }
  }

2 4

下载完之后存入数据库

下载 mysql 模块进行 mysql 数据库操作

const fs = require("fs");
const mysql = require("mysql");
const path_dir = "D:\\data\\wwwroot\\xiezhenji.web\\static\\mrw\\";
const connection = mysql.createConnection({
  host: "xxxx",
  port: "xxxx",
  user: "xiezhenji",
  password: "iJAuzTbdrDJDswjPN6!*M*6%Ne",
  database: "xiezhenji"
});

module.exports = {
  insertImg
};

function insertImg() {
  connection.connect();

  let files = fs.readdirSync(path_dir, {
    encoding: "utf-8"
  });

  files.forEach((file, index) => {
    let cover_img_path = `/mrw/mrw_${index + 1}/image_1`;

    insert([
      "美女",
      file,
      Number(files.length),
      file,
      cover_img_path,
      `mrw/mrw_${index + 1}`,
      `mrw_${index + 1}`
    ]);
  });
}

function insert(arr) {
  let sql = `INSERT INTO photo_album_collect(tags,name,num,intro,cover_img,dir,new_name) VALUES(?,?,?,?,?,?,?)`;
  let sql_params = arr;

  connection.query(sql, sql_params, function(err, result) {
    if (err) {
      console.log("[SELECT ERROR] - ", err.message);
      return;
    }
    console.log("--------------------------SELECT----------------------------");
    console.log(result);
    console.log(
      "------------------------------------------------------------\n\n"
    );
  });
}

Docs

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
nodejs入门教程之http的get和request简介及应用

nodejs入门教程之http的get和request简介及应用前言上一篇文章,我介绍了nodejs的几个常用的模块及简单的案例,今天我们再来重点看一下nodejs的http模块,关于http模块,我们可以看下nodejs官...

osc_d5exiys5
2018/07/13
2
0
鼓捣phantomjs(二) node.js模块化集成

著作权所有:http://www.cnblogs.com/zeusro/ 引用(爬虫)不给稿费的,切你jj 追忆似屎年华 在上一篇post(http://www.cnblogs.com/zeusro/p/4185196.html)里面,我留下了3个坑没有填平。 ...

amiba.org
2014/12/27
0
0
Node及后端

找回 Node.js 里面那些遗失的 ES6 特性 | Taobao FED | 淘宝前端团队 由于 Babel,WebPack, React 技术的流行, 小明同学已经开始在前端代码里面用上了 ECMAScript 2015 (以下称 ES6 ) 的...

掘金官方
2017/12/27
0
0
使用Termux,在手机上做nodejs编程,运行nodejs程序。

如果你是一名nodejs开发者,是否想过以下问题: 在手机上运行nodejs程序? 用手机当nodejs服务器? 在手机上做nodejs编程? YES!使用Termux,以上都可以做到! 下面展示如何实现这个黑魔法。...

osc_0ij3yxc4
2019/11/20
20
0
打算写一个《重学Node.js》系列,希望大家多多支持

先放上链接吧,项目已经开始2周了:https://github.com/hellozhangran/happy-egg-server 想法 现在是2019年11月24日,还有人要开始学习Node.js吗? Node.js大概从2014年开始火热,现在搜一下...

osc_iqtexsjp
04/16
6
0

没有更多内容

加载失败,请刷新页面

加载更多

等到所有jQuery Ajax请求都完成了吗? - Wait until all jQuery Ajax requests are done?

问题: How do I make a function wait until all jQuery Ajax requests are done inside another function? 我如何让一个函数等到所有jQuery Ajax请求都在另一个函数中完成之后? In short...

富含淀粉
15分钟前
0
0
OSChina 周日乱弹 —— 那么长的绳子,你这是放风筝呢

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @ 巴拉迪维:黑豹乐队的单曲《无地自容》 耳畔突然响起旋律,是那首老歌。中国摇滚有了《一无所有》不再一无所有;中国摇滚有了《无地自容》不...

小小编辑
今天
65
1
《吐血整理》-顶级程序员书单集

你知道的越多,你不知道的越多 给岁月以文明,而不是给文明以岁月 前言 王潇:格局决定了一个人的梦想,梦想反过来决定行为。 那格局是什么呢? 格局是你能够看见的深度、广度和密度。 王潇认...

敖丙
2019/12/11
11
0
我可以在Android版式中加下划线吗? - Can I underline text in an Android layout?

问题: 如何在Android布局xml文件中定义带下划线的文本? 解决方案: 参考一: https://stackoom.com/question/A31z/我可以在Android版式中加下划线吗 参考二: https://oldbug.net/q/A31z/...

法国红酒甜
今天
26
0
干掉ELK | 使用Prometheus+Grafana搭建监控平台

什么是Prometheus? Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB)。Prometheus使用Go语言开发,是Google BorgMon监控系统的开源版本。 Prometheus的特点 · 多维度...

木九天
今天
34
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部