用typescript開發爬蟲過程實踐

azumia發表於2019-02-27

最近剛學typescript,想著能用來做點什麼,順便也練練手,加之最近也有個想法,前提是需要解決資料來源的問題,所以嘗試一下能不能用ts來寫一個爬蟲,然後存到資料庫裡面為我所用,下面就是我的實踐過程

配置開發環境

全域性安裝typescript

npm install -g typescript 
複製程式碼

建立專案資料夾

mkdir ts-spider
複製程式碼

進入該資料夾以後初始化專案

npm init -y
複製程式碼

下面要安裝一下專案中用到的模組

  • axios (網路請求)
  • cheerio (提供jQuery Selector的解析能力)
  • mysql (資料庫互動)
npm i --save axios cheerio mysql
複製程式碼

相應的,要安裝一下對應的型別宣告模組

npm i -s @types/axios --save  
npm i -s @types/cheerio --save 
npm i -s @types/mysql --save 
複製程式碼

其實axios已經自帶型別宣告,所以不安裝也是可以的

下面安裝一下專案內的typescript(必須走這一步)

npm i --save typescript 
複製程式碼

用vscode開啟專案,在根目錄下新建一個tsconfig.json檔案,加入一下配置項

{ 
    "compilerOptions": { 
        "target": "ES6", 
        "module": "commonjs", 
        "noEmitOnError": true, 
        "noImplicitAny": true, 
        "experimentalDecorators": true, 
        "sourceMap": false, 
     // "sourceRoot": "./", 
        "outDir": "./out" 
    }, 
    "exclude": [ 
        "node_modules" 
    ] 
}  
複製程式碼

到這裡我們的環境搭建算基本完成了,下面我們來測試下

開發環境測試

在專案根目錄下建立一個api.ts檔案,寫入以下程式碼

import axios from `axios`
 
/**網路請求 */
export const remote_get = function(url: string) { 
  const promise = new Promise(function (resolve, reject) { 
    axios.get(url).then((res: any) => {
        resolve(res.data);
    }, (err: any) => {
        reject(err);
    });
  });
  return promise;
}
複製程式碼

建立一個app.ts檔案,寫入以下程式碼

import { remote_get } from `./api`

const go = async () => { 
    let res = await remote_get(`http://www.baidu.com/`); 
    console.log(`獲取到的資料為: ${res}`);
} 
go();
複製程式碼

執行一下命令

tsc
複製程式碼

我們發現專案根目錄想多了一個/out資料夾,裡面是轉換後的js檔案

我們執行一下

node out/app
複製程式碼

輸出類似這樣,就代表我們的爬蟲已經爬到了這個網頁,環境測試已經通過了!接下來我們嘗試一下抓取其中的資料

用typescript開發爬蟲過程實踐

分析網頁並抓取資料

我們將app.ts重構一下,引入cheerio,開始抓取我們需要的資料,當然了,這次我們換一下目標,我們抓取一下豆瓣上面的的資料

前面也提到了cheerio提供了jQuery Selector的解析能力,關於它的具體用法,可以點選這裡檢視

import { remote_get } from `./api`
import * as cheerio from `cheerio`

const go = async () => { 
  const res: any = await remote_get(`https://www.douban.com/group/szsh/discussion?start=0`);
  // 載入網頁
  const $ = cheerio.load(res);
  let urls: string[] = [];
  let titles: string[] = [];
  // 獲取網頁中的資料,分別寫到兩個陣列裡面
  $(`.olt`).find(`tr`).find(`.title`).find(`a`).each((index, element) => { 
      titles.push($(element).attr(`title`).trim()); 
      urls.push($(element).attr(`href`).trim()); 
  })
  // 列印陣列
  console.log(titles, urls);
} 
go(); 
複製程式碼

這段程式碼是獲取豆瓣上小組話題和對應的連結,然後寫入陣列裡面,分別列印出來。我們跑一下程式碼,看看輸出

用typescript開發爬蟲過程實踐

可以看到已經獲取到我們想要的資料了。接下來我們嘗試把這些資料寫入到資料庫裡面

將資料寫入資料庫

開始的時候其實是想把資料寫到MongoDB裡面,但是考慮到自己對這個還不太熟,和自己手頭的體驗版伺服器那一點點可憐的空間,最後還是放棄了,還是決定先嚐試寫到mysql資料庫裡面

我們先本地安裝一個mysql資料庫,安裝過程就不詳細說了,安裝完後在本地資料庫中新建一個表

用typescript開發爬蟲過程實踐

在專案根目錄下新增util.ts檔案,寫入一下程式碼

import * as mysql from `mysql`

/* 延時函式 */
export function sleep(msec: number) {
  return new Promise<void>(resolve => setTimeout(resolve, msec));
}

/**
 * 封裝一個資料庫連線的方法
 * @param {string} sql SQL語句
 * @param arg SQL語句插入語句的資料
 * @param callback SQL語句的回撥
 */
export function db(sql: string, arg: any, callback?: any) {
  // 1.建立連線
  const config = mysql.createConnection({
      host: `localhost`, // 資料庫地址
      user: `root`, // 資料庫名
      password: ``, // 資料庫密碼
      port: 3306, // 埠號
      database: `zhufang` // 使用資料庫名字
  });
  // 2.開始連線資料庫
  config.connect();
  // 3.封裝對資料庫的增刪改查操作
  config.query(sql, arg, (err:any, data:any) => {
      callback(err, data);
  });
  // 4.關閉資料庫
  config.end();
}
複製程式碼

以上我們已經封裝好了一個資料庫連線的方法,其中包含了資料庫的配置資訊,下面我們修改app.ts檔案,引入我們封裝好的db模組,並寫入資料的操作程式碼

import { remote_get } from `./api`
import * as cheerio from `cheerio`
import { sleep, db } from `./util`

const go = async () => { 
  const res: any = await remote_get(`https://www.douban.com/group/szsh/discussion?start=0`);
  // 載入網頁
  const $ = cheerio.load(res);
  let urls: string[] = [];
  let titles: string[] = [];
  // 獲取網頁中的資料,分別寫到兩個陣列裡面
  $(`.olt`).find(`tr`).find(`.title`).find(`a`).each((index, element) => { 
      titles.push($(element).attr(`title`).trim()); 
      urls.push($(element).attr(`href`).trim()); 
  })
  // 列印陣列
  console.log(titles, urls);
  // 往資料庫裡面寫入資料
  titles.map((item, index) => {
    db(`insert into info_list(title,url) values(?,?)`, [item, urls[index]], (err: any, data: any) => {
        if(data){
          console.log(`提交資料成功!!`)
        }
        if (err) {
            console.log(`提交資料失敗`)
        }
    })
  })
} 
go(); 
複製程式碼

這裡我們往資料庫中插入title陣列和urls陣列的資料。跑一下程式碼,看了輸出沒有問題,我們看下資料庫

用typescript開發爬蟲過程實踐

資料已經寫入了!到這裡我們的這次實踐就告一段落

下面考慮的是爬取資料過快的延時機制,和如何分頁獲取資料,如何獲取爬到的連結對應的詳細資訊,功能模組化等等,這裡就不細說了

參考文件

https://cloud.tencent.com/info/d0dd52a4a2b1f90055afe4fac4dcd76b.html
https://hpdell.github.io/%E7%88%AC%E8%99%AB/crawler-cheerio-ts/

相關文章