Skip to content

Commit

Permalink
Merge pull request #102 from GDSC-PKNU-21-22/feat/#101
Browse files Browse the repository at this point in the history
Feat/#101: 웨일비 데이터 크롤링 추가
  • Loading branch information
pp449 authored Sep 18, 2023
2 parents 4b23259 + a5f466e commit 580b5f2
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 2 deletions.
11 changes: 10 additions & 1 deletion src/apis/notice/controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getNotices, getSchoolNotices } from '@apis/notice/service';
import { getNotices, getSchoolNotices, getWhalebe } from '@apis/notice/service';
import express, { Request, Response } from 'express';

const router = express.Router();
Expand All @@ -17,4 +17,13 @@ router.get('/', async (req: Request, res: Response) => {
}
});

router.get('/whalebe', async (req: Request, res: Response) => {
try {
const whalebeData = await getWhalebe();
res.json(whalebeData);
} catch (err) {
res.json();
}
});

export default router;
12 changes: 12 additions & 0 deletions src/apis/notice/service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { WhalebeData } from '@crawling/whalebeCrawling';
import db from '@db/index';
import { Notice } from 'src/@types/college';
import notificationToSlack from 'src/hooks/notificateToSlack';

interface SeparateNoti {
고정: Notice[];
Expand Down Expand Up @@ -42,3 +44,13 @@ export const getSchoolNotices = async (): Promise<SeparateNoti> => {
};
return notices;
};

export const getWhalebe = async (): Promise<WhalebeData[]> => {
const query = 'SELECT * FROM 웨일비;';
return new Promise<WhalebeData[]>((resolve) => {
db.query(query, (err, res) => {
if (err) notificationToSlack('웨일비 조회 실패');
resolve(res as WhalebeData[]);
});
});
};
39 changes: 39 additions & 0 deletions src/crawling/whalebeCrawling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import axios from 'axios';
import * as cheerio from 'cheerio';

export interface WhalebeData {
title: string;
date: string;
imgUrl: string;
}

export const whalebeCrawling = async (): Promise<WhalebeData[]> => {
const hostname = 'https://whalebe.pknu.ac.kr';
const whalebeLink = hostname + '/main';
const whalebeData: WhalebeData[] = [];

const response = await axios.get(whalebeLink);
const $ = cheerio.load(response.data);

const programs = $('ul.px-0').find('li');
if (programs.length < 1) return;

programs.each((_, element) => {
const imgUrl = hostname + $(element).find('img').attr('src');
const title = $(element).find('.card-title').text();
const date = $(element)
.find('.app_date')
.find('.col-12')
.first()
.text()
.split('~')[1]
.trim();
const tmpData = {
title,
date,
imgUrl,
};
whalebeData.push(tmpData);
});
return whalebeData;
};
18 changes: 18 additions & 0 deletions src/db/data/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
noticeCrawling,
noticeListCrawling,
} from '@crawling/noticeCrawling';
import { whalebeCrawling } from '@crawling/whalebeCrawling';
import { RowDataPacket } from 'mysql2';
import { College, Notice } from 'src/@types/college';
import db from 'src/db';
Expand Down Expand Up @@ -205,3 +206,20 @@ export const saveSchoolNoticeToDB = async (): Promise<void> => {

await Promise.all(savePromises);
};

export const saveWhalebeToDB = async (): Promise<void> => {
const query = 'INSERT INTO 웨일비 (title, date, imgUrl) VALUES (?, ?, ?)';
const whalebeDatas = await whalebeCrawling();

const promises = whalebeDatas.map((data) => {
const values = [data.title, data.date, data.imgUrl];

return new Promise<void>((resolve) => {
db.query(query, values, () => {
resolve();
});
});
});

Promise.all(promises);
};
18 changes: 18 additions & 0 deletions src/db/table/createTables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,26 @@ const createSchoolNoticeTable = () => {
}
};

const createWhalebeDataTable = () => {
const createTableQuery = `CREATE TABLE 웨일비 (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL UNIQUE,
date VARCHAR(255) NOT NULL,
imgUrl VARCHAR(255) NOT NULL
);`;

db.query(createTableQuery, (error) => {
if (error) {
console.log('웨일비 DB 생성 실패', error);
return;
}
console.log('웨일비 테이블 생성 성공!');
});
};

const createAllTables = (college: College[]) => {
createDepartmentTable();
createWhalebeDataTable();
createGraduationTable();
createSchoolNoticeTable();
createNoticeTable(college);
Expand Down
7 changes: 6 additions & 1 deletion src/hooks/cronNoticeCrawling.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { pushNotification } from '@apis/subscribe/service';
import { saveNoticeToDB, saveSchoolNoticeToDB } from '@db/data/handler';
import {
saveNoticeToDB,
saveSchoolNoticeToDB,
saveWhalebeToDB,
} from '@db/data/handler';
import cron from 'node-cron';
import notificationToSlack from 'src/hooks/notificateToSlack';

Expand All @@ -16,6 +20,7 @@ cron.schedule('0 3 * * *', async () => {
const majors = await saveNoticeToDB();
await saveNoticeToDB();
await saveSchoolNoticeToDB();
await saveWhalebeToDB();
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1; // 월은 0부터 시작하므로 1을 더해줍니다.
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/startCrawlingData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
saveDepartmentToDB,
saveNoticeToDB,
saveSchoolNoticeToDB,
saveWhalebeToDB,
} from '@db/data/handler';
import db from '@db/index';
import createNoticeTable from '@db/table/createTables';
Expand All @@ -22,6 +23,7 @@ export const initialCrawling = () => {
await saveDepartmentToDB(collegeList);
await saveGraduationRequirementToDB();
await saveSchoolNoticeToDB();
await saveWhalebeToDB();
await saveNoticeToDB();
}
});
Expand Down
26 changes: 26 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import noticeRouter from '@apis/notice/controller';
import subscriptionRouter from '@apis/subscribe/controller';
import suggestionRouter from '@apis/suggestion/controller';
import env from '@config';
import { saveWhalebeToDB } from '@db/data/handler';
import db from '@db/index';
import { corsOptions } from '@middlewares/cors';
import errorHandler from '@middlewares/error-handler';
import cors from 'cors';
Expand Down Expand Up @@ -39,3 +41,27 @@ app.listen(env.SERVER_PORT, () => {
});

webpush();

const forDeployedServer = () => {
// 이 함수는 현재 배포되어있는 서버를 위해 사용되는 로직이며 최초 서버에 배포되는 1회만 실행되도록 하기위한 함수에요
// 그렇기에 아래에 작성된 코드들은 배포서버에 배포되면 다음 배포전 수정해주세요!!

// 웨일비 관련 테이블 생성 후 데이터 삽입
const createTableQuery = `CREATE TABLE 웨일비 (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL UNIQUE,
date VARCHAR(255) NOT NULL,
imgUrl VARCHAR(255) NOT NULL
);`;

db.query(createTableQuery, (error) => {
if (error) {
console.log('웨일비 DB 생성 실패', error);
return;
}
console.log('웨일비 테이블 생성 성공!');
saveWhalebeToDB();
});
};

forDeployedServer();

0 comments on commit 580b5f2

Please sign in to comment.