Skip to content

Commit

Permalink
feat(the-camp): trainUnitEduSeq, traineeMgrSeq 뽑을 수 있도록 기능 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
WhiteKiwi committed Mar 5, 2022
1 parent 1be0984 commit c54f0b2
Show file tree
Hide file tree
Showing 25 changed files with 4,953 additions and 12 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# .env
.env

# compiled output
/lib
/node_modules
Expand Down
7 changes: 0 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@ async function main() {
생년월일: '2001-01-01',
입영일: '2022-02-14',
전화번호: '01012341234',

// 아래 값들은 현재 직접 뽑아야 함
// TODO: 사이트에서 긁어오게 작업하기
생년월일Code: '08IyuIy6/tXS/vveGiNc+Q==', // birth
입영부대TypeCode: '0000140001', // trainUnitTypeCd
입영부대EduId: '14030', // trainUnitEduSeq
훈련병Id: '', // traineeMgrSeq
},
{
작성자: '장지훈',
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
transform: {
'^.+\\.(t|j)s$': 'ts-jest',
},
setupFiles: ['dotenv/config'],
collectCoverageFrom: ['**/*.(t|j)s', '!**/index.ts'],
coveragePathIgnorePatterns: ['<rootDir>/index.ts'],
moduleNameMapper: {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@kiwi-lib/eslint-config": "^1",
"@types/jest": "^27.4.1",
"@types/node": "^17.0.21",
"dotenv": "^16.0.0",
"jest": "^27.5.1",
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
Expand Down
25 changes: 25 additions & 0 deletions src/core/string/extractInnerText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export function extractInnerText(
target: string,
lefts: string[],
right: string,
): string {
let beforeStartIdx = -1;
let startIdx = -1;
for (const left of lefts) {
startIdx = target.indexOf(left, beforeStartIdx);

if (startIdx < 0) {
break;
}

startIdx += left.length;
beforeStartIdx = startIdx;
}

const endIdx = target.indexOf(right, startIdx);
if (startIdx < 0 || endIdx < 0) {
return '';
}

return target.substring(startIdx, endIdx);
}
24 changes: 24 additions & 0 deletions src/core/string/extractInnerTexts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export function extractInnerTexts(
target: string,
left: string,
right: string,
): string[] {
const extractedTexts = [];
let offset = 0;

while (target.includes(left) && target.includes(right)) {
const startIdx = target.indexOf(left, offset);
const endIdx = target.indexOf(right, startIdx);

if (startIdx === -1 || endIdx === -1) {
break;
}

const extractedText = target.substring(startIdx + left.length, endIdx);

extractedTexts.push(extractedText);
offset = endIdx + right.length;
}

return extractedTexts;
}
2 changes: 2 additions & 0 deletions src/core/string/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './extractInnerText';
export * from './extractInnerTexts';
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { loginRequester } from '../login';
import { fetchSoldiersRequester } from './fetch-soldiers.requester';

describe.skip('FetchSoldiersRequester e2e', () => {
it('성공', async () => {
const session = await loginRequester.request({
id: '',
password: '',
});
await fetchSoldiersRequester.request(session);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { TheCampSession } from '@common/types';
import axios, { AxiosRequestConfig } from 'axios';

import { FetchSoldierRawInfo, parseSoldiers } from './parse-soldiers';

export class FetchSoldiersRequester {
constructor(private readonly parse = parseSoldiers) {}

async request(session: TheCampSession): Promise<FetchSoldierRawInfo[]> {
const response = await axios.get(
'https://www.thecamp.or.kr/eduUnitCafe/viewEduUnitCafeMain.do',
this.createOptions(session),
);

return this.parse(response);
}

private createOptions(session: TheCampSession): AxiosRequestConfig {
return {
headers: {
Accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.70 Whale/3.13.131.27 Safari/537.36',
Host: 'www.thecamp.or.kr',
Origin: 'https://www.thecamp.or.kr',
Referer: 'https://www.thecamp.or.kr/eduUnitCafe/viewEduUnitCafeMain.do',
'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="98", "Whale";v="3"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Dest': 'empty',
Cookie: session.cookies
.map(({ key, value }) => `${key}=${value}`)
.join('; '),
},
};
}
}

export const fetchSoldiersRequester = new FetchSoldiersRequester();
2 changes: 2 additions & 0 deletions src/services/the-camp/requesters/fetch-soldiers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './fetch-soldiers.requester';
export { FetchSoldierRawInfo as FetchSoldierRawInfo } from './parse-soldiers';
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { readFileSync } from 'fs';
import { join } from 'path';

import { parseSoldiers } from './parse-soldiers';

describe('parseSoldiers', () => {
it('성공', () => {
const data = readFileSync(join(__dirname, 'test/성공.txt'), 'utf-8');

expect(parseSoldiers({ data } as any)).toEqual([
{
입영부대Code: '20020191700',
입영부대EduId: '6506',
군인Code: '6142000',
입영일: '20210302',
생년월일: '20010928',
이름: '김민석',
},
{
입영부대Code: '20121190200',
입영부대EduId: '6611',
군인Code: '3051000',
입영일: '20210329',
생년월일: '20010822',
이름: '이예건',
},
{
입영부대Code: '20220280600',
입영부대EduId: '6629',
군인Code: '2050000',
입영일: '20210406',
생년월일: '20010814',
이름: '이지원',
},
{
입영부대Code: '20020191700',
입영부대EduId: '6698',
군인Code: '6142000',
입영일: '20210426',
생년월일: '20010405',
이름: '김민수',
},
{
입영부대Code: '20220280100',
입영부대EduId: '12117',
군인Code: '2031000',
입영일: '20220125',
생년월일: '20011020',
이름: '김명훈',
},
{
입영부대Code: '20020191700',
입영부대EduId: '14030',
군인Code: '6142000',
입영일: '20220214',
생년월일: '20011126',
이름: '이상택',
},
]);
});
});
47 changes: 47 additions & 0 deletions src/services/the-camp/requesters/fetch-soldiers/parse-soldiers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { extractInnerTexts } from '@core/string';
import { AxiosResponse } from 'axios';

export interface FetchSoldierRawInfo {
입영부대Code: string; // trainUnitCd
입영부대EduId: string; // trainUnitEduSeq
군인Code: string; // unitCd
입영일: string; // enterDate
생년월일: string; // birthDay
이름: string; // name
}

export function parseSoldiers({
data,
}: AxiosResponse<string>): FetchSoldierRawInfo[] {
const fnCafeCreateCheckLines = extractInnerTexts(
data,
'javascript:fn_cafeMainLink2(',
'보고싶은군인',
);
return fnCafeCreateCheckLines.map(parseSoldier);
}

// fnLine: fn_cafeCreateCheck(...)
function parseSoldier(fnLine: string): FetchSoldierRawInfo {
const [fn_cafeMainLink2, fn_findArmyArrngmtResult] = fnLine.split(
'javascript:fn_findArmyArrngmtResult(',
);
const [입영부대Code, 입영부대EduId] = fn_cafeMainLink2
.split(');')[0]
.replaceAll("'", '')
.split(',');

const [군인Code, 입영일, 생년월일, 이름] = fn_findArmyArrngmtResult
.split(');')[0]
.replaceAll("'", '')
.split(',');

return {
입영부대Code,
입영부대EduId,
군인Code,
입영일: 입영일.replaceAll('.', ''),
생년월일,
이름,
};
}
Loading

0 comments on commit c54f0b2

Please sign in to comment.