当前位置:   article > 正文

用typescript开发爬虫过程实践

typescript 爬虫

最近刚学typescript,想着能用来做点什么,顺便也练练手,加之最近也有个想法,前提是需要解决数据来源的问题,所以尝试一下能不能用ts来写一个爬虫,然后存到数据库里面为我所用,下面就是我的实践过程

配置开发环境

全局安装typescript

  1. npm install -g typescript
  2. 复制代码

创建项目文件夹

  1. mkdir ts-spider
  2. 复制代码

进入该文件夹以后初始化项目

  1. npm init -y
  2. 复制代码

下面要安装一下项目中用到的模块

  • axios (网络请求)
  • cheerio (提供jQuery Selector的解析能力)
  • mysql (数据库交互)
  1. npm i --save axios cheerio mysql
  2. 复制代码

相应的,要安装一下对应的类型声明模块

  1. npm i -s @types/axios --save
  2. npm i -s @types/cheerio --save
  3. npm i -s @types/mysql --save
  4. 复制代码

其实axios已经自带类型声明,所以不安装也是可以的

下面安装一下项目内的typescript(必须走这一步)

  1. npm i --save typescript
  2. 复制代码

用vscode打开项目,在根目录下新建一个tsconfig.json文件,加入一下配置项

  1. {
  2. "compilerOptions": {
  3. "target": "ES6",
  4. "module": "commonjs",
  5. "noEmitOnError": true,
  6. "noImplicitAny": true,
  7. "experimentalDecorators": true,
  8. "sourceMap": false,
  9. // "sourceRoot": "./",
  10. "outDir": "./out"
  11. },
  12. "exclude": [
  13. "node_modules"
  14. ]
  15. }
  16. 复制代码

到这里我们的环境搭建算基本完成了,下面我们来测试下

开发环境测试

在项目根目录下创建一个api.ts文件,写入以下代码

  1. import axios from 'axios'
  2. /**网络请求 */
  3. export const remote_get = function(url: string) {
  4. const promise = new Promise(function (resolve, reject) {
  5. axios.get(url).then((res: any) => {
  6. resolve(res.data);
  7. }, (err: any) => {
  8. reject(err);
  9. });
  10. });
  11. return promise;
  12. }
  13. 复制代码

创建一个app.ts文件,写入以下代码

  1. import { remote_get } from './api'
  2. const go = async () => {
  3. let res = await remote_get('http://www.baidu.com/');
  4. console.log(`获取到的数据为: ${res}`);
  5. }
  6. go();
  7. 复制代码

执行一下命令

  1. tsc
  2. 复制代码

我们发现项目根目录想多了一个/out文件夹,里面是转换后的js文件

我们执行一下

  1. node out/app
  2. 复制代码

输出类似这样,就代表我们的爬虫已经爬到了这个网页,环境测试已经通过了!接下来我们尝试一下抓取其中的数据

分析网页并抓取数据

我们将app.ts重构一下,引入cheerio,开始抓取我们需要的数据,当然了,这次我们换一下目标,我们抓取一下豆瓣上面的的数据

前面也提到了cheerio提供了jQuery Selector的解析能力,关于它的具体用法,可以点击这里查看

  1. import { remote_get } from './api'
  2. import * as cheerio from 'cheerio'
  3. const go = async () => {
  4. const res: any = await remote_get('https://www.douban.com/group/szsh/discussion?start=0');
  5. // 加载网页
  6. const $ = cheerio.load(res);
  7. let urls: string[] = [];
  8. let titles: string[] = [];
  9. // 获取网页中的数据,分别写到两个数组里面
  10. $('.olt').find('tr').find('.title').find('a').each((index, element) => {
  11. titles.push($(element).attr('title').trim());
  12. urls.push($(element).attr('href').trim());
  13. })
  14. // 打印数组
  15. console.log(titles, urls);
  16. }
  17. go();
  18. 复制代码

这段代码是获取豆瓣上小组话题和对应的链接,然后写入数组里面,分别打印出来。我们跑一下代码,看看输出

可以看到已经获取到我们想要的数据了。接下来我们尝试把这些数据写入到数据库里面

将数据写入数据库

开始的时候其实是想把数据写到MongoDB里面,但是考虑到自己对这个还不太熟,和自己手头的体验版服务器那一点点可怜的空间,最后还是放弃了,还是决定先尝试写到mysql数据库里面

我们先本地安装一个mysql数据库,安装过程就不详细说了,安装完后在本地数据库中新建一个表

在项目根目录下添加util.ts文件,写入一下代码

  1. import * as mysql from 'mysql'
  2. /* 延时函数 */
  3. export function sleep(msec: number) {
  4. return new Promise<void>(resolve => setTimeout(resolve, msec));
  5. }
  6. /**
  7. * 封装一个数据库连接的方法
  8. * @param {string} sql SQL语句
  9. * @param arg SQL语句插入语句的数据
  10. * @param callback SQL语句的回调
  11. */
  12. export function db(sql: string, arg: any, callback?: any) {
  13. // 1.创建连接
  14. const config = mysql.createConnection({
  15. host: 'localhost', // 数据库地址
  16. user: 'root', // 数据库名
  17. password: '', // 数据库密码
  18. port: 3306, // 端口号
  19. database: 'zhufang' // 使用数据库名字
  20. });
  21. // 2.开始连接数据库
  22. config.connect();
  23. // 3.封装对数据库的增删改查操作
  24. config.query(sql, arg, (err:any, data:any) => {
  25. callback(err, data);
  26. });
  27. // 4.关闭数据库
  28. config.end();
  29. }
  30. 复制代码

以上我们已经封装好了一个数据库连接的方法,其中包含了数据库的配置信息,下面我们修改app.ts文件,引入我们封装好的db模块,并写入数据的操作代码

  1. import { remote_get } from './api'
  2. import * as cheerio from 'cheerio'
  3. import { sleep, db } from './util'
  4. const go = async () => {
  5. const res: any = await remote_get('https://www.douban.com/group/szsh/discussion?start=0');
  6. // 加载网页
  7. const $ = cheerio.load(res);
  8. let urls: string[] = [];
  9. let titles: string[] = [];
  10. // 获取网页中的数据,分别写到两个数组里面
  11. $('.olt').find('tr').find('.title').find('a').each((index, element) => {
  12. titles.push($(element).attr('title').trim());
  13. urls.push($(element).attr('href').trim());
  14. })
  15. // 打印数组
  16. console.log(titles, urls);
  17. // 往数据库里面写入数据
  18. titles.map((item, index) => {
  19. db('insert into info_list(title,url) values(?,?)', [item, urls[index]], (err: any, data: any) => {
  20. if(data){
  21. console.log('提交数据成功!!')
  22. }
  23. if (err) {
  24. console.log('提交数据失败')
  25. }
  26. })
  27. })
  28. }
  29. go();
  30. 复制代码

这里我们往数据库中插入title数组和urls数组的数据。跑一下代码,看了输出没有问题,我们看下数据库

数据已经写入了!到这里我们的这次实践就告一段落

下面考虑的是爬取数据过快的延时机制,和如何分页获取数据,如何获取爬到的链接对应的详细信息,功能模块化等等,这里就不细说了

参考文档

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/285800
推荐阅读
相关标签
  

闽ICP备14008679号