最近刚学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/