一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - 基于TypeScript從0到1搭建一款爬蟲工具

基于TypeScript從0到1搭建一款爬蟲工具

2021-01-28 01:08 前端歷劫之路maomin9761 JavaScript

今天,我們將使用TypeScript這門語言搭建一款爬蟲工具。目標網址是什么呢?我們去上網一搜,經過幾番排查之后,我們選定了這一個網站。

基于TypeScript從0到1搭建一款爬蟲工具

前言

今天,我們將使用TS這門語言搭建一款爬蟲工具。目標網址是什么呢?我們去上網一搜,經過幾番排查之后,我們選定了這一個網站。

https://www.hanju.run/

一個視頻網站,我們的目的主要是爬取這個網站上視頻的播放鏈接。下面,我們就開始進行第一步。

第一步

俗話說,萬事開頭難。不過對于這個項目而言,恰恰相反。你需要做以下幾個事情:

1.我們需要創建一個項目文件夾

2.鍵入命令,初始化項目

  1. npm init -y 

3.局部安裝typescript

  1. npm install typescript -D 

4.接著鍵入命令,生成ts配置文件

  1. tsc --init 

5.局部安裝ts-node,用于命令行輸出命令

  1. npm install -D ts-node 

6.在項目文件夾中創建一個src文件夾

然后我們在src文件夾中創建一個crawler.ts文件。

7.在package.json文件中修改快捷啟動命令

  1. "scripts": { 
  2.     "dev-t""ts-node ./src/crawler.ts" 
  3.   } 

第二步

接下來,我們將進行實戰操作,也就是上文中crawler.ts文件是我們的主戰場。

我們首先需要引用的這幾個依賴,分別是

  1. import superagent from "superagent"
  2. import cheerio from "cheerio"
  3. import fs from "fs"
  4. import path from "path"

所以,我們會這樣安裝依賴:

superagent作用是獲取遠程網址html的內容。

  1. npm install superagent 

cheerio作用是可以通過jQ語法獲取頁面節點的內容。

  1. npm install cheerio 

剩余兩個依賴fs,path。它們是node內置依賴,直接引入即可。

我們完成了安裝依賴,但是會發現你安裝的依賴上會有紅色報錯。原因是這樣的,superagent和cheerio內部都是用JS寫的,并不是TS寫的,而我們現在的環境是TS。所以我們需要翻譯一下,我們將這種翻譯文件又稱類型定義文件(以.d.ts為后綴)。我們可以使用以下命令安裝類型定義文件。

  1. npm install -D @types/superagent 

  1. npm install -D @types/cheerio 

接下來,我們就認認真真看源碼了。

