study_xxqg/lib/respond.go

585 lines
14 KiB
Go
Raw Normal View History

2021-11-12 07:46:33 +00:00
package lib
import (
rand2 "math/rand"
"regexp"
"strings"
"time"
"github.com/mxschmitt/playwright-go"
log "github.com/sirupsen/logrus"
"github.com/huoxue1/study_xxqg/model"
2021-11-12 07:46:33 +00:00
)
const (
MyPointsUri = "https://pc.xuexi.cn/points/my-points.html"
DailyBUTTON = `#app > div > div.layout-body > div >
div.my-points-section > div.my-points-content > div:nth-child(5) > div.my-points-card-footer > div.buttonbox > div`
WEEKEND = `#app > div > div.layout-body >
div > div.my-points-section > div.my-points-content > div:nth-child(6) > div.my-points-card-footer > div.buttonbox > div`
SPECIALBUTTON = `#app > div > div.layout-body >
div > div.my-points-section > div.my-points-content > div:nth-child(7) > div.my-points-card-footer > div.buttonbox > div`
)
func (c *Core) RespondDaily(user *model.User, model string) {
2021-11-12 07:46:33 +00:00
defer func() {
err := recover()
if err != nil {
2021-11-27 08:24:24 +00:00
log.Errorln("答题模块异常结束或答题已完成")
c.Push("text", "答题模块异常退出或答题已完成")
time.Sleep(5 * time.Second)
log.Errorln(err)
2021-11-12 07:46:33 +00:00
}
}()
if c.IsQuit() {
return
}
2021-11-12 07:46:33 +00:00
// 获取用户成绩
score, err := GetUserScore(user.ToCookies())
2021-11-12 07:46:33 +00:00
if err != nil {
log.Errorln("获取分数失败,停止每日答题", err.Error())
return
}
page, err := (*c.context).NewPage()
2021-11-12 07:46:33 +00:00
if err != nil {
log.Errorln("创建页面失败" + err.Error())
return
}
defer func() {
page.Close()
}()
log.Infoln(user.ToBrowserCookies())
err = (*c.context).AddCookies(user.ToBrowserCookies()...)
2021-11-12 07:46:33 +00:00
if err != nil {
log.Errorln(err.Error())
2021-11-12 07:46:33 +00:00
log.Errorln("添加cookie信息失败已退出答题")
return
}
page.Goto("https://pc.xuexi.cn/points/my-points.html")
2021-11-27 08:24:24 +00:00
log.Infoln("已加载答题模块")
2021-11-12 07:46:33 +00:00
_, err = page.Goto(MyPointsUri, playwright.PageGotoOptions{
Referer: playwright.String(MyPointsUri),
Timeout: playwright.Float(10000),
2021-11-12 07:46:33 +00:00
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
})
if err != nil {
log.Errorln("跳转页面失败")
return
}
switch model {
case "daily":
{
// 检测是否已经完成
if score.Content["daily"].CurrentScore >= score.Content["daily"].MaxScore {
log.Infoln("检测到每日答题已经完成,即将退出答题")
return
}
err = page.Click(DailyBUTTON)
if err != nil {
log.Errorln("跳转到积分页面错误")
return
}
c.Push("text", "已加载每日答题模块")
2021-11-12 07:46:33 +00:00
}
case "weekly":
{
// 检测是否已经完成
if score.Content["weekly"].CurrentScore >= score.Content["weekly"].MaxScore {
log.Infoln("检测到每周答题已经完成,即将退出答题")
return
}
err = page.Click(WEEKEND)
if err != nil {
log.Errorln("跳转到积分页面错误")
return
}
c.Push("text", "已加载每周答题模块")
2021-11-12 07:46:33 +00:00
}
case "special":
{
// 检测是否已经完成
if score.Content["special"].CurrentScore >= score.Content["special"].MaxScore {
log.Infoln("检测到特殊答题已经完成,即将退出答题")
return
}
err = page.Click(SPECIALBUTTON)
if err != nil {
log.Errorln("跳转到积分页面错误")
return
}
c.Push("text", "已加载专项答题模块")
2021-11-12 07:46:33 +00:00
}
}
time.Sleep(5 * time.Second)
2021-12-06 05:31:05 +00:00
// 跳转到答题页面若返回true则说明已答完
if getAnswerPage(page, model) {
return
}
2021-11-12 07:46:33 +00:00
tryCount := 0
2021-11-12 07:46:33 +00:00
for true {
label:
tryCount++
if tryCount >= 30 {
log.Panicln("多次循环尝试答题已超出30次自动退出")
}
if c.IsQuit() {
return
}
2021-11-12 07:46:33 +00:00
// 查看是否存在答题按钮,若按钮可用则重新提交答题
btn, err := page.QuerySelector(`#app > div > div.layout-body > div > div.detail-body > div.action-row > button`)
if err != nil {
log.Infoln("获取提交按钮失败,本次答题结束" + err.Error())
return
}
enabled, err := btn.IsEnabled()
if err != nil {
log.Errorln(err.Error())
continue
}
if enabled {
err := btn.Click()
if err != nil {
log.Errorln("提交答案失败")
}
}
handle, _ := page.QuerySelector("#nc_mask > div")
if handle != nil {
log.Infoln(handle)
en, err := handle.IsVisible()
if err != nil {
return
}
if en {
page.Mouse().Move(496, 422)
time.Sleep(1 * time.Second)
page.Mouse().Down()
page.Mouse().Move(772, 416, playwright.MouseMoveOptions{})
page.Mouse().Up()
time.Sleep(10 * time.Second)
log.Infoln("可能存在滑块")
c.Push("text", "答题过程出现滑块,正在尝试滑动")
en, err = handle.IsVisible()
if err != nil {
return
}
if en {
page.Evaluate("__nc.reset()")
goto label
}
}
}
2021-11-12 07:46:33 +00:00
switch model {
case "daily":
{
// 检测是否已经完成
if score.Content["daily"].CurrentScore >= score.Content["daily"].MaxScore {
log.Infoln("检测到每日答题已经完成,即将退出答题")
return
}
}
case "weekly":
{
// 检测是否已经完成
if score.Content["weekly"].CurrentScore >= score.Content["weekly"].MaxScore {
log.Infoln("检测到每周答题已经完成,即将退出答题")
return
}
}
case "special":
{
// 检测是否已经完成
if score.Content["special"].CurrentScore >= score.Content["special"].MaxScore {
log.Infoln("检测到特殊答题已经完成,即将退出答题")
return
}
}
}
// 获取题目类型
category, err := page.QuerySelector(
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-header`)
if err != nil {
log.Errorln("没有找到题目元素" + err.Error())
return
}
2021-11-27 08:24:24 +00:00
_ = category.WaitForElementState(`visible`)
2021-11-12 07:46:33 +00:00
time.Sleep(1 * time.Second)
// 获取题目
question, err := page.QuerySelector(
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-body > div`)
if err != nil {
log.Errorln("未找到题目问题元素")
return
}
categoryText, err := category.TextContent()
if err != nil {
log.Errorln("获取题目元素失败" + err.Error())
return
}
log.Infoln("## 题目类型:" + categoryText)
questionText, err := question.TextContent()
if err != nil {
log.Errorln("获取题目问题失败" + err.Error())
return
}
log.Infoln("## 题目:" + questionText)
// 获取答题帮助
openTips, err := page.QuerySelector(
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-footer > span`)
if err != nil || openTips == nil {
log.Errorln("未获取到题目提示信息")
2021-11-12 07:46:33 +00:00
goto label
2021-11-12 07:46:33 +00:00
}
log.Debugln("开始尝试获取打开提示信息按钮")
2021-11-12 07:46:33 +00:00
err = openTips.Click()
if err != nil {
log.Errorln("点击打开提示信息按钮失败" + err.Error())
goto label
2021-11-12 07:46:33 +00:00
}
log.Debugln("已打开提示信息")
2021-11-12 07:46:33 +00:00
content, err := page.Content()
if err != nil {
log.Errorln("获取网页全体内容失败" + err.Error())
goto label
2021-11-12 07:46:33 +00:00
}
2022-04-24 08:55:39 +00:00
time.Sleep(time.Second * time.Duration(rand2.Intn(3)))
log.Debugln("以获取网页内容")
2021-11-12 07:46:33 +00:00
err = openTips.Click()
if err != nil {
log.Errorln("点击打开提示信息按钮失败" + err.Error())
goto label
2021-11-12 07:46:33 +00:00
}
log.Debugln("已关闭提示信息")
2021-11-12 07:46:33 +00:00
tips := getTips(content)
log.Infoln("[提示信息]", tips)
// 填空题
switch {
case strings.Contains(categoryText, "填空题"):
2022-02-14 09:57:55 +00:00
if len(tips) < 1 {
tips = append(tips, "不知道")
}
2021-11-12 07:46:33 +00:00
err := FillBlank(page, tips)
if err != nil {
log.Errorln("填空题答题失败" + err.Error())
return
}
case strings.Contains(categoryText, "多选题"):
log.Infoln("读取到多选题")
options, err := getOptions(page)
if err != nil {
log.Errorln("获取选项失败" + err.Error())
return
}
log.Infoln("获取到选项答案:", options)
log.Infoln("[多选题选项]", options)
var answer []string
for _, option := range options {
for _, tip := range tips {
if strings.Contains(option, tip) {
answer = append(answer, option)
2021-11-12 07:46:33 +00:00
}
}
}
if len(answer) < 1 {
answer = append(answer, options...)
log.Infoln("无法判断答案自动选择ABCD")
}
log.Infoln("根据提示分别选择了", RemoveRepByLoop(answer))
2021-11-12 07:46:33 +00:00
err = radioCheck(page, answer)
if err != nil {
return
}
case strings.Contains(categoryText, "单选题"):
log.Infoln("读取到单选题")
options, err := getOptions(page)
if err != nil {
log.Errorln("获取选项失败" + err.Error())
return
}
log.Infoln("获取到选项答案:", options)
2021-11-12 07:46:33 +00:00
var answer []string
for _, option := range options {
for _, tip := range tips {
if strings.Contains(option, tip) {
answer = append(answer, option)
2021-11-12 07:46:33 +00:00
}
}
}
if len(answer) < 1 {
answer = append(answer, options[0])
log.Infoln("无法判断答案自动选择A")
}
log.Infoln("根据提示分别选择了", answer)
2021-11-12 07:46:33 +00:00
err = radioCheck(page, answer)
if err != nil {
return
}
}
score, _ = GetUserScore(user.ToCookies())
2021-11-12 07:46:33 +00:00
}
}
2021-12-06 05:31:05 +00:00
func getAnswerPage(page playwright.Page, model string) bool {
2021-11-12 07:46:33 +00:00
selectPages, err := page.QuerySelectorAll(`#app .ant-pagination .ant-pagination-item`)
if err != nil {
log.Errorln("获取到页码失败")
2021-12-06 05:31:05 +00:00
return false
2021-11-12 07:46:33 +00:00
}
log.Infoln("共获取到", len(selectPages), "页")
modelName := ""
modelSlector := ""
switch model {
case "daily":
2021-12-06 05:31:05 +00:00
return false
2021-11-12 07:46:33 +00:00
case "weekly":
modelName = "每周答题"
modelSlector = "button.ant-btn-primary"
case "special":
modelName = "专项答题"
modelSlector = "#app .items .item button"
}
for i := 1; i <= len(selectPages); i++ {
log.Infoln("获取到"+modelName, "第", i, "页")
err1 := selectPages[i-1].Click()
if err1 != nil {
log.Errorln("点击页码失败")
}
time.Sleep(2 * time.Second)
2021-11-12 07:46:33 +00:00
datas, err := page.QuerySelectorAll(modelSlector)
if err != nil {
log.Errorln("获取页面内容失败")
continue
}
for _, data := range datas {
content, err := data.TextContent()
if err != nil {
log.Errorln("获取按钮文本失败" + err.Error())
2021-11-12 07:46:33 +00:00
continue
}
if strings.Contains(content, "重新") || strings.Contains(content, "满分") {
continue
} else {
if strings.Contains(content, "电影试题") {
log.Infoln("发现有未答题的电影试题")
continue
}
enabled, err := data.IsEnabled()
if err != nil {
2021-12-06 05:31:05 +00:00
return false
2021-11-12 07:46:33 +00:00
}
if enabled {
log.Infoln("按钮可用")
}
data.WaitForElementState("stable", playwright.ElementHandleWaitForElementStateOptions{Timeout: playwright.Float(10000)})
time.Sleep(5 * time.Second)
2021-11-12 07:46:33 +00:00
err = data.Click(playwright.ElementHandleClickOptions{
Button: nil,
ClickCount: playwright.Int(2),
Delay: nil,
Force: nil,
Modifiers: nil,
NoWaitAfter: nil,
Position: nil,
Timeout: playwright.Float(100000),
})
if err != nil {
log.Errorln("点击按钮失败" + err.Error())
time.Sleep(2 * time.Second)
continue
}
time.Sleep(3 * time.Second)
2021-12-06 05:31:05 +00:00
return false
2021-11-12 07:46:33 +00:00
}
}
}
2021-12-06 05:31:05 +00:00
log.Infoln("检测到每周答题已经完成")
return true
2021-11-12 07:46:33 +00:00
}
func radioCheck(page playwright.Page, answer []string) error {
radios, err := page.QuerySelectorAll(`.q-answer.choosable`)
if err != nil {
log.Errorln("获取选项失败")
return err
}
log.Debugln("获取到", len(radios), "个按钮")
for _, radio := range radios {
textContent, err := radio.TextContent()
if err != nil {
return err
}
for _, s := range answer {
if textContent == s {
err := radio.Click()
if err != nil {
return err
}
r := rand2.Intn(2)
time.Sleep(time.Duration(r) * time.Second)
}
}
}
r := rand2.Intn(5)
time.Sleep(time.Duration(r) * time.Second)
checkNextBotton(page)
return nil
}
func getOptions(page playwright.Page) ([]string, error) {
handles, err := page.QuerySelectorAll(`.q-answer.choosable`)
if err != nil {
log.Errorln("获取选项信息失败")
return nil, err
}
var options []string
for _, handle := range handles {
content, err := handle.TextContent()
if err != nil {
return nil, err
}
options = append(options, content)
}
return options, err
}
func getTips(data string) []string {
data = strings.ReplaceAll(data, " ", "")
data = strings.ReplaceAll(data, "\n", "")
compile := regexp.MustCompile(`<fontcolor="red">(.*?)</font>`)
match := compile.FindAllStringSubmatch(data, -1)
var tips []string
for _, i := range match {
tips = append(tips, i[1])
}
return tips
}
func FillBlank(page playwright.Page, tips []string) error {
video := false
var answer []string
for _, tip := range tips {
if tip == "请观看视频" {
video = true
}
}
if video {
answer = append(answer, "不知道")
} else {
answer = tips
}
inouts, err := page.QuerySelectorAll(`div.q-body > div > input`)
if err != nil {
log.Errorln("获取输入框错误" + err.Error())
return err
}
log.Debugln("获取到", len(inouts), "个填空")
if len(inouts) == 1 && len(tips) > 1 {
temp := ""
for _, tip := range tips {
temp += tip
}
answer = strings.Split(temp, ",")
log.Infoln("答案已合并处理" + err.Error())
}
for i := 0; i < len(inouts); i++ {
err := inouts[i].Fill(answer[i])
if err != nil {
log.Errorln("填充答案失败" + err.Error())
continue
}
r := rand2.Intn(5)
time.Sleep(time.Duration(r) * time.Second)
}
r := rand2.Intn(2)
time.Sleep(time.Duration(r) * time.Second)
checkNextBotton(page)
return nil
}
func checkNextBotton(page playwright.Page) {
btns, err := page.QuerySelectorAll(`#app .action-row > button`)
if err != nil {
log.Errorln("未检测到按钮" + err.Error())
return
}
if len(btns) <= 1 {
err := btns[0].Check()
if err != nil {
log.Errorln("点击下一题按钮失败")
2021-11-12 07:46:33 +00:00
return
}
time.Sleep(2 * time.Second)
_, err = btns[0].GetAttribute("disabled")
if err != nil {
log.Infoln("未检测到禁言属性")
return
}
} else {
err := btns[1].Click()
if err != nil {
log.Errorln("提交试卷失败")
return
}
log.Infoln("已成功提交试卷")
}
}
// RemoveRepByLoop 通过两重循环过滤重复元素
func RemoveRepByLoop(slc []string) []string {
var result []string // 存放结果
for i := range slc {
flag := true
for j := range result {
if slc[i] == result[j] {
flag = false // 存在重复元素标识为false
break
}
}
if flag { // 标识为false不添加进结果
result = append(result, slc[i])
}
}
return result
}