시험시간표 검색 API
중앙대학교 시험 시간표를 검색하는 공개 API다. 인증이 없어 사람도 ChatGPT 같은 AI도 바로 호출할 수 있다. 검색 문법은 웹 검색 페이지(/cau/exam)와 같은 파서를 서버에서 실행하므로 결과가 항상 같다.
- 지원 학교:
cau(중앙대학교) — 모든 경로가/cau/…접두사를 쓴다. - 기본 URL:
https://univmcp.com - 요청·응답은 JSON(UTF-8),
GET/HEAD만 지원한다. - CORS:
Access-Control-Allow-Origin: *— 브라우저에서 직접 호출해도 된다. - 기계용 스펙:
/api/v1/cau/exam/openapi.json
엔드포인트
/api/v1/cau/exam/search시험 일정 검색/api/v1/cau/exam/exams보유한 시험 목록과 최신 시험 확인/api/v1/cau/exam/schedules검색 페이지용 전체 행(원문·슬러그 포함)/api/v1/cau/exam/openapi.jsonOpenAPI 3.1 스펙Accept 협상
사람이 보는 페이지 URL은 같은 URL에서 Accept 헤더로 협상한다.
| Accept | 응답 |
|---|---|
text/html (기본) | SSR HTML 페이지 |
application/json | 같은 자원의 JSON |
머신 클라이언트는 협상 대신 /api/v1/cau/exam/* 경로를 쓰면 항상 JSON이다.
HTML 페이지 구조 (AI·검색엔진용)
API 호출이 어려운 AI·검색 도구는 서버에서 렌더링한 HTML을 그대로 읽고 인용할 수 있다. 사람과 AI가 같은 URL을 쓰며 인증은 없다. 검색 페이지는 q·term·exam_type 쿼리를 받는다.
| 경로 | 용도 |
|---|---|
/cau/exam | 검색창 |
/cau/exam?q=…&term=…&exam_type=… | 과목 검색 결과 |
/cau/exam/2026-2 | 학기 허브(중간·기말 목록) |
/cau/exam/2026-2/midterm | 학기·시험별 전체 목록(페이지네이션) |
/cau/exam/2026-2/midterm/{slug} | 개별 과목 시험 정보(색인 제외, 링크 진입용) |
과목 상세 페이지는 시험 일시·시간·고사실·담당교수·원본 공고를 담는다. 검색·목록·허브 페이지는 검색엔진 색인 대상이고, 상세 페이지는 noindex라서 검색 결과에서 링크로 들어간다. 프로그래밍 방식 조회에는 JSON API와 OpenAPI 명세를 쓴다.
https://univmcp.com/cau/exam?q=인간행동&term=2026-2&exam_type=midterm
검색 문법
- 공백·쉼표로 나눈 토큰을 AND로 검사한다:
다빈치스포츠 2분반 월요일. - 검색 대상은 과목명·분반·강의시간(요일)·교수·과목코드다.
- 분반 표기 변형을 흡수한다:
2분반=02분반=분반2=2. - 교시는 붙여 써도 매칭된다:
월456=월4,5,6. - 한글은 자모·초성 부분일치를 지원한다:
ㄷㅂㅊ→ 다빈치스포츠.
GET /api/v1/cau/exam/search
| 파라미터 | 필수 | 형식 | 설명 |
|---|---|---|---|
q | O | 1~100자 | 검색어. 공백·쉼표 구분 AND, 자모/초성 부분일치, 분반·교시 표기 변형을 흡수한다. |
term | X | 2026-1 · 2026-2 · 2026-S · 2026-W | 학기. “2026년도 1학기” 같은 한글 표기도 인식한다. |
exam_type | X | midterm · final | 시험 종류. |
limit | X | 1~200 (기본 200) | 최대 반환 건수. 전체 일치는 total, 잘리면 truncated=true. |
term·exam_type을 생략하면 보유한 최신 시험 하나를 검색하고 scope.defaulted가 true다.
curl 'https://univmcp.com/api/v1/cau/exam/search?q=다빈치스포츠%202분반'
{
"query": "다빈치스포츠 2분반",
"scope": {"term": "2026-1", "exam_type": "midterm", "defaulted": true},
"count": 1,
"total": 1,
"truncated": false,
"results": [
{
"term": "2026-1", "exam_type": "midterm",
"course_code": null, "course_name": "다빈치스포츠",
"section": "02", "lecture_time": "월1,2,3",
"instructor": "정우영", "exam_method": "과제물대체",
"exam_date": null, "start_time": null, "end_time": null,
"building": null, "rooms": null, "note": null,
"document_id": "2026-1/midterm/ge/5c92de…",
"notice_url": "https://ge.cau.ac.kr/board_notice_view.php?no=1571&page=1",
"matched_fields": ["course_name", "section"]
}
]
}
document_id는 /download?id=에 그대로 쓸 수 있고, lecture_time은 교시로 통일된 표기다(월1,2,3). 시험 일시가 미정이면 exam_date 등이 null이다.
에러
| 상태 | error | 원인 |
|---|---|---|
| 400 | INVALID_QUERY | q 누락·공백뿐·100자 초과 |
| 400 | INVALID_PARAM | term · exam_type · limit 형식 오류 |
| 405 | METHOD_NOT_ALLOWED | GET/HEAD가 아닌 요청 |
| 404 | NOT_FOUND | 없는 경로·없는 슬러그 |
| 429 | RATE_LIMITED | 요청 한도 초과 — Retry-After 초만큼 대기 |
| 500 | INTERNAL | 서버 오류 |
스팸 방지와 쿼터
- 응답 캐시(Cloudflare Workers Cache): 같은 요청은 캐시에서 바로 나가고, 동시 요청도 Worker는 한 번만 실행한다.
- IP당 요청 한도: API 분당 60회, 페이지 분당 300회. 초과 시
429와Retry-After. - 입력 검증:
q1~100자,limit1~200, 검색 응답 최대 200건.
데이터는 한국시간 09:00·21:00 크롤과 수동 /sync로 갱신된다. 응답 캐시는 이번 크롤이 실제로 데이터를 바꿨을 때만 무효화하고, 바뀐 게 없으면 살아 있는 캐시를 그대로 둔다.
ChatGPT 연결
GPT Actions의 스키마 URL을 https://univmcp.com/api/v1/cau/exam/openapi.json로 지정하면 인증 없이 바로 쓸 수 있다. searchExams로 검색하고, 최신 시험이 궁금하면 listExams를 호출한다.