NestJS之13- 爬虫案例

979 阅读1分钟

1. NestJS 进行爬虫

Nest.js 是一个基于 Node.js 和 TypeScript 的后端框架,它内置了许多实用的功能和工具,如模块化架构、依赖注入、路由处理、中间件、拦截器和管道等。

在 Nest.js 中进行爬虫开发时,可以使用第三方库 cheeriopuppeteer 来实现网页信息的获取和解析。

此处我们使用cherrio。

  • cheerio: Cheerio 是一个类似于 jQuery 的库,主要用于在 Node.js 中解析、操作和遍历 HTML 和 XML 文档。
  • axios 网络请求库可以发送http请求

2. 爬取图片

https://www.测试.com/Cosplay/Cosplay10772.html

spider.controller.ts

import { Controller, Get } from '@nestjs/common';
import { SpiderService } from './spider.service';
import axios from 'axios';
import * as cheerio from 'cheerio';

@Controller('spider')
export class SpiderController {
  constructor(private readonly spiderService: SpiderService) {}

  @Get()
  findAll() {
    const baseUrl = 'https://www.111.com';
    axios
      .get('https://www.111.com/Cosplay/Cosplay10772.html')
      .then((res) => {
        // console.log(res.data);
        const $ = cheerio.load(res.data);
        const urls: string[] = [];
        const imgs = $('.article-content p img').each(function (index, item) {
          // console.log(index, item);

          urls.push(baseUrl + $(this).attr('src'));
        });
        console.log(urls);
      });

    return this.spiderService.findAll();
  }
}

获取的结果

image.png

完整版:

最后一页没有下一页,可以通过判断有没有该值,决定请求是否结束。结束拿到所有结果,将其写入服务器。

image.png

path fs 需要通过 * as 进行引入

import { Controller, Get } from '@nestjs/common';
import { SpiderService } from './spider.service';
import axios from 'axios';
import * as cheerio from 'cheerio';
import * as path from 'path';
import * as fs from 'fs';

@Controller('spider')
export class SpiderController {
  constructor(private readonly spiderService: SpiderService) {}

  @Get()
  async findAll() {
    const baseUrl = 'https://www.111.com';
    const next = '下一页';
    let index = 0;
    const urls: string[] = [];

    const getCosplayImage = async () => {
      const res = await axios.get(
        `https://www.111.com/Cosplay/Cosplay10772${
          index !== 0 ? `_${index}` : ''
        }.html`,
      );
      const $ = cheerio.load(res.data);
      // 找出分页的所有dom元素
      const pages = $('.article-content .pagination a')
        .map(function () {
          return $(this).text();
        })
        .toArray();
      if (pages.includes(next)) {
        $('.article-content p img').each(function () {
          console.log($(this).attr('src'));
          urls.push(baseUrl + $(this).attr('src'));
        });
        index++;
        await getCosplayImage();
      }
    };
    await getCosplayImage();
    this.saveImages(urls);

    return this.spiderService.findAll();
  }

// 保存到服务器
  saveImages(urls: string[]) {
    urls.forEach(async (url) => {
      const buffer = await axios
        .get(url, { responseType: 'arraybuffer' })
        .then((res) => res.data);
      const ws = fs.createWriteStream(
        path.join(__dirname, '../images/' + new Date().getTime() + '.jpg'),
      );
      ws.write(buffer);
    });
  }

image.png

image.png