1.安裝完兩個依賴后,我們需要創建一個Crawler類,并且將其實例化。

  1. import superagent from "superagent"
  2. import cheerio from "cheerio"
  3. import fs from "fs"
  4. import path from "path"
  5.  
  6. class Crawler { 
  7.   constructor() { 
  8.      
  9.   } 
  10.  
  11. const crawler = new Crawler(); 

2.我們確定下要爬取的網址,然后賦給一個私有變量。最后我們會封裝一個getRawHtml方法來獲取對應網址的內容。

getRawHtml方法中我們使用了async/await關鍵字,主要用于異步獲取頁面內容,然后返回值。

  1. import superagent from "superagent"
  2. import cheerio from "cheerio"
  3. import fs from "fs"
  4. import path from "path"
  5.  
  6. class Crawler { 
  7.   private url = "https://www.hanju.run/play/39221-4-0.html"
  8.  
  9.   async getRawHtml() { 
  10.     const result = await superagent.get(this.url); 
  11.     return result.text; 
  12.   } 
  13.  
  14.   async initSpiderProcess() { 
  15.     const html = await this.getRawHtml(); 
  16.   } 
  17.  
  18.   constructor() { 
  19.     this.initSpiderProcess(); 
  20.   } 
  21.  
  22. const crawler = new Crawler(); 

3.使用cheerio依賴內置的方法獲取對應的節點內容。

我們通過getRawHtml方法異步獲取網頁的內容,然后我們傳給getJsonInfo這個方法,注意是string類型。我們這里通過cheerio.load(html)這條語句處理,就可以通過jQ語法來獲取對應的節點內容。我們獲取到了網頁中視頻的標題以及鏈接,通過鍵值對的方式添加到一個對象中。注:我們在這里定義了一個接口,定義鍵值對的類型。

  1. import superagent from "superagent"
  2. import cheerio from "cheerio"
  3. import fs from "fs"
  4. import path from "path"
  5.  
  6. interface Info { 
  7.   name: string; 
  8.   url: string; 
  9.  
  10. class Crawler { 
  11.   private url = "https://www.hanju.run/play/39221-4-0.html"
  12.  
  13.   getJsonInfo(html: string) { 
  14.     const $ = cheerio.load(html); 
  15.     const info: Info[] = []; 
  16.     const scpt: string = String($(".play>script:nth-child(1)").html()); 
  17.     const url = unescape( 
  18.       scpt.split(";")[3].split("(")[1].split(")")[0].replace(/\"/g, "") 
  19.     ); 
  20.     const name: string = String($("title").html()); 
  21.     info.push({ 
  22.       name
  23.       url, 
  24.     }); 
  25.     const result = { 
  26.       time: new Date().getTime(), 
  27.       data: info, 
  28.     }; 
  29.     return result; 
  30.   } 
  31.  
  32.   async getRawHtml() { 
  33.     const result = await superagent.get(this.url); 
  34.     return result.text; 
  35.   } 
  36.  
  37.   async initSpiderProcess() { 
  38.     const html = await this.getRawHtml(); 
  39.     const info = this.getJsonInfo(html); 
  40.   } 
  41.  
  42.   constructor() { 
  43.     this.initSpiderProcess(); 
  44.   } 
  45.  
  46. const crawler = new Crawler(); 

4.我們首先要在項目根目錄下創建一個data文件夾。然后我們將獲取的內容我們存入文件夾內的url.json文件(文件自動生成)中。

我們將其封裝成getJsonContent方法,在這里我們使用了path.resolve來獲取文件的路徑。fs.readFileSync來讀取文件內容,fs.writeFileSync來將內容寫入文件。注:我們分別定義了兩個接口objJson與InfoResult。

  1. import superagent from "superagent"
  2. import cheerio from "cheerio"
  3. import fs from "fs"
  4. import path from "path"
  5.  
  6. interface objJson { 
  7.   [propName: number]: Info[]; 
  8.  
  9. interface Info { 
  10.   name: string; 
  11.   url: string; 
  12.  
  13. interface InfoResult { 
  14.   time: number; 
  15.   data: Info[]; 
  16.  
  17. class Crawler { 
  18.   private url = "https://www.hanju.run/play/39221-4-0.html"
  19.  
  20.   getJsonInfo(html: string) { 
  21.     const $ = cheerio.load(html); 
  22.     const info: Info[] = []; 
  23.     const scpt: string = String($(".play>script:nth-child(1)").html()); 
  24.     const url = unescape( 
  25.       scpt.split(";")[3].split("(")[1].split(")")[0].replace(/\"/g, "") 
  26.     ); 
  27.     const name: string = String($("title").html()); 
  28.     info.push({ 
  29.       name
  30.       url, 
  31.     }); 
  32.     const result = { 
  33.       time: new Date().getTime(), 
  34.       data: info, 
  35.     }; 
  36.     return result; 
  37.   } 
  38.  
  39.   async getRawHtml() { 
  40.     const result = await superagent.get(this.url); 
  41.     return result.text; 
  42.   } 
  43.  
  44.   getJsonContent(info: InfoResult) { 
  45.     const filePath = path.resolve(__dirname, "../data/url.json"); 
  46.     let fileContent: objJson = {}; 
  47.     if (fs.existsSync(filePath)) { 
  48.       fileContent = JSON.parse(fs.readFileSync(filePath, "utf-8")); 
  49.     } 
  50.     fileContent[info.time] = info.data; 
  51.     fs.writeFileSync(filePath, JSON.stringify(fileContent)); 
  52.   } 
  53.  
  54.   async initSpiderProcess() { 
  55.     const html = await this.getRawHtml(); 
  56.     const info = this.getJsonInfo(html); 
  57.     this.getJsonContent(info); 
  58.   } 
  59.  
  60.   constructor() { 
  61.     this.initSpiderProcess(); 
  62.   } 
  63.  
  64. const crawler = new Crawler(); 

5.運行命令

  1. npm run dev-t 

6.查看生成文件的效果

  1.   "1610738046569": [ 
  2.     { 
  3.       "name""《復仇者聯盟4:終局之戰》HD1080P中字m3u8在線觀看-韓劇網"
  4.       "url""https://wuxian.xueyou-kuyun.com/20190728/16820_302c7858/index.m3u8" 
  5.     } 
  6.   ], 
  7.   "1610738872042": [ 
  8.     { 
  9.       "name""《鋼鐵俠2》HD高清m3u8在線觀看-韓劇網"
  10.       "url""https://www.yxlmbbs.com:65/20190920/54uIR9hI/index.m3u8" 
  11.     } 
  12.   ], 
  13.   "1610739069969": [ 
  14.     { 
  15.       "name""《鋼鐵俠2》中英特效m3u8在線觀看-韓劇網"
  16.       "url""https://tv.youkutv.cc/2019/11/12/mjkHyHycfh0LyS4r/playlist.m3u8" 
  17.     } 
  18.   ] 

準結語

到這里真的結束了嗎?

不!不!不!

真的沒有結束。

我們會看到上面一坨代碼,真的很臭~

我們將分別使用組合模式與單例模式將其優化。

優化一:組合模式

組合模式(Composite Pattern),又叫部分整體模式,是用于把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及整體層次。這種類型的設計模式屬于結構型模式,它創建了對象組的樹形結構。

這種模式創建了一個包含自己對象組的類。該類提供了修改相同對象組的方式。

簡言之,就是可以像處理簡單元素一樣來處理復雜元素。

首先,我們在src文件夾下創建一個combination文件夾,然后在其文件夾下分別在創建兩個文件crawler.ts和urlAnalyzer.ts。

crawler.ts

crawler.ts文件的作用主要是處理獲取頁面內容以及存入文件內。

  1. import superagent from "superagent"
  2. import fs from "fs"
  3. import path from "path"
  4. import UrlAnalyzer from "./urlAnalyzer.ts"
  5.  
  6. export interface Analyzer { 
  7.   analyze: (html: string, filePath: string) => string; 
  8.  
  9. class Crowller { 
  10.   private filePath = path.resolve(__dirname, "../../data/url.json"); 
  11.  
  12.   async getRawHtml() { 
  13.     const result = await superagent.get(this.url); 
  14.     return result.text; 
  15.   } 
  16.  
  17.   writeFile(content: string) { 
  18.     fs.writeFileSync(this.filePath, content); 
  19.   } 
  20.  
  21.   async initSpiderProcess() { 
  22.     const html = await this.getRawHtml(); 
  23.     const fileContent = this.analyzer.analyze(html, this.filePath); 
  24.     this.writeFile(fileContent); 
  25.   } 
  26.  
  27.   constructor(private analyzer: Analyzer, private url: string) { 
  28.     this.initSpiderProcess(); 
  29.   } 
  30. const url = "https://www.hanju.run/play/39257-1-1.html"
  31.  
  32. const analyzer = new UrlAnalyzer(); 
  33. new Crowller(analyzer, url); 

urlAnalyzer.ts

urlAnalyzer.ts文件的作用主要是處理獲取頁面節點內容的具體邏輯。

  1. import cheerio from "cheerio"
  2. import fs from "fs"
  3. import { Analyzer } from "./crawler.ts"
  4.  
  5. interface objJson { 
  6.   [propName: number]: Info[]; 
  7. interface InfoResult { 
  8.   time: number; 
  9.   data: Info[]; 
  10. interface Info { 
  11.   name: string; 
  12.   url: string; 
  13.  
  14. export default class UrlAnalyzer implements Analyzer { 
  15.   private getJsonInfo(html: string) { 
  16.     const $ = cheerio.load(html); 
  17.     const info: Info[] = []; 
  18.     const scpt: string = String($(".play>script:nth-child(1)").html()); 
  19.     const url = unescape( 
  20.       scpt.split(";")[3].split("(")[1].split(")")[0].replace(/\"/g, "") 
  21.     ); 
  22.     const name: string = String($("title").html()); 
  23.     info.push({ 
  24.       name
  25.       url, 
  26.     }); 
  27.     const result = { 
  28.       time: new Date().getTime(), 
  29.       data: info, 
  30.     }; 
  31.     return result; 
  32.   } 
  33.  
  34.   private getJsonContent(info: InfoResult, filePath: string) { 
  35.     let fileContent: objJson = {}; 
  36.     if (fs.existsSync(filePath)) { 
  37.       fileContent = JSON.parse(fs.readFileSync(filePath, "utf-8")); 
  38.     } 
  39.     fileContent[info.time] = info.data; 
  40.     return fileContent; 
  41.   } 
  42.  
  43.   public analyze(html: string, filePath: string) { 
  44.     const info = this.getJsonInfo(html); 
  45.     console.log(info); 
  46.     const fileContent = this.getJsonContent(info, filePath); 
  47.     return JSON.stringify(fileContent); 
  48.   } 

可以在package.json文件中定義快捷啟動命令。

  1. "scripts": { 
  2.   "dev-c""ts-node ./src/combination/crawler.ts" 
  3. }, 

然后使用npm run dev-c啟動即可。

優化二:單例模式

**單例模式(Singleton Pattern)**是 Java 中最簡單的設計模式之一。這種類型的設計模式屬于創建型模式,它提供了一種創建對象的最佳方式。

這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

應用實例:

  • 1、一個班級只有一個班主任。
  • 2、Windows 是多進程多線程的,在操作一個文件的時候,就不可避免地出現多個進程或線程同時操作一個文件的現象,所以所有文件的處理必須通過唯一的實例來進行。
  • 3、一些設備管理器常常設計為單例模式,比如一個電腦有兩臺打印機,在輸出的時候就要處理不能兩臺打印機打印同一個文件。

同樣,我們在src文件夾下創建一個singleton文件夾,然后在其文件夾下分別在創建兩個文件crawler1.ts和urlAnalyzer.ts。

這兩個文件的作用與上文同樣,只不過代碼書寫不一樣。

crawler1.ts

  1. import superagent from "superagent"
  2. import fs from "fs"
  3. import path from "path"
  4. import UrlAnalyzer from "./urlAnalyzer.ts"
  5.  
  6. export interface Analyzer { 
  7.   analyze: (html: string, filePath: string) => string; 
  8.  
  9. class Crowller { 
  10.   private filePath = path.resolve(__dirname, "../../data/url.json"); 
  11.  
  12.   async getRawHtml() { 
  13.     const result = await superagent.get(this.url); 
  14.     return result.text; 
  15.   } 
  16.  
  17.   private writeFile(content: string) { 
  18.     fs.writeFileSync(this.filePath, content); 
  19.   } 
  20.  
  21.   private async initSpiderProcess() { 
  22.     const html = await this.getRawHtml(); 
  23.     const fileContent = this.analyzer.analyze(html, this.filePath); 
  24.     this.writeFile(JSON.stringify(fileContent)); 
  25.   } 
  26.  
  27.   constructor(private analyzer: Analyzer, private url: string) { 
  28.     this.initSpiderProcess(); 
  29.   } 
  30. const url = "https://www.hanju.run/play/39257-1-1.html"
  31.  
  32. const analyzer = UrlAnalyzer.getInstance(); 
  33. new Crowller(analyzer, url); 

urlAnalyzer.ts

  1. import cheerio from "cheerio"
  2. import fs from "fs"
  3. import { Analyzer } from "./crawler1.ts"
  4.  
  5. interface objJson { 
  6.   [propName: number]: Info[]; 
  7. interface InfoResult { 
  8.   time: number; 
  9.   data: Info[]; 
  10. interface Info { 
  11.   name: string; 
  12.   url: string; 
  13. export default class UrlAnalyzer implements Analyzer { 
  14.   static instance: UrlAnalyzer; 
  15.  
  16.   static getInstance() { 
  17.     if (!UrlAnalyzer.instance) { 
  18.       UrlAnalyzer.instance = new UrlAnalyzer(); 
  19.     } 
  20.     return UrlAnalyzer.instance; 
  21.   } 
  22.  
  23.   private getJsonInfo(html: string) { 
  24.     const $ = cheerio.load(html); 
  25.     const info: Info[] = []; 
  26.     const scpt: string = String($(".play>script:nth-child(1)").html()); 
  27.     const url = unescape( 
  28.       scpt.split(";")[3].split("(")[1].split(")")[0].replace(/\"/g, "") 
  29.     ); 
  30.     const name: string = String($("title").html()); 
  31.     info.push({ 
  32.       name
  33.       url, 
  34.     }); 
  35.     const result = { 
  36.       time: new Date().getTime(), 
  37.       data: info, 
  38.     }; 
  39.     return result; 
  40.   } 
  41.  
  42.   private getJsonContent(info: InfoResult, filePath: string) { 
  43.     let fileContent: objJson = {}; 
  44.     if (fs.existsSync(filePath)) { 
  45.       fileContent = JSON.parse(fs.readFileSync(filePath, "utf-8")); 
  46.     } 
  47.     fileContent[info.time] = info.data; 
  48.     return fileContent; 
  49.   } 
  50.  
  51.   public analyze(html: string, filePath: string) { 
  52.      const info = this.getJsonInfo(html); 
  53.      console.log(info); 
  54.     const fileContent = this.getJsonContent(info, filePath); 
  55.     return JSON.stringify(fileContent); 
  56.   } 
  57.  
  58.   private constructor() {} 

可以在package.json文件中定義快捷啟動命令。

  1. "scripts": { 
  2.     "dev-s""ts-node ./src/singleton/crawler1.ts"
  3.  }, 

然后使用npm run dev-s啟動即可。

結語

這下真的結束了,謝謝閱讀。希望可以幫到你。

完整源碼地址:

https://github.com/maomincoding/TsCrawler

原文地址:https://mp.weixin.qq.com/s/Q8AJsDqrQAy9NQdv6Ykg3w

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 午夜香蕉成视频人网站高清版 | 天堂男人在线 | 亚洲精品一区二区三区在线观看 | 99精品偷自拍 | 日本高清视频一区二区 | ckinese中国男同gay男男 | 亚洲 欧美 在线观看 | 探花 在线 | 北岛玲亚洲一区在线观看 | 羞羞私人影院可以直接免费观影吗 | 日本道高清 | 俺去俺来也www色官网免费的 | 欧美亚洲另类综合 | 192.168.191| 国产免费专区 | 我被男人下药添得好爽 | 秋霞黄色网 | 国产成人免费高清激情明星 | ai换脸杨颖被啪在线观看 | 高清在线观看免费入口 | 91久久99热青草国产 | 亚洲另类第一页 | 日产2021免费一二三四区 | 日韩毛片免费在线观看 | 国产免费一区二区三区免费视频 | 好大好硬好深好爽想要之黄蓉 | tube69xxxxhd日本| 高h文3p双龙 | 四虎成人国产精品视频 | 69av美女| 国产成人精品午夜在线播放 | 思久久| 午夜DY888国产精品影院 | 成人欧美一区二区三区白人 | 香蕉视频在线观看网站 | 午夜神器老司机高清无码 | 好大好硬好深好爽想要之黄蓉 | 国产精品久久久久久久久 | 国产123区| 久久久精品免费视频 | 精品亚洲永久免费精品 |