All checks were successful
Build / build (push) Successful in 2m17s
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.
71 lines
1.5 KiB
Go
71 lines
1.5 KiB
Go
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
|
||
}
|