入坑TypeScript(一):使用TypeScript写nod

2020-04-17  本文已影响0人  Martain

入坑TypeScript(一):使用TypeScript写node脚本爬取小说

一、为何入坑TypeScript?

​ 虽然我不是专业的前端工程师,但是对于TypeScript早有所耳闻,但是对于javascript众多的框架以及第三方库来说,我并没有特别在意(或许这就是专业和业余的差距吧~),我的前端技术栈目前仅仅是 vue.js 以及会点 nodejs 而已,最近的遭遇让我不得不去接触下TypeScript,当然,都跑来写博客了,那要不是非常痛恨ts,要不是就是对ts喜出望外,显然,我就是后者。我如此坚定的入坑原因以下两点:

于是乎,我认真的逛了逛官网~

二、我对TypeScript的第一印象

​ 从简单的阅读了官网以及找朋友讨论了下之后,我对TypeScript是满怀期待的,吸引我的是它的严谨(变量要显示地指定类型)、支持Class、支持枚举、支持接口。开始我是喜欢Javascript这个动态类型的编程的,觉得没有那么繁杂的定义,不用掌握很多东西都能出一点成果,写了一段时间之后也开始厌恶它比较难维护,相对于现在的我来说,我更注重的是代码的质量,设计的质量,而不是仅仅是为了完成某个功能而已。

三、开始学吧

​ 官网文档简单的看了下,对于现在的我来说,着实是没有耐心慢慢地、细细的学,还是喜欢项目驱动地来边做边学,敲好一个朋友在做他的毕业设计,是一个阅读的app,之前有听他提到过用的是某网站的接口来获取书本资源,于是乎,我觉得来写个小爬虫(虽然我知道可能不足以称之为爬虫~)把书本资源保存到本地吧。

3.1 前期准备

3.2 分析接口

​ github上那位大佬提供了三个接口:

3.3 定义实体

​ 根据接口的分析,我们可以抽象出4个实体类,他们是书本实体Book 、书本详情BookDetail、章节Chepter、章节详情ChepterDetail,这里就很好的用上了TypeScript的class的知识点

​ 这里我们封装了三个方法,获取书本列表、获取书本详情、获取章节详情。调用关系就像分析接口的步骤那样,这里我们只是加入了对请求数据的保存功能。

四、完整代码

import axios from 'axios'
import * as fs from 'fs'
const request = axios.create({
    timeout: 1000 * 60
})
const fileSavePath = "book/"
fs.mkdir(fileSavePath, err => {
    console.log(err);
})
enum api {
    books = "https://novel.juhe.im/books",
    bookDetail = "https://novel.juhe.im/book/",
    chapterDetail = "https://novel.juhe.im/book/"
}
class Book {
    _id: string;
    title: string;
    author: string;
    shortIntro: string;
    cover: string;
    cat: string;
    followerCount: string;
    zt: string;
    updated: string;
    lastchapter: string; 
}

class BookDetail {
    _id: string;
    title: string;
    author: string;
    shortIntro: string;
    cover: string;
    cat: string;
    followerCount: string;
    zt: string;
    updated: string;
    lastchapter: string;
    wordCount: string;
    retentionRatio: string;
    chapters: Chapter[]
}
class Chapter {
    cid: string;
    wordCount: string;
    title: string;
}

class ChapterDetail{
    title:string;
    content:string;
    bookDetail:BookDetail;
}
async function getBookDetail(book: Book) {
    try {
        let res = await request.get(api.bookDetail + book._id)
        let bookDetail: BookDetail = res.data
        let bookId = bookDetail._id
        let title = bookDetail.title
        let chapters = bookDetail.chapters
        let savePath = fileSavePath + title
        let mkResult = fs.mkdirSync(savePath, 0o777)
        console.log("\t创建目录:" + savePath + "==>" + mkResult);
        fs.writeFileSync(savePath + "/" + title + ".json", JSON.stringify(bookDetail))
        // chapters.forEach(chapter=>{
        //     getChapterDetail(title,bookId,chapter.cid)
        // })
        for (const chapter of chapters) {
            await getChapterDetail(title, bookId, chapter.cid)
        }
        return res
    } catch (error) {
        console.log("getBooDetail errpr", book, error);
    }
}
async function getChapterDetail(bookTitle: string, bookId: string, chapterId: string) {
    try {
        let res = await request.get(api.chapterDetail + bookId + "/" + chapterId)
        let chapterDetail:ChapterDetail = res.data 
        let csavePath = fileSavePath + bookTitle + "/" + chapterDetail.title + chapterId
        csavePath = csavePath.replace(' ', '')
        let _mkResult = fs.mkdirSync(csavePath, 0o777)
        console.log("\t\t创建目录:" + csavePath + "==>" + _mkResult);
        let fileName = csavePath + "/" + chapterDetail.title + "_" + chapterId + ".json";
        fileName = fileName.replace(' ', '')
        fs.writeFileSync(fileName, JSON.stringify(chapterDetail))
        console.log("\t\t\t保存文件:" + fileName);
        return res
    } catch (error) {
        console.log("getChapterDetail error", bookTitle, chapterId, error);
    }
} 
async function getBooks() {
    try {
        let res = await request.get(api.books, {})
        let books: Book[] = res.data.books
        for (const book of books) {
            await getBookDetail(book)
        }
        return res
    } catch (error) {

    }
} 
let res = getBooks()
console.log(res); 

五、总结

5.1 学了如何使用TypeScript编写node脚本

​ 因为之前用过nodejs+js来写脚本,所以使用ts来代替js其实也就是照搬照套,区别除了语法之外,就是执行流程上需要使用tsc xxx.ts 编译成xxx.js 之后,再执行node xxx.js,才能正常运行。关于如何使用第三方库的问题,我也是直接使用npm去安装第三方库的。如果要使用node 里面的httpfs 这类的包的话,需要执行npm install @types/node -D 安装相关的库,至于axios的话就直接执行npm install axios 了。

5.2 async与await的基本用法

​ 这两个关键字一般都是配合一起使用的,因为我了解甚少,这里就不给出详细解释以免误人子弟 o(╥﹏╥)o,后面有空了会对这个专门写个文章学习下把,可以先参考阮一峰的教程文章

5.3 forEach是同步的,但是forEach里面加await是无法同步执行的

​ 这个问题也是我在使用await和async的时候遇到的,因为当时对这个不是很了解,我想要的效果是获取书本列表之后,一本一本的去爬,就是爬第一本的时候,要等这本书的所有章节都爬完了再开始爬第二本书,也是这里才遇到这些问题,也是靠大神指点的,后来将forEach 改成了for of

5.4 下一步计划

也许我永远也追不上他们的脚步,但是我可以超越昨天的自己。

上一篇 下一篇

猜你喜欢

热点阅读