package common import ( "errors" "git.listensoft.net/tool/jspkit/common/lxrod" "git.listensoft.net/tool/jspkit/common/models" "git.listensoft.net/tool/jspkit/common/watermark" "git.listensoft.net/tool/jspkit/logger" "git.listensoft.net/tool/jspkit/taxerr" "github.com/go-rod/rod" "github.com/go-rod/rod/lib/input" "github.com/go-rod/rod/lib/proto" "github.com/go-rod/rod/lib/utils" "go.uber.org/zap" "os" "strings" "time" ) func MustHas(page *rod.Page, xpath string) bool { x, _, _ := HasX(page, xpath) return x } func MustHasX(page *rod.Page, xpath string) bool { x, _, _ := HasX(page, xpath) return x } func MustHasXV(page *rod.Page, xpath string) bool { for _, element := range MustElementsX(page, xpath) { visible, _ := element.Visible() if visible { return true } } return false } func MustElementX(page *rod.Page, xpath string) *rod.Element { for i := 0; i < 5; i++ { x, _ := ElementX(page, xpath) if x != nil { return x } utils.Sleep(1) } return nil } func MustHasXV1(page *rod.Page, xpath string) bool { for _, element := range MustElementsX1(page, xpath) { visible, _ := element.Visible() if visible { return true } } return false } func HasX(page *rod.Page, xpath string) (bool, *rod.Element, error) { var x *rod.Element var has bool var err error err = rod.Try(func() { has, x, err = page.HasX(xpath) if has { return } if err != nil { panic(err) } if has { return } iframe := GetAllIframe(page) for _, pg := range iframe { has, x, err = pg.HasX(xpath) if has { return } if err != nil { panic(err) } if has { return } } }) if x != nil { x = x.Timeout(time.Second * 15) } return has, x, err } func ElementX(page *rod.Page, xpath string) (*rod.Element, error) { _, element, err := HasX(page, xpath) if err != nil { err = taxerr.NewWebStuckTitle(false) } return element, err } func GetAllIframe(page *rod.Page) []*rod.Page { fs := make([]*rod.Page, 0) if page.MustHasX(`//iframe`) { for _, element := range page.MustElementsX(`//iframe`) { fs = append(fs, element.MustFrame()) fs = append(fs, GetAllIframe(element.MustFrame())...) } } return fs } func MustElementXV(page *rod.Page, xpath string) *rod.Element { for i := 0; i < 5; i++ { x, _ := ElementsX(page, xpath) for _, element := range x { visible, _ := element.Visible() if visible { return element } } utils.Sleep(1) } return nil } func MustElementsX(page *rod.Page, xpath string) (x []*rod.Element) { for i := 0; i < 5; i++ { x, _ = ElementsX(page, xpath) if len(x) != 0 { break } utils.Sleep(1) } return x } func MustElementsX1(page *rod.Page, xpath string) (x []*rod.Element) { x, _ = ElementsX(page, xpath) return x } func ElementsX(page *rod.Page, xpath string) ([]*rod.Element, error) { var arr []*rod.Element var err error err = rod.Try(func() { r, _ := page.Timeout(ClickTimeOut).ElementsX(xpath) if err != nil { panic(err) } arr = append(arr, r...) for _, pg := range GetAllIframe(page) { pg.MustWaitLoad() r, err = pg.Timeout(ClickTimeOut).ElementsX(xpath) if err != nil { panic(err) } arr = append(arr, r...) } }) return arr, err } func WaitElementX(page *rod.Page, xpath string, interval float64) *rod.Element { for i := 0; i < 60; i++ { if has, el, _ := HasX(page, xpath); has { return el } time.Sleep(time.Duration(float64(time.Second) * interval)) } return nil } func WaitNavigation(page *rod.Page, url string) { navigation := page.Timeout(time.Minute).MustWaitNavigation() page.Timeout(time.Minute).MustNavigate(url) logger.Info("调试埋点11-1") utils.Sleep(1) WaitTimeOut(navigation, time.Minute) logger.Info("埋点11-2") } func WaitTimeOut(f func(), timeout time.Duration) { resultChan := make(chan struct{}, 1) go func() { f() resultChan <- struct{}{} }() select { case <-resultChan: return case <-time.After(timeout): panic(taxerr.NewWebStuckTitle(ComInfo.Cscsts)) } } func Link(p *rod.Page) { go func() { //for { //utils.Sleep(1) if p == nil { return } rod.Try(func() { lxrod.DialogWatch(nil, p) go p.Browser().EachEvent(func(e *proto.TargetTargetCreated) { defer func() { if r := recover(); r != nil { logger.Error("EachPageCreatedEvent recover:", zap.Any("r", r)) } }() if e.TargetInfo.Type != proto.TargetTargetInfoTypePage { return } page := p.Browser().MustPageFromTargetID(e.TargetInfo.TargetID) lxrod.DialogWatch(nil, page) })() // has, _, _ := p.Has("dialog") // if has { // _, _ = p.Eval(` //window.alert = function() {}; //window.confirm = function() { return true; }; //window.prompt = function() {};`) // } }) //} }() } // 有就点 没有就不点击 func MustClick(page *rod.Page, xpath string) { x := MustElementsX(page, xpath) for _, element := range x { visible, _ := element.Visible() if visible { element.MustClick() break } } } func MustText(page *rod.Page, xpath string) string { //去掉左右空格 return strings.TrimSpace(MustElementX(page, xpath).MustText()) } // 输入文字 func Input(p *rod.Page, selector, inputVal string) { err := rod.Try(func() { if inputVal == "" || inputVal == "*" { inputVal = "0" } e := rod.Try(func() { p.Timeout(time.Second).MustSearch(selector).MustSelectAllText().MustFrame().Keyboard.MustType(input.Backspace) }) if e != nil { if w := errors.Unwrap(e); w != nil { logger.Info(w.Error() + "-" + selector + "-" + inputVal) } else { logger.Info(e.Error() + "-" + selector + "-" + inputVal) } } e = rod.Try(func() { p.Timeout(time.Second).MustSearch(selector).MustSelectAllText().MustInput(inputVal) }) if e != nil { if w := errors.Unwrap(e); w != nil { logger.Info(strings.Split(w.Error(), "\t")[0] + "-" + selector + "-" + inputVal) } else { logger.Info(strings.Split(e.Error(), "\t")[0] + "-" + selector + "-" + inputVal) } } }) if err != nil { logger.Info(err.Error() + "-" + selector + "-" + inputVal) } } // 输入文字 func MustInputX(p *rod.Page, xPath, inputVal string) { e := MustElementX(p, xPath) _ = e.ScrollIntoView() e.MustClick().MustSelectAllText().MustInput(inputVal) } // 拦截请求 func PageHijackReq(b *rod.Page, pattern string, ch chan []byte) *rod.HijackRouter { router := b.HijackRequests() router.MustAdd(pattern, func(ctx *rod.Hijack) { rod.Try(func() { ctx.MustLoadResponse() ch <- []byte(ctx.Response.Body()) utils.Sleep(5) select { case <-ch: break } }) }) go router.Run() return router } // 获取拦截请求的值 func GetHijackResp(ch chan []byte, t float64) ([]byte, error) { d := time.Duration(t * float64(time.Second)) select { case val := <-ch: return val, nil case <-time.After(d): return nil, errors.New("请求网页超时,请稍后重试!") } } // WaitForPageLoad 等待页面完全加载,selector 为等待某个元素加载的选择器,可选 func WaitForPageLoad(page *rod.Page, timeoutDuration time.Duration, selector ...string) { start := time.Now() // 1. 等待页面 readyState 为 "complete",加上超时控制 for { readyState := page.MustEval(`() => document.readyState`).String() if readyState == "complete" { break // 页面加载完成,退出循环 } // 检查是否超时 if time.Since(start) > timeoutDuration { break } time.Sleep(500 * time.Millisecond) // 每次检查之间等待一段时间 } // 2. 等待页面元素稳定 page.MustWaitStable() // 3. 如果传入了 selector,等待特定元素加载完成 if len(selector) > 0 { rod.Try(func() { page.Timeout(timeoutDuration).MustElement(selector[0]) // 使用传入的选择器等待元素 }) } // 4. 等待所有网络请求结束 rod.Try(func() { page.Timeout(timeoutDuration).MustWaitIdle() }) utils.Sleep(3) } func WaitHasX(page *rod.Page, xpath string) (x bool) { for i := 0; i < 5; i++ { x, _, _ = HasX(page, xpath) if !x { utils.Sleep(1) } } return x } func SaveErrImg(p *rod.Page, info models.CompanyInfo) string { var check_path string check_path = "./data/sbImg/" + info.TaxNo + "/" if !PathExists(check_path) { os.MkdirAll(check_path, os.ModePerm) } check_path = check_path + info.Period + "-" + time.Now().Format("2006-01-02-15-04-05") + ".png" check_path2 := "" _ = rod.Try(func() { p.Timeout(ClickTimeOut).MustScreenshot(check_path) watermark.Add(check_path) check_path2 = PostSbjt(info.TaxNo, info.Period, check_path) os.Remove(check_path) }) return check_path2 } // InputWithTimeout 规定时间内填入输入值,默认5s func InputWithTimeout(p *rod.Page, selector, inputVal string, timeout ...int64) { var t int64 if len(timeout) == 0 { t = 5 } else { t = timeout[0] } p.Timeout(time.Duration(t) * time.Second).MustSearch(selector).MustSelectAllText().MustInput(inputVal) } func SaveErrImgTask(p *rod.Page, info *models.TaxTask) string { var check_path string check_path = "./data/sbImg/" + info.TaxNo + "/" if !PathExists(check_path) { os.MkdirAll(check_path, os.ModePerm) } check_path = check_path + info.Period + "-" + time.Now().Format("2006-01-02-15-04-05") + ".png" var check_path2 string _ = rod.Try(func() { p.Timeout(ClickTimeOut).MustScreenshot(check_path) watermark.Add(check_path) check_path2 = PostSbjt(info.TaxNo, info.Period, check_path) os.Remove(check_path) }) return check_path2 } // 使用键盘模拟输入 func InputStrNew(page *rod.Page, el *rod.Element, str string) { el.MustScrollIntoView() box := el.MustShape().Box() Click(page, box.X+(box.Width/2), box.Y+(box.Height/2)) time.Sleep(time.Millisecond * 100) selectAll2(page) time.Sleep(time.Millisecond * 100) _ = page.Keyboard.Type(input.Delete) _ = page.Keyboard.Type(input.Backspace) time.Sleep(time.Millisecond * 100) _ = page.Keyboard.Type(input.Backspace) for _, v := range str { _ = page.Keyboard.Type(input.Key(v)) time.Sleep(time.Millisecond * 100) } } func Click(page *rod.Page, x, y float64) { page.Mouse.MustMoveTo(x, y) time.Sleep(time.Millisecond * 100) page.Mouse.MustDown("left") page.Mouse.MustUp("left") } func selectAll2(page *rod.Page) { page.Keyboard.MustType(input.ControlLeft).MustType('a').MustType('a').MustType(input.ControlLeft) } // 输入文字Str func InputStr(p *rod.Page, selector, inputVal string) { err := rod.Try(func() { e := rod.Try(func() { p.Timeout(time.Duration(1 * float64(time.Second))).MustSearch(selector).MustSelectAllText().MustFrame().Keyboard.MustType(input.Backspace) }) if e != nil { logger.Info(e.Error() + "-" + selector + "-" + inputVal) } e = rod.Try(func() { p.Timeout(time.Duration(1 * float64(time.Second))).MustSearch(selector).MustSelectAllText().MustInput(inputVal) }) if e != nil { logger.Info(strings.Split(e.Error(), "\t")[0] + "-" + selector + "-" + inputVal) } }) if err != nil { logger.Info(err.Error() + "-" + selector + "-" + inputVal) } } // 输入文字 string func InputElementXStr(p *rod.Page, xPath, inputVal string) { elementX := MustElementX(p, xPath) disabled := elementX.MustAttribute("disabled") if disabled != nil { return } readonly := elementX.MustAttribute("readonly") if readonly != nil { return } elementX.MustSelectAllText().MustInput(inputVal) } func WaitElementXFoTimesNil(page *rod.Page, xpath string, times int) *rod.Element { for i := 0; i < times; i++ { if has, el, _ := HasX(page, xpath); has && MustElementX(page, xpath).MustVisible() { return el } time.Sleep(time.Second) } return nil } func MustElementX10(page *rod.Page, xpath string) *rod.Element { for i := 0; i < 10; i++ { x, _ := ElementX(page, xpath) if x != nil { return x } utils.Sleep(1) } return nil } func MustElementX15(page *rod.Page, xpath string) *rod.Element { for i := 0; i < 15; i++ { x, _ := ElementX(page, xpath) if x != nil { return x } utils.Sleep(1) } return nil } func MustHasXV30(page *rod.Page, xpath string) bool { for _, element := range MustElementsX30(page, xpath) { visible, _ := element.Visible() if visible { return true } } return false } func MustElementsX30(page *rod.Page, xpath string) (x []*rod.Element) { for i := 0; i < 30; i++ { x, _ = ElementsX(page, xpath) if len(x) != 0 { break } utils.Sleep(1) } return x } func WaitElementXFoTimes(page *rod.Page, xpath string, times int) *rod.Element { for i := 0; i < times; i++ { if has, el, _ := HasX(page, xpath); has && MustElementX(page, xpath).MustVisible() { return el } time.Sleep(time.Second) } logger.Info("页面加载失败元素未找到,请稍后再试", xpath) panic(taxerr.NewWebStuckTitle(InfoCscsts)) } func MustElementsX10(page *rod.Page, xpath string) (x []*rod.Element) { for i := 0; i < 10; i++ { x, _ = ElementsX(page, xpath) if len(x) != 0 { break } utils.Sleep(1) } return x } func WaitMustElementsX(page *rod.Page, xpath string) (elementsX []*rod.Element) { for i := 0; i < 5; i++ { elementsX = MustElementsX(page, xpath) if len(elementsX) != 0 { return } utils.Sleep(1) } return } func ClickB(page *rod.Page, el string) { box := MustElementX(page, el).MustShape().Box() Click(page, box.X+(box.Width/2), box.Y+(box.Height/2)) } func WaitElementX10(page *rod.Page, xpath string) *rod.Element { return WaitElementXFoTimes(page, xpath, 10) } func MustElementX30(page *rod.Page, xpath string) *rod.Element { for i := 0; i < 30; i++ { x, _ := ElementX(page, xpath) if x != nil { return x } utils.Sleep(1) } return nil } func WaitHasX10(page *rod.Page, xpath string) (x bool) { for i := 0; i < 10; i++ { x, _, _ = HasX(page, xpath) if !x { utils.Sleep(1) } } return x } // 返回当前元素下一个元素的text 如果没有元素就直接返回空 func MustNextText(page *rod.Page, xpath string) string { x := MustElementXV(page, xpath) if x == nil { return "" } return x.MustNext().MustText() } // 2033年12月31日 // 2033-12-31 func DataFormat(data string) string { strings.ReplaceAll(data, "年", "-") strings.ReplaceAll(data, "月", "-") strings.ReplaceAll(data, "日", "") if len(data) > 10 { data = data[:10] } return data } // 返回当前元素下一个元素的text 如果没有元素就直接返回空 func MustNext2Text(page *rod.Page, xpath string) string { x := MustElementXV(page, xpath) if x == nil { return "" } return x.MustNext().MustNext().MustText() } // 拦截 func HijackReq(page *rod.Page, uri, xPath string) []byte { ch := make(chan []byte) r := PageHijackReq(page, uri, ch) MustElementX(page, xPath).MustClick() data, err := GetHijackResp(ch, 10) if err != nil { panic(taxerr.NewWebStuckTitle(false)) } _ = r.Stop() return data } // 输入文字 float func InputElementX(p *rod.Page, xPath, inputVal string) { disabled := MustElementX(p, xPath).MustAttribute("disabled") if disabled != nil { return } readonly := MustElementX(p, xPath).MustAttribute("readonly") if readonly != nil { return } float := StrToFloat(inputVal) if float == 0 { inputVal = "" } else { inputVal = FloatToStr(float) } MustElementX(p, xPath).MustSelectAllText().MustInput(inputVal) } func GetText(page *rod.Page, selector string) string { return page.Timeout(ClickTimeOut).MustSearch(selector).MustText() }