Files
schedule_converter/parser/exam.go
lafay ab37aeb2fc
All checks were successful
Build / build (push) Successful in 2m17s
refactor: introduce service layer and migrate gRPC handlers to use it
Extract business logic from gRPC handlers into a dedicated service package.
Add context support throughout for cancellation and timeouts. Move models to
their own package, remove hardcoded credentials from config, and simplify
parsers to only handle HTML parsing.
2026-06-16 18:33:13 +08:00

71 lines
1.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package parser
import (
"strings"
"schedule_converter/models"
"github.com/PuerkitoBio/goquery"
)
// examTypeToCode 将考试类型映射为教务系统的请求码。
func examTypeToCode(t models.ExamType) string {
switch t {
case models.ExamTypeMidterm:
return "02"
case models.ExamTypeMakeup:
return "03"
default:
return "01"
}
}
// ExamTypeCode 返回考试类型对应的请求码(供 client 层构造请求使用)。
func ExamTypeCode(t models.ExamType) string {
return examTypeToCode(t)
}
// ParseExamHTML 解析考试安排页面 HTML返回考试条目列表。
func ParseExamHTML(html string, examType models.ExamType) ([]models.ExamEntry, error) {
doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
if err != nil {
return nil, err
}
var exams []models.ExamEntry
doc.Find("table.bot_line").Each(func(_ int, table *goquery.Selection) {
rows := table.Find("tr")
if rows.Length() < 2 {
return
}
rows.Each(func(idx int, row *goquery.Selection) {
if idx == 0 {
return
}
cells := row.Find("td")
if cells.Length() < 6 {
return
}
texts := getCellTexts(cells)
exam := models.ExamEntry{
Course: safeGet(texts, 1),
Date: safeGet(texts, 2),
Time: safeGet(texts, 3),
Week: safeGet(texts, 4),
Weekday: safeGet(texts, 5),
Type: examType,
}
if exam.Course != "" && len(exam.Course) >= 2 {
exams = append(exams, exam)
}
})
})
return exams, nil
}