ca460453af5cd7b4419d7ca40fab7c1bdd1e367f
All checks were successful
hufs-notice-crawler-cicd / build_push_deploy (push) Successful in 8m35s
HUFS 컴퓨터공학부 공지 크롤러
HUFS 컴퓨터공학부 사이트의 다음 게시판을 크롤링하는 FastAPI 백엔드입니다.
- 공지사항
- 자료실
- 취업정보
n8n이 POST /api/v1/crawl을 주기적으로 호출하면, 서버는 게시판을 다시 확인하고 PostgreSQL에 저장된 기존 글과 비교해 새 글만 반환합니다.
문서
- 서비스 설명:
README.md - 운영/배포:
README.operation.md - 테스트:
README.test.md - n8n 연동:
README.n8n.md
주요 기능
- 공지사항, 자료실, 취업정보 게시판 크롤링
- 게시판별
article_id기준 신규 글 판별 - 제목, 작성자, 게시일, 본문 텍스트, 첨부파일 링크 정리
- 사용자에게 보이는
subview.do?enc=...링크 반환 - 최초 1회 실행 시
bootstrap mode로 기존 글 알림 폭주 방지 new_posts_count == 0일 때만latest_posts_by_board제공- Docker Hub 이미지 배포 및
docker compose pull운영 지원
동작 방식
n8n이POST /api/v1/crawl요청을 보냅니다.- 서버가 세 게시판 목록 페이지를 크롤링합니다.
- 각 게시글의
article_id를 DB와 비교합니다. - DB에 없는 글만 상세 페이지를 추가 크롤링합니다.
- 정리된 데이터를 응답으로 반환하고 DB에 저장합니다.
- 다음 실행부터는 이미 저장된 글은 제외됩니다.
bootstrap mode
최초 실행 시 예전 글 알림이 한꺼번에 나가는 것을 막기 위해 bootstrap mode를 사용합니다.
판단 기준:
scraped_posts테이블이 비어 있으면bootstrap_mode = true- 저장된 글이 하나라도 있으면
bootstrap_mode = false
동작:
bootstrap_mode = true- 기존 글을 DB에 저장만 함
new_posts_count = 0new_posts = []
- 이후부터는 일반 신규 감지 모드로 동작
즉, 첫 실행에서 기존 공지가 한꺼번에 Discord/Slack으로 쏟아지는 문제를 막습니다.
API
GET /health
서버 상태 확인용입니다.
응답:
{ "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일 때만 포함- 별도 추가 요청이 아니라 실제 크롤링 결과를 재사용
응답 예시:
{
"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를 준비합니다.
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- FastAPI 엔드포인트
app/service.py- 크롤링 실행, bootstrap, DB 저장 로직
app/crawler.py- 게시판 목록/상세 크롤러
app/models.py- SQLAlchemy 모델
sql/schema.sql- PostgreSQL 스키마
docker-compose.yml- Docker Hub 이미지 pull 기반 실행
참고
- 신규 여부 판단 기준은 게시판별
article_id입니다. - 반환 링크는
artclView.do가 아니라 실제 사용자용subview.do?enc=...형식입니다. - HTML 구조가 바뀌면
app/crawler.py의 selector 조정이 필요할 수 있습니다.
Description
Languages
Python
98.6%
Dockerfile
1.4%