Feat: [main] hufs-notice-crawler CI/CD까지 구현 완료
All checks were successful
hufs-notice-crawler-cicd / build_push_deploy (push) Successful in 8m35s
All checks were successful
hufs-notice-crawler-cicd / build_push_deploy (push) Successful in 8m35s
This commit is contained in:
162
README.md
Normal file
162
README.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# HUFS 컴퓨터공학부 공지 크롤러
|
||||
|
||||
`HUFS 컴퓨터공학부` 사이트의 다음 게시판을 크롤링하는 `FastAPI` 백엔드입니다.
|
||||
|
||||
- 공지사항
|
||||
- 자료실
|
||||
- 취업정보
|
||||
|
||||
`n8n`이 `POST /api/v1/crawl`을 주기적으로 호출하면, 서버는 게시판을 다시 확인하고 `PostgreSQL`에 저장된 기존 글과 비교해 새 글만 반환합니다.
|
||||
|
||||
## 문서
|
||||
|
||||
- 서비스 설명: [`README.md`](/C:/Users/USER/Desktop/notice_crawler/README.md)
|
||||
- 운영/배포: [`README.operation.md`](/C:/Users/USER/Desktop/notice_crawler/README.operation.md)
|
||||
- 테스트: [`README.test.md`](/C:/Users/USER/Desktop/notice_crawler/README.test.md)
|
||||
- n8n 연동: [`README.n8n.md`](/C:/Users/USER/Desktop/notice_crawler/README.n8n.md)
|
||||
|
||||
## 주요 기능
|
||||
|
||||
- 공지사항, 자료실, 취업정보 게시판 크롤링
|
||||
- 게시판별 `article_id` 기준 신규 글 판별
|
||||
- 제목, 작성자, 게시일, 본문 텍스트, 첨부파일 링크 정리
|
||||
- 사용자에게 보이는 `subview.do?enc=...` 링크 반환
|
||||
- 최초 1회 실행 시 `bootstrap mode`로 기존 글 알림 폭주 방지
|
||||
- `new_posts_count == 0`일 때만 `latest_posts_by_board` 제공
|
||||
- Docker Hub 이미지 배포 및 `docker compose pull` 운영 지원
|
||||
|
||||
## 동작 방식
|
||||
|
||||
1. `n8n`이 `POST /api/v1/crawl` 요청을 보냅니다.
|
||||
2. 서버가 세 게시판 목록 페이지를 크롤링합니다.
|
||||
3. 각 게시글의 `article_id`를 DB와 비교합니다.
|
||||
4. DB에 없는 글만 상세 페이지를 추가 크롤링합니다.
|
||||
5. 정리된 데이터를 응답으로 반환하고 DB에 저장합니다.
|
||||
6. 다음 실행부터는 이미 저장된 글은 제외됩니다.
|
||||
|
||||
## bootstrap mode
|
||||
|
||||
최초 실행 시 예전 글 알림이 한꺼번에 나가는 것을 막기 위해 `bootstrap mode`를 사용합니다.
|
||||
|
||||
판단 기준:
|
||||
|
||||
- `scraped_posts` 테이블이 비어 있으면 `bootstrap_mode = true`
|
||||
- 저장된 글이 하나라도 있으면 `bootstrap_mode = false`
|
||||
|
||||
동작:
|
||||
|
||||
- `bootstrap_mode = true`
|
||||
- 기존 글을 DB에 저장만 함
|
||||
- `new_posts_count = 0`
|
||||
- `new_posts = []`
|
||||
- 이후부터는 일반 신규 감지 모드로 동작
|
||||
|
||||
즉, 첫 실행에서 기존 공지가 한꺼번에 Discord/Slack으로 쏟아지는 문제를 막습니다.
|
||||
|
||||
## API
|
||||
|
||||
### `GET /health`
|
||||
|
||||
서버 상태 확인용입니다.
|
||||
|
||||
응답:
|
||||
|
||||
```json
|
||||
{ "status": "ok" }
|
||||
```
|
||||
|
||||
### `POST /api/v1/crawl`
|
||||
|
||||
세 게시판을 크롤링해 새 글만 반환합니다.
|
||||
|
||||
응답 필드:
|
||||
|
||||
- `checked_at`: 크롤링 시각
|
||||
- `bootstrap_mode`: bootstrap 실행 여부
|
||||
- `bootstrap_inserted_count`: bootstrap 시 저장된 글 수
|
||||
- `new_posts_count`: 실제 신규 글 수
|
||||
- `new_posts`: 신규 글 목록
|
||||
- `latest_posts_by_board`: 게시판별 최신 글
|
||||
- `new_posts_count == 0`일 때만 포함
|
||||
- 별도 추가 요청이 아니라 실제 크롤링 결과를 재사용
|
||||
|
||||
응답 예시:
|
||||
|
||||
```json
|
||||
{
|
||||
"checked_at": "2026-03-17T00:00:00Z",
|
||||
"bootstrap_mode": false,
|
||||
"bootstrap_inserted_count": 0,
|
||||
"new_posts_count": 1,
|
||||
"new_posts": [
|
||||
{
|
||||
"board_key": "notice",
|
||||
"board_name": "공지사항",
|
||||
"board_id": 1926,
|
||||
"article_id": 249714,
|
||||
"title": "예시 제목",
|
||||
"post_url": "https://computer.hufs.ac.kr/computer/10058/subview.do?enc=...",
|
||||
"author": "computer",
|
||||
"published_at": "2026-03-17T00:00:00",
|
||||
"summary": "본문 요약",
|
||||
"content_text": "정리된 본문 텍스트",
|
||||
"attachments": [
|
||||
{
|
||||
"name": "첨부파일.pdf",
|
||||
"url": "https://computer.hufs.ac.kr/..."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"latest_posts_by_board": []
|
||||
}
|
||||
```
|
||||
|
||||
## 환경 변수
|
||||
|
||||
`.env.example`을 참고해서 `.env`를 준비합니다.
|
||||
|
||||
```env
|
||||
APP_ENV=production
|
||||
DB_USER=postgres
|
||||
DB_PASSWORD=postgres
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=hufs_notice_crawler
|
||||
BASE_URL=https://computer.hufs.ac.kr
|
||||
REQUEST_TIMEOUT_SECONDS=15
|
||||
MAX_PAGES_PER_BOARD=5
|
||||
DOCKER_IMAGE=your-dockerhub-id/hufs-notice-crawler:latest
|
||||
```
|
||||
|
||||
- `APP_ENV`: 실행 환경
|
||||
- `DB_USER`: PostgreSQL 사용자 -> 공통 .env에 있음
|
||||
- `DB_PASSWORD`: PostgreSQL 비밀번호 -> 공통 .env에 있음
|
||||
- `POSTGRES_HOST`: PostgreSQL 호스트
|
||||
- `POSTGRES_PORT`: PostgreSQL 포트
|
||||
- `POSTGRES_DB`: 데이터베이스 이름
|
||||
- `BASE_URL`: 기본 크롤링 대상 사이트
|
||||
- `REQUEST_TIMEOUT_SECONDS`: 외부 요청 타임아웃
|
||||
- `MAX_PAGES_PER_BOARD`: 게시판별 최대 확인 페이지 수
|
||||
- `DOCKER_IMAGE`: Docker Hub 이미지 이름
|
||||
|
||||
## 주요 파일
|
||||
|
||||
- [`app/main.py`](/C:/Users/USER/Desktop/notice_crawler/app/main.py)
|
||||
- FastAPI 엔드포인트
|
||||
- [`app/service.py`](/C:/Users/USER/Desktop/notice_crawler/app/service.py)
|
||||
- 크롤링 실행, bootstrap, DB 저장 로직
|
||||
- [`app/crawler.py`](/C:/Users/USER/Desktop/notice_crawler/app/crawler.py)
|
||||
- 게시판 목록/상세 크롤러
|
||||
- [`app/models.py`](/C:/Users/USER/Desktop/notice_crawler/app/models.py)
|
||||
- SQLAlchemy 모델
|
||||
- [`sql/schema.sql`](/C:/Users/USER/Desktop/notice_crawler/sql/schema.sql)
|
||||
- PostgreSQL 스키마
|
||||
- [`docker-compose.yml`](/C:/Users/USER/Desktop/notice_crawler/docker-compose.yml)
|
||||
- Docker Hub 이미지 pull 기반 실행
|
||||
|
||||
## 참고
|
||||
|
||||
- 신규 여부 판단 기준은 게시판별 `article_id`입니다.
|
||||
- 반환 링크는 `artclView.do`가 아니라 실제 사용자용 `subview.do?enc=...` 형식입니다.
|
||||
- HTML 구조가 바뀌면 [`app/crawler.py`](/C:/Users/USER/Desktop/notice_crawler/app/crawler.py)의 selector 조정이 필요할 수 있습니다.
|
||||
Reference in New Issue
Block a user