Skip to content

Commit 5fd5ca5

Browse files
authored
fix: find plan (#48)
1 parent cf63480 commit 5fd5ca5

File tree

1 file changed

+120
-9
lines changed

1 file changed

+120
-9
lines changed

plan.go

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,141 @@ func (s *Student) GetCultivatePlan() (string, error) {
3131
if err != nil {
3232
return "", err
3333
}
34+
35+
// 获取初始页面状态
3436
viewStateMap, err := s.getState(constants.CultivatePlanURL)
3537
if err != nil {
3638
return "", err
3739
}
40+
41+
// 尝试精确匹配学院和专业代码
42+
url, err := s.getCultivatePlanWithPreciseMatch(info, viewStateMap)
43+
if err == nil {
44+
return url, nil
45+
}
46+
47+
// 如果精确匹配失败,使用fallback逻辑
48+
return s.getCultivatePlanWithFallback(info, viewStateMap)
49+
}
50+
51+
// 精确匹配学院和专业代码获取培养方案
52+
func (s *Student) getCultivatePlanWithPreciseMatch(info *StudentDetail, viewStateMap map[string]string) (string, error) {
53+
// 获取学院选择页面
54+
initialDoc, err := s.GetWithIdentifier(constants.CultivatePlanURL)
55+
if err != nil {
56+
return "", err
57+
}
58+
59+
// 查找学院代码
60+
collegeSelect := htmlquery.FindOne(initialDoc, `//select[@id="xymcdpl"]`)
61+
if collegeSelect == nil {
62+
return "", fmt.Errorf("college select not found")
63+
}
64+
65+
collegeCode := ""
66+
collegeOptions := htmlquery.Find(collegeSelect, ".//option")
67+
for _, option := range collegeOptions {
68+
optionText := htmlquery.InnerText(option)
69+
optionValue := htmlquery.SelectAttr(option, "value")
70+
71+
// 直接匹配学院名称
72+
if optionText == info.College {
73+
collegeCode = optionValue
74+
break
75+
}
76+
77+
// 处理学院改名的情况
78+
if (strings.Contains(optionText, "计算机与大数据") || strings.Contains(optionText, "数学与统计")) &&
79+
strings.Contains(info.College, "数学与计算机") {
80+
collegeCode = optionValue
81+
break
82+
}
83+
}
84+
85+
if collegeCode == "" {
86+
return "", fmt.Errorf("college code not found for %s", info.College)
87+
}
88+
89+
viewStateGenerator := htmlquery.SelectAttr(htmlquery.FindOne(initialDoc, `//*[@id="__VIEWSTATEGENERATOR"]`), "value")
90+
91+
// 选择年级和学院后获取专业列表
92+
majorListResp, err := s.PostWithIdentifier(constants.CultivatePlanURL, map[string]string{
93+
"__VIEWSTATE": viewStateMap["VIEWSTATE"],
94+
"__EVENTVALIDATION": viewStateMap["EVENTVALIDATION"],
95+
"__EVENTTARGET": "ctl00$njdpl",
96+
"__EVENTARGUMENT": "",
97+
"__VIEWSTATEGENERATOR": viewStateGenerator,
98+
"ctl00$njdpl": info.Grade, // 年级
99+
"ctl00$xymcdpl": collegeCode, // 学院名称
100+
"ctl00$dldpl": "<-全部->", // 大类
101+
"ctl00$zymcdpl": "<-全部->", // 专业代码
102+
"ctl00$zylbdpl": "本专业", // 修读类别:本专业/辅修
103+
"ctl00$ContentPlaceHolder1$DDL_syxw": "<-全部->", // 授予学位
104+
"ctl00$ContentPlaceHolder1$BT_submit": "确定",
105+
})
106+
if err != nil {
107+
return "", err
108+
}
109+
110+
// 查找专业代码
111+
majorSelect := htmlquery.FindOne(majorListResp, `//select[@id="zymcdpl"]`)
112+
if majorSelect == nil {
113+
return "", fmt.Errorf("major select not found")
114+
}
115+
116+
majorCode := ""
117+
majorOptions := htmlquery.Find(majorSelect, ".//option")
118+
for _, option := range majorOptions {
119+
optionText := htmlquery.InnerText(option)
120+
if optionText == info.Major {
121+
majorCode = htmlquery.SelectAttr(option, "value")
122+
break
123+
}
124+
}
125+
126+
if majorCode == "" {
127+
return "", fmt.Errorf("major code not found for %s", info.Major)
128+
}
129+
130+
// 构造最终URL
131+
finalURL := fmt.Sprintf("/pyfa/pyjh/pyfa_bzy.aspx?nj=%s&xyh=%s&zyh=%s&zylb=本专业&id=%s",
132+
info.Grade, collegeCode, majorCode, s.Identifier)
133+
134+
return constants.JwchPrefix + finalURL, nil
135+
}
136+
137+
// fallback逻辑:当精确匹配失败时使用
138+
func (s *Student) getCultivatePlanWithFallback(info *StudentDetail, viewStateMap map[string]string) (string, error) {
139+
// 获取初始页面状态
140+
initialDoc, err := s.GetWithIdentifier(constants.CultivatePlanURL)
141+
if err != nil {
142+
return "", err
143+
}
144+
145+
viewStateGenerator := htmlquery.SelectAttr(htmlquery.FindOne(initialDoc, `//*[@id="__VIEWSTATEGENERATOR"]`), "value")
146+
147+
// 只选择年级,提交查询
38148
res, err := s.PostWithIdentifier(constants.CultivatePlanURL,
39149
map[string]string{
40-
"__VIEWSTATE": viewStateMap["VIEWSTATE"],
41-
"__EVENTVALIDATION": viewStateMap["EVENTVALIDATION"],
42-
"ctl00$njdpl": info.Grade, // 年级
43-
// "ctl00$xymcdpl": "010",// 学院名称
44-
"ctl00$dldpl": "<-全部->", // 大类
45-
"ctl00$zymcdpl": "<-全部->", // 专业代码(无法获取)
46-
"ctl00$zylbdpl": "本专业", // 本专业、辅修
150+
"__VIEWSTATE": viewStateMap["VIEWSTATE"],
151+
"__EVENTVALIDATION": viewStateMap["EVENTVALIDATION"],
152+
"__EVENTTARGET": "",
153+
"__EVENTARGUMENT": "",
154+
"__VIEWSTATEGENERATOR": viewStateGenerator,
155+
"ctl00$njdpl": info.Grade,
156+
"ctl00$dldpl": "<-全部->",
157+
"ctl00$zymcdpl": "<-全部->",
158+
"ctl00$zylbdpl": "本专业",
47159
"ctl00$ContentPlaceHolder1$DDL_syxw": "<-全部->",
48160
"ctl00$ContentPlaceHolder1$BT_submit": "确定",
49161
})
50162
if err != nil {
51163
return "", err
52164
}
53165
xpathExpr := fmt.Sprintf("//tr[td[matches(string(.), '^(.*?)%s$')]]/td/a[contains(@href, 'pyfa')]/@href", regexp.QuoteMeta(info.Major))
54-
55166
node := htmlquery.FindOne(res, xpathExpr)
56167
if node == nil {
57-
return "", fmt.Errorf("%s", "cultivate plan not found")
168+
return "", fmt.Errorf("cultivate plan not found for major: %s", info.Major)
58169
}
59170

60171
url := htmlquery.SelectAttr(node, "href")

0 commit comments

Comments
 (0)