使用Node爬蟲中國所有大學數據(一)

Nest是用於構建高效,可擴展的Node.js服務器端應用程序的框架。它使用漸進式JavaScript,內置並完全支持TypeScript,並結合了OOP(面向對象編程),FP(函數式編程)和FRP(函數響應式編程)。

在底層,Nest默認使用Express這類的健壯的服務端框架,並且你可以選擇自己配置使用Fastify

Nest在這些常見的Node.js框架(Express / Fastify)之上提供了一個抽象級別,但也直接向開發者公開了它們的API。 這使開發人員可以自由使用底層平臺的第三方庫。

這裏就不對Nest進行更多介紹了,你可以在Nest官方文檔瞭解更多信息。畢竟本文的重點是展示如何去爬蟲。

開始你的Nest應用

 npm i -g @nestjs/cli
 nest new project-name

連接MYSQL數據庫

爲了與SQL和NoSQL數據庫集成,Nest提供了@nestjs/typeorm包。 TypeORM其官方文檔稱之爲是可用於TypeScript的最成熟的對象關係映射器(ORM)。由於它是用TypeScript編寫的,因此可以與Nest框架很好地集成。

使用TypeORM和在.Net或者JAVA裏使用任何對象關係映射器並沒有什麼區別,它只是給我們方便的提供諸如find,save,create,remove,update,delete等API,如果你不喜歡,你當然也可以直接使用query傳入SQL語句來操作數據庫。

npm install --save @nestjs/typeorm typeorm mysql

然後在app.module.ts裏:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersModule } from './users/users.module';
import { CollegeModule } from './college/college.module';
import { BachelorPointsModule } from './bachelor-points/backelor.module';
import { MasterPointsModule } from './master-points/master.module';
import { ProvinceModule } from './province-data/province-data.module';
@Module({
 imports: [
   TypeOrmModule.forRoot({
     type:'mysql',
     host:'localhost',
     port:3306,
     username:'root',
     password:'root123456',
     database:'test',
     autoLoadEntities: true,
     synchronize:true
   }),
   UsersModule,CollegeModule,BachelorPointsModule,MasterPointsModule,ProvinceModule
 ],
 controllers: [AppController],
 providers: [AppService],
})
export class AppModule {}

關於這個如果你遇到什麼問題,可以參考我的文章Nest.js初探索之實體映射數據庫的三種方式

爬取所有省份

爲了獲取中國所有大學信息,我們希望可以根據省份查詢。所以,我們先爬取所有省份。

先創建province實體類

import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';

@Entity()
export class Province {

   @PrimaryGeneratedColumn()
   id: number;

   @Column()
   name: string;

   @Column(
       {
           nullable: true
       }
   )
   abbr: string;

   @CreateDateColumn({ comment: '創建時間',type:'datetime' })  // 自動生成列
   created_ts: string

   @UpdateDateColumn({ comment: '更新時間',type:'datetime'})   // 自動生成並自動更新列
   updated_ts: string


}

然後在controller裏面設置Rest API相關信息

import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { Province } from './province.entity';
import { ProvinceService } from './province.service';

@Controller('province')
export class ProvinceController {
    constructor(private readonly provinceService: ProvinceService) {
    }
    @Post('crawler')
    crawlerProvince() {
        return this.provinceService.crawlerProvince();
    }

    @Get()
    list(): Promise<Province[]> {
        return this.provinceService.listProvince();
    }


}

在Service裏進行爬蟲和數據庫操作

主要的爬蟲邏輯在service裏,我們重點看下crawlerProvince方法,使用了Crawler庫來解析和爬蟲。

import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as Crawler from 'crawler';
import { Province } from './province.entity';

@Injectable()
export class ProvinceService {
    constructor(
        @InjectRepository(Province)
        private provinceRepository: Repository<Province>,
    ) {
    }

    listProvince(): Promise<Province[]> {
        return this.provinceRepository.find();
    }
    async crawlerProvince() {
        const a = () => {
            return new Promise((reslove, reject) => {
                var c = new Crawler({
                    maxConnections: 10,
                    callback: (error, res, done) => {
                        if (error) {
                            console.log(error);
                            reject(error)
                        } else {
                            var $ = res.$;
                            let items = [];
                            $('.row').find('.col-md-12').find('.row').find('.col-md-12').find('a').each(async (idx, element) => {
                                if (idx >= 34) { return; }
                                var $element = $(element);
                                let province = {
                                    name: $element.text(),
                                }
                                await this.provinceRepository.save(province);
                                items.push(province);
                            });
                            reslove(items);

                        }
                        done();
                    }
                });
                c.queue(`http://www.52maps.com/china_city.php`);

            })
        };
        return await a();
    }

}

這裏我們使用Crawler爬取頁面信息之後,將每個省份使用this.provinceRepository.save(province)都存儲進數據庫。

module引入

最後我們需要ProvinceModule將controller和service以及實體Province都在module文件裏聲明,最後在app.module不要忘記導入ProvinceModule。

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Province } from './province.entity';
import { ProvinceController } from './province-data.controller';
import { ProvinceService } from './province.service';
@Module({
  imports: [
    TypeOrmModule.forFeature([Province]),
  ],
  controllers:[ProvinceController],
  providers:[ProvinceService]
})
export class ProvinceModule {}

這時數據庫裏就有省份信息了:

使用get請求查看我們爬取的結果:

結果

在前端框架我們就可以讓用戶選擇不同的省份來獲取相應的大學信息。

下一篇文章,我將介紹如何根據不同的省份爬取大學列表,並爬取百度百科的大學詳細信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章