定时自动跑爬虫?js说湿湿碎~

前言

如果只是一次性的爬取数据,那我推荐直接在浏览器里跑js脚本就行,例子可看写爬虫?前端er何必用python

但如果你想定时自动爬取数据,这时js表示依然小case。当然,得用nodejs了,不多说,直接上需求:

需求:每天0点自动爬取获取豆瓣评分电影Top250的详细信息

每天0点获取豆瓣评分电影Top250的以下信息,并存到本地/数据库/..

前置知识

下面涉及一些第三方库,只需要简单了解即可使用,莫慌~

  • 简单nodejs知识
  • cheerio: jquery风格的解析和操作 html/xml 库
  • node-schedule:可实现定时执行任务

nodejs实现

1. 分析页面请求,找到数据来源,分析接口规律

根据上一篇写爬虫?前端er何必用python知道:

依此类推,第几页只是start参数不一样

2. 用代码模拟获取接口数据

nodejs从18.x版本开始支持fetch接口,nodejs.org/en/blog/ann... ,所以用我们熟悉的fetch直接撸:

js 复制代码
fetch("https://movie.douban.com/top250?start=1")
  .then(function (response) {
    return response.text();
  })
  .then((r) => {
    console.log(333, r.slice(0, 1000)); // 用slice截部分用于演示
  });

跑下,没问题

3. 过滤处理提取数据

处理数据就要找到数据规律,这一步是灵魂。简单看下发现每部电影信息都在 li 标签里了,只需把对应文本提取出来即可。

从html里过滤提取数据,用dom api操作是我们熟悉且方便的,不出意外的是,node端也有这个能力,下面通过cheerio 来实现,cheerio库是jquery(链式调用)风格的解析和操作 html/xml 库。简单熟悉下cheerio文档,搜下别人怎么用,直接撸:

js 复制代码
const cheerio = require("cheerio");

// ...
    console.log(333, r.slice(0, 1000)); // 用slice截部分用于演示
    const $ = cheerio.load(r);
    const itemList = $(".item").each((idx, el) => {
      const item = cheerio.load($(el).prop("outerHTML"));
      // 电影详情链接
      const link = item("a").attr("href");
      // 图片链接
      const imageUrl = item("img").attr("src");
      // 影片名字
      const name = item(".title").prop("innerText");
      // 评分
      const rateNum = item(".rating_num").prop("innerText");
      //评价数
      const ratePerson = parseInt(item(".star > span:last-child").text());
      // 概况
      const about = item(".quote")?.prop("innerText");
      // 相关信息
      const desc = item(".bd > p").prop("innerText");
      console.log(1111, { link, imageUrl, name, rateNum, ratePerson, about, desc });
    });
// ...

跑下,没问题

4. 存储/下载/..数据

这里我选择保存为json文件,简单用fs、path写个工具函数:

js 复制代码
const fs = require("fs"); 
const path = require("path");

// ... 
const saveToJson = (filePath, content) => {
  // 自动创建目录
  const dirPath = path.dirname(filePath);
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath, { recursive: true });
  }

  fs.writeFile(filePath, content, function (err) {
    if (err) {
      console.error(err);
    }
    console.log(filePath, "写入成功!");
  });
};

测试下,没问题!

5. 定时自动爬取

下面用node-schedule 来实现定时执行任务,简单写个demo测试下

js 复制代码
const schedule = require("node-schedule");

// 当前时间的秒值为 10 时执行任务,如:2018-7-8 13:25:10
let job = schedule.scheduleJob("10 * * * * *", () => {
  console.log(
    "定时自动执行啦>>>",
    new Date()
      .toLocaleString()
      .replace(", ", "_")
      .replace(/\//g, "_")
      .slice(0, 19)
  );
});

其中时间数值按下表表示

markdown 复制代码
*  *  *  *  *  *
┬  ┬  ┬  ┬  ┬  ┬
│  │  │  │  │  |
│  │  │  │  │  └ 星期几,取值:0 - 7,其中 0 和 7 都表示是周日
│  │  │  │  └─── 月份,取值:1 - 12
│  │  │  └────── 日期,取值:1 - 31
│  │  └───────── 时,取值:0 - 23
│  └──────────── 分,取值:0 - 59
└─────────────── 秒,取值:0 - 59(可选)

跑下,没问题

全部代码

js 复制代码
const cheerio = require("cheerio");
const fs = require("fs");
const path = require("path");
const schedule = require("node-schedule");

const top250 = {};
let currentPage = 1;
const spiderDoubanTop250 = async (url) => {
  await fetch(url)
    .then(function (response) {
      return response.text();
    })
    .then((r) => {
      const $ = cheerio.load(r);
      $(".item").each((idx, el) => {
        const item = cheerio.load($(el).prop("outerHTML"));
        // 电影详情链接
        const link = item("a").attr("href");
        // 图片链接
        const imageUrl = item("img").attr("src");
        // 影片名字
        const name = item(".title").prop("innerText");
        // 评分
        const rateNum = item(".rating_num").prop("innerText");
        //评价数
        const ratePerson = parseInt(item(".star > span:last-child").text());
        // 概况
        const about = item(".quote")?.prop("innerText");
        // 相关信息
        const desc = item(".bd > p").prop("innerText");
        top250[name] = { link, imageUrl, name, rateNum, ratePerson, about, desc };
      });
    });

  // 启动下一页
  if (currentPage <= 10) {
    currentPage++;
    spiderDoubanTop250(
      `https://movie.douban.com/top250?start=${25 * (currentPage - 1)}`
    );
  } else {
    saveToJson(
      `./doupanTop250/${new Date()
        .toLocaleString()
        .replace(", ", "_")
        .replace(/\//g, "_")
        .slice(0, 19)}.json`,
      JSON.stringify(top250)
    );
  }
};

// 每天0:0:0点执行任务
schedule.scheduleJob("0 0 0 * * *", () => {
  spiderDoubanTop250("https://movie.douban.com/top250?start=0");
});

const saveToJson = (filePath, content) => {
  // 自动创建目录
  const dirPath = path.dirname(filePath);
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath, { recursive: true });
  }

  fs.writeFile(filePath, content, function (err) {
    if (err) {
      console.error(err);
    }
    console.log("写入成功!");
  });
};

总结

nodejs版的爬虫和浏览器js版的爬虫思路是一样的,借助fetch、cheerio提供的熟悉的接口,前端程序员可以复用经验,轻松上手nodejs爬虫。

相关推荐
全栈开发圈1 分钟前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫
小白学大数据6 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
ac-er88881 小时前
PHP网络爬虫常见的反爬策略
开发语言·爬虫·php
聪明的墨菲特i4 小时前
Python爬虫学习
爬虫·python·学习
oliveira-time6 小时前
爬虫学习6
爬虫
xiaoxiongip66611 小时前
HTTP 和 HTTPS
网络·爬虫·网络协议·tcp/ip·http·https·ip
兆。13 小时前
掌握 PyQt5:从零开始的桌面应用开发
开发语言·爬虫·python·qt
API快乐传递者19 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
兜里有糖请分享1 天前
Python中序列化/反序列化JSON格式的数据
爬虫·python
亿牛云爬虫专家1 天前
用Puppeteer点击与数据爬取:实现动态网页交互
javascript·爬虫·爬虫代理·puppeteer·数据·代理ip·16yun