最近剛學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/