chromedp -—— 基于 go 的自动化操作浏览器库

chromedp

chromedp 是一个用于 Chrome 浏览器的自动化测试工具,基于 Go 语言开发,专门用于控制和操作 Chrome 浏览器实例。

chromedp 安装

bash 复制代码
go get -u github.com/chromedp/chromedp

基于chromedp 实现的的简易学习通刷课系统

目前实现的功能:

  1. 自动登录,找到课程中第一个没刷的课
  2. 视频播放意外暂停时,自动恢复播放
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:

相关推荐
Ai-_Man1 分钟前
Coze扣子还是不可以导出左侧所有对话,只能点进去单条内容导出,方法不对吗?
开发语言·人工智能·ai·小程序·1024程序员节
raindayinrain9 分钟前
c++设计模式
开发语言·c++·设计模式
hiahiahia12317 分钟前
Streaming Model Output
开发语言·前端
熊猫钓鱼>_>44 分钟前
鸿蒙PC高分屏与键鼠交互适配:DPI缩放、右键菜单一次讲清
开发语言·笔记·华为·ai编程·harmonyos·鸿蒙·鸿蒙心迹
紧跟先前的步伐1 小时前
Go AI Agent 实战 22|完善 Agent 执行循环:从工具调用到最终回答
人工智能·ai·golang
octopus_c1 小时前
C++ 运算符重载详解 && 日期类的实现
开发语言·c++
Eiceblue1 小时前
用 Python 给 Word 文档加水印:文字、图片与批量处理
开发语言·vscode·python·word
j7~1 小时前
【C++ 面试笔记】(篇二):类与数据抽象 & STL 容器与算法
开发语言·c++·面试·stl容器和算法·类和数据抽象
Fuyo_11192 小时前
深入解析 C++ unordered_set 与 unordered_map 的核心特性与性能实战
开发语言·c++
ShineWinsu2 小时前
对于Qt:QPushButton常见属性的解析
开发语言·c++·qt·api·gui·按钮·qpushbutton