node如何命令行摸鱼

186 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

本次开发命令行看小说的工具, 环境的搭建细节可以看之前的活动文章

安装依赖

cheerio

cheerio为服务器特别定制的,快速、灵活、实施的jQuery核心实现.

详情: github.com/cheeriojs/c…

安装

pnpm add cheerio

开发

这次请求的是起点中文网的页面,侵权请联系我删除.

  1. 创建 readBook.ts 文件。

封装请求, 起点web端的页面是服务端渲染的, 所以我们直接请求html, 做相应处理。

import { get } from "https";

/**
 * 发送请求
 * @param url 请求的页面地址
 * @returns 页面html的字符串
 */
function getHttp(url: string): Promise<string> {
  return new Promise((resolve, reject) => {
    get(
      url,
      {
        headers: {
          "Content-type": "text/html",
        },
      },
      (res) => {
        res.setEncoding("utf8");
        let rawData = "";
        // 拼接数据片段
        res.on("data", (d: string) => {
          rawData += d;
        });
        res.on("end", () => {
          resolve(rawData);
        });
      }
    ).on("error", (e) => {
      reject(e);
    });
  });
}

使用cherrio,注入html字符产,可以像jQuery一样操作html, 接下来就不多赘述了,dom的操作就是前端的拿手好戏。 思路是先搜索, 在跳详情, 详情页有章节目录,处理之后根据输入跳转到内容页。

import { load } from "cheerio";
import { echo } from "./echo.js";
import ora from "ora";
import chalk from "chalk";

export async function readBook(options: Record<string, string>) {
  const spinner = ora();
  spinner.start(
    chalk.blue("(温馨提示: 看小说 看正版 !!)正在从起点小说网中查询....")
  );
  const html = await getHttp(`https://www.qidian.com/soushu/${options.n}.html`);
  const querySelect = load(html);
  const bookList = querySelect(
    ".book-img-text li .book-mid-info .book-info-title a"
  )
    .map((_, el) => {
      return {
        name: querySelect(el).text(),
        url: "https:" + el.attribs["href"],
      };
    })
    .toArray();
  spinner.succeed(chalk.blue("获取以下目录"));
  console.log(
    chalk.cyan(
      bookList
        .map((v, i) => {
          return `${i}. ${v.name}`;
        })
        .join("\n")
    )
  );
  const bookindex = Number(
    await echo("获取到以上的近似书籍列表, 请输入要阅读的书籍编号: ")
  );
  spinner.start(chalk.blue("正在获取章节列表....."));
  const chapter = await getHttp(bookList[bookindex].url);
  const chapterHtml = load(chapter);
  const chapterList = chapterHtml(".cf li .book_name a")
    .map((_, el) => {
      return {
        name: chapterHtml(el).text(),
        url: "https:" + el.attribs["href"],
      };
    })
    .toArray();
  spinner.succeed(chalk.green(`共获取${chapterList.length}章`));
  
  let chapterIndex = Number(
    await echo("请输入要阅读的章节(vip章节无法观看): ")
  );
  while(true) {
    console.log(await readDetails(chapterList[chapterIndex - 1].url))
    console.log('\n\n\n\n')
    const isRead = await echo("是否阅读下一张(Y/N): ")
    if(isRead !== 'Y') break
    chapterIndex++
    if(chapterIndex >= chapterList.length) chapterIndex = chapterList.length
  }
}
  1. inde.ts文件中添加book命令。
import { readBook } from "./readBooks.js";

// book
program
  .command("book")
  .description("看书")
  .option('-n [name]', '书名')
  .action(readBook);

测试

image.png