Files
hufs-notice-crawler/README.md
nkey ca460453af
All checks were successful
hufs-notice-crawler-cicd / build_push_deploy (push) Successful in 8m35s
Feat: [main] hufs-notice-crawler CI/CD까지 구현 완료
2026-03-17 17:18:16 +09:00

5.3 KiB

HUFS 컴퓨터공학부 공지 크롤러

HUFS 컴퓨터공학부 사이트의 다음 게시판을 크롤링하는 FastAPI 백엔드입니다.

  • 공지사항
  • 자료실
  • 취업정보

n8nPOST /api/v1/crawl을 주기적으로 호출하면, 서버는 게시판을 다시 확인하고 PostgreSQL에 저장된 기존 글과 비교해 새 글만 반환합니다.

문서

주요 기능

  • 공지사항, 자료실, 취업정보 게시판 크롤링
  • 게시판별 article_id 기준 신규 글 판별
  • 제목, 작성자, 게시일, 본문 텍스트, 첨부파일 링크 정리
  • 사용자에게 보이는 subview.do?enc=... 링크 반환
  • 최초 1회 실행 시 bootstrap mode로 기존 글 알림 폭주 방지
  • new_posts_count == 0일 때만 latest_posts_by_board 제공
  • Docker Hub 이미지 배포 및 docker compose pull 운영 지원

동작 방식

  1. n8nPOST /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

서버 상태 확인용입니다.

응답:

{ "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 이미지 이름

주요 파일

참고

  • 신규 여부 판단 기준은 게시판별 article_id입니다.
  • 반환 링크는 artclView.do가 아니라 실제 사용자용 subview.do?enc=... 형식입니다.
  • HTML 구조가 바뀌면 app/crawler.py의 selector 조정이 필요할 수 있습니다.