这是我用18行代码写的爬虫,基于Node.j实现

1,510 阅读2分钟

前言

本文介绍一个简单的爬虫,是基于Node.js写的,由于我水平不高,所以写的功能不完善,实现方法比较简单,仅用于学习。

什么是爬虫

网络爬虫(又称为网页蜘蛛),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。简单来说,自动爬取目标网站内容的工具。

爬虫的原理

通过爬虫,发起网页请求,获取到网页信息,接着进行网页解析,最后根据HTML结构,获取我们想要的信息。

准备工作

需要导入三个模块:

  • axios:http库,可以用http模块或request代替。好处是返回的是promise对象,对我们解决异步提供了很大便利
  • cheerio:能让我们在服务器以jq语法操作dom(服务端的JQ
  • fs:模块提供了许多非常实用的函数来访问文件系统并与文件系统进行交互

cheerio是我们的主要库,用来解析HTML,这里简单的介绍一下API

 // HTML模板
<ul id="fruits">
  <li class="apple">Apple</li>
  <li class="orange">Orange</li>
  <li class="pear">Pear</li>
</ul>
​
//解析HTML页面
$ = cheerio.load('<ul id = "fruits">...</ul>');
​
// selectors选择器,这里和JQ一模一样
$('.apple', '#fruits').text() //=> Apple
$('ul .pear').attr('class') //=> pear
$('li[class=orange]').html() //=> <li class = "orange">Orange</li>// atrributes属性操作
$('ul').attr('id') //=> fruits
$('.apple').attr('id', 'favorite').html() //=> <li class = "apple" id = "favorite">Apple</li>//.each( function(index, element) )遍历
var fruits = [];
$('li').each(function(i, elem) {
  fruits[i] = $(this).text();
});
fruits.join(', '); //=> Apple, Orange, Pear//解析和渲染
$.html()
//=>  <ul id = "fruits">
//      <li class = "apple">Apple</li>
//      <li class = "orange">Orange</li>
//      <li class = "pear">Pear</li>
//    </ul>

创建一个简易的被爬取网站

index.html

<body>
  <div>
    <button><a href="http://127.0.0.1:5500/test1.html">跳转至测试页面1</a></button>
    <button><a href="http://127.0.0.1:5500/test2.html">跳转至测试页面2</a></button>
    <button><a href="http://127.0.0.1:5500/test3.html">跳转至测试页面3</a></button>
    <button><a href="http://127.0.0.1:5500/test4.html">跳转至测试页面4</a></button>
    <button><a href="http://127.0.0.1:5500/test5.html">跳转至测试页面4</a></button>
  </div>
</body>

test1.html

<body>
  <h1>第一张</h1>
  <img src="http://127.0.0.1:5500/image/bg01.jpg" />
</body>

test2.html

<body>
  <h1>第二张</h1>
  <img src="http://127.0.0.1:5500/image/bg02.jpg" />
</body>

test3.html

<body>
  <h1>第三张</h1>
  <img src="http://127.0.0.1:5500/image/bg03.jpg" />
</body>

被扒取的页面需要运行在服务器中,不然不能通过axios发起网络请求获取

我这里通过Live Server将页面运行到本地服务器,端口为为:5500

效果图:

Snipaste_2022-05-10_16-31-57.png

点击第一个按钮 跳转页面如下: Snipaste_2022-05-10_16-32-35.png

准备爬取目标网页

我们爬取前,需要了解网页结构,知道自己需要爬取什么。

  • 分析页面结构。我们需要扒取目标网页的图片

    • 通过网络请求,访问页面,并解析HTML
    • 找到a标签中的href属性,获取属性内容,内容为另一个URL地址。
    • 继续通过网络请求,访问页面,解析HTML
    • 找到img标签,获取到src中的内容。
    • 创建一个写入流,开通文件读写通道pipe,将文件写入本地文件夹。
  • 代码:

    • 请求解析index页面

        let res = await axios.get('http://127.0.0.1:5500/index.html');
        let html = res.data;
        let $ = cheerio.load(html);
      
    • 找到a标签中href属性。通过each遍历

        $('a').each(async (index, element) => {
          $(element).attr('href')  // 成功获取所有a标签中href属性
        })
      
    • 继续解析请求url

        $('a').each(async (index, element) => {
          let res = await axios.get($(element).attr('href'));
          let $html = res.data
          let $$ = cheerio.load($html);//成功解析请求test1.html页面结构
        })
      
    • 找到img标签,获取src内容,将文件写入本地

          const $img = await axios.get($$('img').attr('src'), {
            responseType: 'stream'
          });
          const ws = fs.createWriteStream(`./image/${index}.jpg`);//将index作为图片名称
          $img.data.pipe(ws);
      
    • 在本地创建image,执行代码,成功获取到图片

Snipaste_2022-05-10_16-47-31.png

Snipaste_2022-05-10_16-47-43.png

  • 完整代码

    const fs = require("fs");
    const cheerio = require("cheerio");
    const axios = require("axios");
    (async function() {
      let res = await axios.get("http://127.0.0.1:5500/index.html");
      let html = res.data;
      let $ = cheerio.load(html);
      $("a").each(async (index, element) => {
        setTimeout(() => {
          var a = (b = 1);
          let res = await axios.get($(element).attr("href"));
          let $html = res.data;
          let $$ = cheerio.load($html);
          const $img = await axios.get($$("img").attr("src"), {responseType: "stream"});
          const ws = fs.createWriteStream(`./image/${index}.jpg`);
          $img.data.pipe(ws);
      console.log(b);
    ​
        }, 1000);
      });
    })();
    

总结

这是我做的一个简单的爬虫,核心代码只用了18行。其实方法是非常简单的,只需要分析好HTML结构,代码中修改为需要被爬取的属性,就能精准的获取想要的数据。当然,这只是个小案例,功能并不完善,如果要真正爬网页的话,至少应该加个sleep(),给它增加爬取时间间隔,或者ip代理请求,不然就...。