最近剛學typescript,想着能用來作點什麼,順便也練練手,加之最近也有個想法,前提是須要解決數據來源的問題,因此嘗試一下能不能用ts來寫一個爬蟲,而後存到數據庫裏面爲我所用,下面就是個人實踐過程html
全局安裝typescriptnode
npm install -g typescript
建立項目文件夾mysql
mkdir ts-spider
進入該文件夾之後初始化項目ios
npm init -y
下面要安裝一下項目中用到的模塊git
npm i --save axios cheerio mysql
相應的,要安裝一下對應的類型聲明模塊github
npm i -s @types/axios --save npm i -s @types/cheerio --save npm i -s @types/mysql --save
其實axios已經自帶類型聲明,因此不安裝也是能夠的sql
下面安裝一下項目內的typescript(必須走這一步)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" ] }
到這裏咱們的環境搭建算基本完成了,下面咱們來測試下npm
在項目根目錄下建立一個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
輸出相似這樣,就表明咱們的爬蟲已經爬到了這個網頁,環境測試已經經過了!接下來咱們嘗試一下抓取其中的數據
咱們將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(); 複製代碼
這段代碼是獲取豆瓣上小組話題和對應的連接,而後寫入數組裏面,分別打印出來。咱們跑一下代碼,看看輸出
能夠看到已經獲取到咱們想要的數據了。接下來咱們嘗試把這些數據寫入到數據庫裏面
開始的時候實際上是想把數據寫到MongoDB裏面,可是考慮到本身對這個還不太熟,和本身手頭的體驗版服務器那一點點可憐的空間,最後仍是放棄了,仍是決定先嚐試寫到mysql數據庫裏面
咱們先本地安裝一個mysql數據庫,安裝過程就不詳細說了,安裝完後在本地數據庫中新建一個表
在項目根目錄下添加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數組的數據。跑一下代碼,看了輸出沒有問題,咱們看下數據庫
數據已經寫入了!到這裏咱們的此次實踐就告一段落
下面考慮的是爬取數據過快的延時機制,和如何分頁獲取數據,如何獲取爬到的連接對應的詳細信息,功能模塊化等等,這裏就不細說了
參考文檔
https://cloud.tencent.com/info/d0dd52a4a2b1f90055afe4fac4dcd76b.html
https://hpdell.github.io/%E7%88%AC%E8%99%AB/crawler-cheerio-ts/