commit fcdc5b8f2dd6a7262e7f733f8cfe4d8c4ed5bb31 Author: zyj Date: Mon Feb 9 02:08:53 2026 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d8d8d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +user-data \ No newline at end of file diff --git a/account_cookie.json b/account_cookie.json new file mode 100644 index 0000000..32cf51a --- /dev/null +++ b/account_cookie.json @@ -0,0 +1,362 @@ +[ + { + "name": "tfstk", + "value": "gREthFDeE6fgrssCwhbhnyNsGkB3kw2ap5yWmjcMlWFLGSHDm-GmDSFYMf0f_cqY9SNxnn2bmxZxbk4MmffZD-NoD_flqgmaQ0ofZ_AYbUGtcxsmGw01D9Qpu_flqMb6dmCOZRq-YUhIeYijCfiXd9HoFAij5mMCpxMD1Et_GJ6KTxLXfngsAMMZHAijcSwCpxlIGmg_GJ6K3XGjZaCxOdGDDye4oACPRf-XckHt5w2sOnMUvA3tNRZ9cn9rBVh7CXCtMibER-uY0K-xuRazgYN61_0ahyFKBmIH50wLl7HUfgAtLP2QEXwJ3nyZXkELl2B1fJnt64qQtdLjXrNaDVz93TyIfWzraV_FTvEgqqhrJB1_KJhsyrFGTnGgyJNKrkAHqmPUlSMYOCIztuq--0RowxY1p9L2uVMETlR31IcEn7kKZOIvuEuFLvhlpT82uVM-pbX9eE8q895..", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1786125734 + }, + { + "name": "arms_uid", + "value": "27b17ae2-81c6-4d4f-9496-3e0582ff16d2", + "domain": "cart.taobao.com", + "path": "/", + "secure": true, + "expires": 1786125734.323322 + }, + { + "name": "ucn", + "value": "center", + "domain": "cart.taobao.com", + "path": "/", + "expires": 1789673650.898824 + }, + { + "name": "ubn", + "value": "p", + "domain": "cart.taobao.com", + "path": "/", + "expires": 1805133733.898694 + }, + { + "name": "havana_sdkSilent", + "value": "1770602527511", + "domain": ".taobao.com", + "path": "/", + "expires": -1 + }, + { + "name": "havana_lgc_exp", + "value": "1801677727511", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1801706527.482485 + }, + { + "name": "bxuab", + "value": "0", + "domain": ".taobao.com", + "path": "/", + "expires": 1770574326.708635 + }, + { + "name": "_m_h5_tk_enc", + "value": "4c9af36e47eb95f02be3d950f7d55fe8", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1770579126.261152 + }, + { + "name": "sdkSilent", + "value": "1770602527511", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": -1 + }, + { + "name": "_cc_", + "value": "Vq8l%2BKCLiw%3D%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1802138525.099279 + }, + { + "name": "uc3", + "value": "nk2=2W5q6SxD\u0026id2=UU8OeHEFYuIE%2Fw%3D%3D\u0026lg2=VFC%2FuZ9ayeYq2g%3D%3D\u0026vt3=F8dD29DnFvY6X0CtCDI%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1773165725.098812 + }, + { + "name": "thw", + "value": "cn", + "domain": ".taobao.com", + "path": "/", + "expires": 1802109726.659989 + }, + { + "name": "sn", + "value": "", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.098801 + }, + { + "name": "isg", + "value": "BOfnyr79QnbK1cb6ZiUi-ICWdhuxbLtOBy1sRLlUA3adqAdqwTxLniW7yKg2QJPG", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1786125729 + }, + { + "name": "cookie1", + "value": "AHnVds9uwkx%2BzrBsa2Br6M%2B8mFv7ocAZXOGLS3QmG%2Fo%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1773165725.099435 + }, + { + "name": "wk_unb", + "value": "UU8OeHEFYuIE%2Fw%3D%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1775786522.464568 + }, + { + "name": "_l_g_", + "value": "Ug%3D%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.099344 + }, + { + "name": "cna", + "value": "h70PIpIjgAECAa+8pHQPSpRy", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1805133703.735092 + }, + { + "name": "tracknick", + "value": "%5Cu4F55%5Cu672A%5Cu5C39", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1802138525.099204 + }, + { + "name": "_samesite_flag_", + "value": "true", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": -1 + }, + { + "name": "_nk_", + "value": "%5Cu4F55%5Cu672A%5Cu5C39", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.099402 + }, + { + "name": "uc1", + "value": "cookie14=UoYZaqFObbA9zg%3D%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": -1 + }, + { + "name": "skt", + "value": "3e7dedf3c5d7f59e", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1773165725.099071 + }, + { + "name": "dnk", + "value": "%5Cu4F55%5Cu672A%5Cu5C39", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.099038 + }, + { + "name": "cookie17", + "value": "UU8OeHEFYuIE%2Fw%3D%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1773165725.099007 + }, + { + "name": "existShop", + "value": "MTc3MDU3MzcyNQ%3D%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.099129 + }, + { + "name": "cancelledSubSites", + "value": "empty", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.098946 + }, + { + "name": "csg", + "value": "63a3b224", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.098847 + }, + { + "name": "uc4", + "value": "id4=0%40U22Jqe1yyAMca0PbJ175RuXiEyQm\u0026nk4=0%4024ipPGyqAyNcYskAXekPLbg%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1773165725.099159 + }, + { + "name": "unb", + "value": "2769790825", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1773165725.098682 + }, + { + "name": "mtop_partitioned_detect", + "value": "1", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1770579126.261076 + }, + { + "name": "3PcFlag", + "value": "1770573702709", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1771466502.684566 + }, + { + "name": "sgcookie", + "value": "E100QYmZjz3WUI%2B6Yb1YO6UfaxPQ62sdAFFOvgkUiNEFnVLhaN%2FpQ9g6DjgxTOJNI9udV24oFQAPLP17peJOZks%2FOvhoACbilBAC1Hhe3vMAoa9jvUDa9%2F5D%2FVIoj40y%2Ffnx", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1802138522.464589 + }, + { + "name": "ultraCookieBase", + "value": "1k6S5%2BcxkgQpZA4Xfbyi8gTG%2By4cSksG3aXzy18EbaWBcFwmxQrEFaptGmtlgMhMyFkb9xXZw49oDDyhu36m6TasHWvnb5c0fdjGmLf0P4VfHzktxDxzIUgpJasHyc2AFlKN6wB8MGHOhvDSnHXMMA9Ak3KjaEUqLHbfZjokqSviRjqfKadUT%2BRD5bo15bmtMvqZRIj851tLvlG8tRKCZ5OwrvUSwimB4MvXB0EjsKp0nOQx3IDBO%2Bf2xICypyv1o13sbZyPDPfe756xwOhelodlzHk7hp%2FhysThoa8BCrcd65zMYzb5Tdio2bhkgVfFIya0JcQ%3D%3D", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": -1 + }, + { + "name": "_hvn_lgc_", + "value": "0", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1801706527.482438 + }, + { + "name": "wk_cookie2", + "value": "182060f48332dfef01c11cf24af15454", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1775786522.464268 + }, + { + "name": "lgc", + "value": "%5Cu4F55%5Cu672A%5Cu5C39", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.098914 + }, + { + "name": "havana_lgc2_0", + "value": "eyJoaWQiOjI3Njk3OTA4MjUsInNnIjoiNmIwZGE3OTVhOTNmNDE0MTQ5ZWQ2YmYzNjY0ZDAyM2QiLCJzaXRlIjowLCJ0b2tlbiI6IjFYNXFrLTlIeExkV2k5MUtnTXlVV0hnIn0", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1801706527.482518 + }, + { + "name": "_tb_token_", + "value": "e71eb736fe5ee", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.099468 + }, + { + "name": "sg", + "value": "%E5%B0%B952", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.099374 + }, + { + "name": "xlly_s", + "value": "1", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1770832903 + }, + { + "name": "t", + "value": "b19353ffe27e48a62571c666710e67aa", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1773165725.098976 + }, + { + "name": "_m_h5_tk", + "value": "bbf86786a9fc68cbff2d3ea69228ef04_1770584166279", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "expires": 1770579126.261124 + }, + { + "name": "cookie2", + "value": "1a0986ed49f3d18139c1d71113f6ce18", + "domain": ".taobao.com", + "path": "/", + "secure": true, + "httpOnly": true, + "expires": 1773165725.0991 + } +] \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..59988dc --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,201 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "go-sccchina/libs" + "log" + "os" + "strings" + "time" + + "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/proto" +) + +var login = flag.Bool("login", false, "是否登录") +var test = flag.Bool("time", false, "测试") +var Browser libs.Browser + +// var Chrome libs.Chrome +func main() { + flag.Parse() + log.Println(*login) + if *login { + loginFun() + } + if *test { + obj := Browser.GetBrowser(1, &libs.Fingerprint{}) + browser := obj.Browser + page := obj.Page + cookies, _ := loadCookiesFromFile("account_cookie.json") + browser.SetCookies(cookies) + page.MustNavigate("https://cart.taobao.com/cart.htm?spm=tbpc.mytb_index.leftnav.1.6db2782d0TVVip").MustWaitLoad() + page.MustWaitNavigation() + page.MustWaitLoad() // DOM 加载完成 + page.MustWaitIdle() // 基本静止(减少早期误判) + page.MustActivate() // 前置以便扫码 + // // 获取当前课程列表 + // res := getApiResponse(page, "https://hnit.sccchina.net/student/student/coursestudy/getlist") + // var dataBody map[string]any + // json.Unmarshal([]byte(res), &dataBody) + // list := dataBody["items"].([]interface{}) + // // pretty, _ := json.MarshalIndent(list, "", " ") + // // 判断当前有多少个课程需要学习 + // for _, v := range list { + // m := v.(map[string]interface{}) + // realCoursewarePlayNum := m["realCoursewarePlayNum"].(string) + // realCoursewarePlayTime := m["realCoursewarePlayTime"].(string) + // var showScore string = "0" + // if m["showScore"] != nil { + // if str, ok := m["showScore"].(string); ok { + // showScore = str + // } + // } + // courseVersionID := m["courseVersionID"].(string) + // teachplanCourseVersionId := m["teachplanCourseVersionId"].(string) + // sign := m["sign"].(string) + // userAccountId := m["userAccountId"].(string) + // versionName := m["versionName"].(string) + // // 分割字符串 判断当前 课时 成绩 + // playTimeArr := strings.Split(realCoursewarePlayTime, " / ") + // // 将第一个转为数字 + // activeTime, _ := strconv.ParseFloat(strings.TrimSpace(playTimeArr[0]), 64) + // var endTime float64 + // if strings.TrimSpace(playTimeArr[1]) == "--" { + // endTime = 360 + // } else { + // TimeEnd, _ := strconv.ParseFloat(strings.TrimSpace(playTimeArr[1]), 64) + // endTime = TimeEnd + // } + // // 判断有哪些课程需要观看 + // // var pages []*rod.Page + // if showScore == "0" && activeTime < endTime { + // log.Println(activeTime) + // log.Println(endTime) + // log.Println(realCoursewarePlayNum, realCoursewarePlayTime, showScore, courseVersionID, teachplanCourseVersionId, sign, userAccountId, versionName) + // url := fmt.Sprintf(`https://hnit.sccchina.net/student/videolearning.html#Subpage/StudentVersionVideo?courseVersionId=%s&teachplanCourseVersionId=%s&sign=%s&userAccountId=%s&syncPracticePiwik=1&piwikSiteId=750&versionName=%s`, courseVersionID, teachplanCourseVersionId, sign, userAccountId, versionName) + // log.Println(url) + // time.Sleep(3 * time.Second) + // p := browser.MustPage(url) + // satrt := p.Timeout(5 * time.Second).MustElement(`#button-courseware`) + // satrt.MustClick() + // time.Sleep(2 * time.Second) + // log.Println(1) + // iframeEl := p.Timeout(10*time.Second).MustElementR(`iframe`, ".*") + // log.Println(2) + // log.Println(iframeEl) + // if iframeEl != nil { + // iframePage := iframeEl.MustFrame() + // iframePage.MustWaitLoad() + // // 再次进入内嵌的iframe + // iframeEl2 := iframePage.Timeout(10 * time.Second).MustElement(`iframe#iframe`) + // iframePage2 := iframeEl2.MustFrame() + // iframePage2.MustWaitLoad() + // cl := iframePage2.Timeout(5 * time.Second).MustElement(`em.pop_close`) + // cl.MustClick() + // } + // time.Sleep(3 * time.Second) + // // pages = append(pages, p) + + // // go func() { + // // browser.MustPage(url) + // // }() + // } + // } + // log.Println(string(pretty)) + select {} + } + +} + +func loginFun() { + obj := Browser.GetBrowser(1, &libs.Fingerprint{}) + browser := obj.Browser + page := obj.Page + page.MustNavigate(`https://login.taobao.com/havanaone/login/login.htm`).MustWaitLoad() + page.MustWaitNavigation() + page.MustWaitLoad() // DOM 加载完成 + page.MustWaitIdle() // 基本静止(减少早期误判) + page.MustActivate() // 前置以便扫码 + + var usl string = "https://login.taobao.com/havanaone/login/login.htm" + for usl == "https://login.taobao.com/havanaone/login/login.htm" { + uri := page.MustEval("() => window.location.href").String() + log.Println("获取当前网页URL:", uri) + usl = uri + time.Sleep(5 * time.Second) + } + page.MustNavigate("https://cart.taobao.com/cart.htm?spm=tbpc.mytb_index.leftnav.1.6db2782d0TVVip").MustWaitLoad() + page.MustWaitNavigation() + page.MustWaitLoad() // DOM 加载完成 + page.MustWaitIdle() // 基本静止(减少早期误判) + page.MustActivate() // 前置以便扫码 + cookieArr := getPageCookie(page, "https://cart.taobao.com/cart.htm?spm=tbpc.mytb_index.leftnav.1.6db2782d0TVVip") + saveCookiesToFile(cookieArr, "account_cookie.json") + browser.Close() +} + +func getPageCookie(page *rod.Page, url string) []*proto.NetworkCookieParam { + cookieArr, _ := page.Cookies([]string{url}) + var cookies []*proto.NetworkCookieParam + for _, cookie := range cookieArr { + cookies = append(cookies, &proto.NetworkCookieParam{ + Name: cookie.Name, + Value: cookie.Value, + Domain: cookie.Domain, + Path: cookie.Path, + Expires: cookie.Expires, // 过期时间 + HTTPOnly: cookie.HTTPOnly, // 禁止 JS 访问 + Secure: cookie.Secure, // 仅 HTTPS 传输 + }) + } + return cookies +} + +func saveCookiesToFile(cookies []*proto.NetworkCookieParam, filename string) error { + data, err := json.MarshalIndent(cookies, "", " ") + if err != nil { + return err + } + return os.WriteFile(filename, data, 0644) +} + +func loadCookiesFromFile(filename string) ([]*proto.NetworkCookieParam, error) { + data, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + var cookies []*proto.NetworkCookieParam + if err := json.Unmarshal(data, &cookies); err != nil { + return nil, err + } + return cookies, nil +} + +// 获取指定接口的响应参数 +func getApiResponse(page *rod.Page, url string) string { + // 定义一个通道接收消息 + ch := make(chan string) + go page.EachEvent(func(e *proto.PageLoadEventFired) { + log.Println("1234567890") + }, func(e *proto.NetworkResponseReceived) { + if strings.Contains(e.Response.URL, url) { + reply, err := (proto.NetworkGetResponseBody{RequestID: e.RequestID}).Call(page) + if err != nil { + fmt.Println(err) + } + ch <- reply.Body + // fmt.Println(reply.Body) + } + })() + + select { + case res := <-ch: + return res + case <-time.After(30 * time.Second): + log.Println("等待上传响应超时") + return "" + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..df23884 --- /dev/null +++ b/go.mod @@ -0,0 +1,16 @@ +module go-sccchina + +go 1.25.1 + +require ( + github.com/go-rod/rod v0.116.2 + github.com/go-rod/stealth v0.4.9 +) + +require ( + github.com/ysmood/fetchup v0.2.3 // indirect + github.com/ysmood/goob v0.4.0 // indirect + github.com/ysmood/got v0.40.0 // indirect + github.com/ysmood/gson v0.7.3 // indirect + github.com/ysmood/leakless v0.9.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f5d8cc3 --- /dev/null +++ b/go.sum @@ -0,0 +1,22 @@ +github.com/go-rod/rod v0.113.0/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= +github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= +github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= +github.com/go-rod/stealth v0.4.9 h1:X2PmQk4DUF2wzw6GOsWjW/glb8K5ebnftbEvLh7MlZ4= +github.com/go-rod/stealth v0.4.9/go.mod h1:eAzyvw8c0iAd5nJJsSWeh0fQ5z94vCIfdi1hUmYDimc= +github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= +github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= +github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= +github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= +github.com/ysmood/gop v0.0.2/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk= +github.com/ysmood/gop v0.2.0 h1:+tFrG0TWPxT6p9ZaZs+VY+opCvHU8/3Fk6BaNv6kqKg= +github.com/ysmood/gop v0.2.0/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk= +github.com/ysmood/got v0.34.1/go.mod h1:yddyjq/PmAf08RMLSwDjPyCvHvYed+WjHnQxpH851LM= +github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q= +github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg= +github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY= +github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM= +github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= +github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= +github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= +github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU= +github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= diff --git a/libs/browser.go b/libs/browser.go new file mode 100644 index 0000000..bb93daf --- /dev/null +++ b/libs/browser.go @@ -0,0 +1,83 @@ +package libs + +import ( + "sync" + + "github.com/go-rod/rod" +) + +type Browser struct{} + +type BrowserInfo struct { + Id int + Browser *rod.Browser + Url string + Page *rod.Page +} + +// 浏览器指纹数据 +type Fingerprint struct { + Viewport []struct { + Height int + Width int + } + Proxy string + Lang string +} + +var ( + BrowserPool = make(map[int]*BrowserInfo) // 初始化map + poolMutex sync.RWMutex // 添加读写锁保证并发安全 +) + +var ChromeExample Chrome + +func (*Browser) GetBrowser(id int, params *Fingerprint) *BrowserInfo { + poolMutex.RLock() + value, ok := BrowserPool[id] + poolMutex.RUnlock() + + if ok { + return value + } + + // 未找到时获取写锁(互斥) + poolMutex.Lock() + defer poolMutex.Unlock() + + // 双检查:避免在等待锁期间其他goroutine已创建 + if value, ok := BrowserPool[id]; ok { + return value + } + + // 创建新实例(补充CancelFunc) + var ChromeExample Chrome + browser, url, page := ChromeExample.Create(id, params) + browserInfo := &BrowserInfo{ + Id: id, + Browser: browser, + Url: url, + Page: page, + } + BrowserPool[id] = browserInfo + return browserInfo +} + +func (*Browser) GetAllBrowser() map[int]*BrowserInfo { + return BrowserPool +} + +func (*Browser) CancelAllBrowser() { + for _, v := range BrowserPool { + v.Browser.MustClose() + } +} + +func (*Browser) CancelBrowser(id int) { + browserInfo := BrowserPool[id] + if browserInfo == nil { + return + } + browserInfo.Browser.MustClose() + delete(BrowserPool, id) +} diff --git a/libs/chrome.go b/libs/chrome.go new file mode 100644 index 0000000..12c0a56 --- /dev/null +++ b/libs/chrome.go @@ -0,0 +1,89 @@ +package libs + +import ( + "log" + "path/filepath" + "strconv" + + "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/launcher" + "github.com/go-rod/rod/lib/proto" + "github.com/go-rod/stealth" +) + +type Chrome struct{} + +func (c *Chrome) Create(accountId int, params *Fingerprint) (*rod.Browser, string, *rod.Page) { + var accountIdStr = strconv.Itoa(accountId) + userDataDir := "user-data/" + accountIdStr + absPath, _ := filepath.Abs(userDataDir) + log.Printf("用户数据目录: %s", absPath) + path, _ := launcher.LookPath() // 获取当前系统的浏览器目录 + // 判断是否传递代理 + // var proxyHandle utils.ProxyHandle + // protocol, username, password, ip, port, errProxy := proxyHandle.ParseProxy(params.Proxy) + + l := launcher.New(). + Bin(path). + // Proxy("210.51.27.121:50003"). // 直接传入完整认证URL + Delete("use-mock-keychain"). // delete flag "--use-mock-keychain" + Set("disable-blink-features", "AutomationControlled"). // 绕过自动化检测 + // Set("incognito"). // 无痕模式 + Set("user-data-dir", absPath). // 数据持久化目录 + Set("window-size", "1920,1480"). // 窗口尺寸 + Set("disable-infobars", "true"). // 隐藏自动化提示栏 + Set("no-sandbox", "true"). + Set("excludeSwitches", "enable-automation"). + Set("enable-gpu"). // 启用 GPU 加速 + Set("ignore-certificate-errors"). // 忽略证书错误 + Set("use-fake-ui-for-media-stream"). // 允许媒体流 + Set("autoplay-policy", "no-user-gesture-required"). // 自动播放 + Set("ignore-certificate-errors"). + Set("disable-application-cache"). + Set("disable-dev-shm-usage"). + // 禁用webrtc + Set("disable-webrtc", "true"). // 核心禁用参数 + Set("disable-features", "WebRtcHideLocalIpsWithMdns"). // 隐藏本地IP + Set("webrtc-ip-handling-policy", "disable_non_proxied_udp"). // 禁用非代理UDP + Set("force-webrtc-ip-handling-policy"). + Headless(false) // 关闭无头模式 + + // 修改时区 + l.Set("disable-geolocation", "true") // 启用地理定位API + l.Set("disable-web-security", "true") // 允许跨域(某些网站需要) 可以跨域访问iframe标签 + l.Set("disable-notifications", "true") + l.Set("disable-site-isolation-trials", "true") + // if errProxy == nil { + // if strings.Contains(protocol, "http") { + // log.Println(protocol + "://" + ip + ":" + port) + // l = l.Proxy(ip + ":" + port) + // } + // } + + uri := l.MustLaunch() + + browser := rod.New(). + ControlURL(uri). + MustConnect().NoDefaultDevice() + browser.MustIgnoreCertErrors(true) + // if errProxy == nil { + // if strings.Contains(protocol, "http") { + // log.Println(username, password) + // go browser.MustHandleAuth(username, password)() + // } + // } + page := stealth.MustPage(browser) + // page := browser.MustPage() + + go browser.EachEvent(func(e *proto.TargetTargetCreated) { + if e.TargetInfo.Type != proto.TargetTargetInfoTypePage { + return + } + browser.MustPageFromTargetID(e.TargetInfo.TargetID).MustEvalOnNewDocument(stealth.JS) + })() + + // 在页面加载前注入时区覆盖代码 + page.MustSetViewport(1920, 1480, 1.0, false) + + return browser, uri, page +}