package parser import ( "fmt" "net/http" "strings" "schedule_converter/client" "schedule_converter/config" "github.com/PuerkitoBio/goquery" ) type ExamType string const ( ExamTypeFinal ExamType = "final" ExamTypeMidterm ExamType = "midterm" ExamTypeMakeup ExamType = "makeup" ) type ExamEntry struct { Course string Date string Time string Week string Weekday string Type ExamType } func examTypeToCode(t ExamType) string { switch t { case ExamTypeMidterm: return "02" case ExamTypeMakeup: return "03" default: return "01" } } func FetchExams(httpClient *http.Client, examType ExamType) ([]ExamEntry, error) { examURL := config.BaseURL + "/kscx/queryKsForXs" fmt.Printf("[考试] 正在获取考试时间数据 (%s)...\n", examType) data := fmt.Sprintf("xnxq=&kssjd=%s", examTypeToCode(examType)) req, err := http.NewRequest("POST", examURL, strings.NewReader(data)) if err != nil { return nil, err } req.Header = client.GetHeadersWithContentType("application/x-www-form-urlencoded") resp, err := httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() html, err := decodeResponseBody(resp) if err != nil { return nil, err } exams, err := ParseExamTimeHTML(html, examType) if err != nil { return nil, err } fmt.Printf("[考试] 共获取 %d 条考试记录 (%s)\n", len(exams), examType) return exams, nil } func FetchAllExams(httpClient *http.Client) ([]ExamEntry, error) { var allExams []ExamEntry for _, et := range []ExamType{ExamTypeFinal, ExamTypeMidterm, ExamTypeMakeup} { exams, err := FetchExams(httpClient, et) if err != nil { fmt.Printf("[考试] 获取%s考试失败: %v\n", et, err) continue } allExams = append(allExams, exams...) } return allExams, nil } func ParseExamTimeHTML(html string, examType ExamType) ([]ExamEntry, error) { doc, err := goquery.NewDocumentFromReader(strings.NewReader(html)) if err != nil { return nil, err } var exams []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 := 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 }