chromedp
chromedp 是一个用于 Chrome 浏览器的自动化测试工具,基于 Go 语言开发,专门用于控制和操作 Chrome 浏览器实例。
chromedp 安装
bash
go get -u github.com/chromedp/chromedp
基于chromedp 实现的的简易学习通刷课系统
目前实现的功能:
- 自动登录,找到课程中第一个没刷的课
- 视频播放意外暂停时,自动恢复播放
go
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/chromedp/chromedp"
)
func main() {
// 1. 创建有界面的浏览器选项
opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.Flag("headless", false),
chromedp.Flag("start-maximized", true),
chromedp.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"),
)
// 2. 创建上下文
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()
ctx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
defer cancel()
// 3. 运行主流程
err := chromedp.Run(ctx,
// 登录流程
chromedp.Navigate("课程url"), // 替换为要刷的课的url
chromedp.WaitVisible(`#phone`, chromedp.ByID),
chromedp.SendKeys(`#phone`, "账号", chromedp.ByID), // 替换为自己的账号
chromedp.SendKeys(`#pwd`, "密码", chromedp.ByID), // 替换为自己的密码
chromedp.Click(`#loginBtn`, chromedp.ByID),
chromedp.Sleep(3*time.Second),
// 开始学习流程
startLearningProcess(),
)
if err != nil {
log.Fatal("运行失败: ", err)
}
}
func startLearningProcess() chromedp.Action {
return chromedp.ActionFunc(func(ctx context.Context) error {
// 1. 点击第一个待完成任务
if err := chromedp.Run(ctx,
chromedp.WaitVisible(`.catalog_points_yi`, chromedp.ByQuery),
chromedp.Click(`.posCatalog_select:has(.catalog_points_yi) .posCatalog_name`, chromedp.NodeVisible),
chromedp.Sleep(2*time.Second),
); err != nil {
return fmt.Errorf("点击任务失败: %w", err)
}
// 2. 处理视频播放
if err := handleVideoPlayback(ctx); err != nil {
return fmt.Errorf("视频处理失败: %w", err)
}
// todo 视频结束后自动刷题
return nil
})
}
func handleVideoPlayback(ctx context.Context) error {
// 尝试点击播放按钮
if err := chromedp.Run(ctx,
chromedp.Click(`//button[@class="vjs-big-play-button"]`, chromedp.NodeVisible),
chromedp.Sleep(3*time.Second),
); err != nil {
log.Println("未能点击播放按钮,可能已自动播放:", err)
}
// 监控视频状态
for {
var videoState struct {
CurrentTime float64 `js:"currentTime"`
Duration float64 `js:"duration"`
Ended bool `js:"ended"`
Paused bool `js:"paused"`
}
var result []interface{}
err := chromedp.Evaluate(`
var video = document.getElementById('iframe').contentWindow.document.querySelector(".ans-attach-online").contentWindow.document.getElementById('video_html5_api');
[video.currentTime,video.duration,video.ended,video.paused]
`, &result).Do(ctx)
videoState.CurrentTime = result[0].(float64)
videoState.Duration = result[1].(float64)
videoState.Ended = result[2].(bool)
videoState.Paused = result[3].(bool)
if err != nil {
return fmt.Errorf("获取视频状态失败: %w", err)
}
if videoState.Duration == 0 {
log.Println("等待视频加载...")
time.Sleep(3 * time.Second)
continue
}
log.Printf("视频进度: %.1f/%.1f秒, 已暂停: %v, 已结束: %v",
videoState.CurrentTime, videoState.Duration, videoState.Paused, videoState.Ended)
if videoState.Ended {
log.Println("视频播放结束")
return nil
}
if videoState.Paused {
log.Println("检测到视频暂停,尝试恢复播放...")
if err := chromedp.Run(ctx,
chromedp.Evaluate(`document.getElementById('iframe').contentWindow.document.querySelector(".ans-attach-online").contentWindow.document.getElementById('video_html5_api').play()`, nil),
); err != nil {
log.Println("恢复播放失败:", err)
}
}
time.Sleep(10 * time.Second) // 每10秒检查一次
}
}
课程url为该页面的url: