如果您是站长,如果您的网站需要支付模块,那你一定懂我在说什么。
爬虫使用Glang编写,采用了chromedp库,运行依赖于chrome/chromium(运行时不需要安装桌面环境,最小化系统即可运行,使用浏览器无头模式)。
喜欢请支持,给个评论再走。
看图:
上代码:
package main import ( "bytes" "context" "errors" "fmt" "image" "log" "regexp" "strconv" "strings" "time" "github.com/chromedp/cdproto/cdp" "github.com/chromedp/chromedp" "github.com/makiuchi-d/gozxing" "github.com/makiuchi-d/gozxing/qrcode" goQrcode "github.com/skip2/go-qrcode" ) var ( timeOut int = 60 // 响应超时时间 live int = 500 // 保活刷新频率 ) func main() { // chromdp依赖context上限传递参数 ctx, _ := chromedp.NewExecAllocator( context.Background(), // 以默认配置的数组为基础,覆写headless参数 // 当然也可以根据自己的需要进行修改,这个flag是浏览器的设置 append( chromedp.DefaultExecAllocatorOptions[:], //chromedp.Flag("headless", false), )..., ) // 创建新的chromedp上下文对象,超时时间的设置不分先后 // 注意第二个返回的参数是cancel(),只是我省略了 ctx, _ = context.WithTimeout(ctx, time.Duration(timeOut)*time.Second) ctx, _ = chromedp.NewContext( ctx, // 设置日志方法 chromedp.WithLogf(log.Printf), ) // 通常可以使用 defer cancel() 去取消 // 但是在Windows环境下,我们希望程序能顺带关闭掉浏览器 // 如果不希望浏览器关闭,使用cancel()方法即可 // defer cancel() // defer chromedp.Cancel(ctx) // 执行我们自定义的任务 - myTasks函数在第4步 if err := chromedp.Run(ctx, Tasks()); err != nil { log.Print(err) } } // 开始你的自定义任务 func Tasks() chromedp.ActionFunc { // 返回一个函数类型到chromedp.Run return func(ctx context.Context) (err error) { var loginStat []*cdp.Node URL := "https://consumeprod.alipay.com/record/advanced.htm" // 打开登录页面 chromedp.Navigate(URL).Do(ctx) // 获取登录二维码,参数2位元素selector,参数二位描述信息,展示在二维码下方 getCode(ctx, "#J-authcenter > div.authcenter-body.fn-clear", "请使用支付宝客户端扫码登录,") // 等待用户扫码,n秒后开始验证 //chromedp.Sleep(2 * time.Second).Do(ctx) time.Sleep(2 * time.Second) //确认登录状 for { time.Sleep(1 * time.Second) // 检查当前页面是否存在该元素,不存在返回0(检查登录页内容) chromedp.Nodes("#J-qrcode-body", &loginStat, chromedp.AtLeast(0)).Do(ctx) // 判断是否还停留在登录页面 if len(loginStat) == 0 { fmt.Println("已确认登录") // 检查是否需要二次扫码验证 time.Sleep(3 * time.Second) chromedp.Nodes("#hover-instructions > img", &loginStat, chromedp.AtLeast(0)).Do(ctx) // 需要二次扫码验证 if len(loginStat) != 0 { getCode(ctx, "#main-containor", "请再次扫码进行安全验证,") // 检查二次扫码验证是否通过 for len(loginStat) != 0 { time.Sleep(1 * time.Second) chromedp.Nodes("#hover-instructions > img", &loginStat, chromedp.AtLeast(0)).Do(ctx) } } break } } // 判断是否进入账单页面 time.Sleep(3 * time.Second) chromedp.Nodes("#main > div.ui-title.fn-clear > h2", &loginStat, chromedp.AtLeast(0)).Do(ctx) if len(loginStat) == 0 { return errors.New("error: 登录失败!") } // 到此已经登录成功,下面进行保活操作 go alive(ctx) //对外提供服务的借口,可以在此使用gin框架搭建web服务对外提供访问 // 需要注意的是此处代码推出后,保活进程也将推出 for { readBill(ctx, "-96h", false) time.Sleep(10 * time.Second) } } } // 读取账单 // pastTime: 查询多少时间内的订单("-24h"), coodplay: 是否只展示二维码收款内容接受bool值 func readBill(ctx context.Context, pastTime string, codePlay bool) { var ( day string times string name string number string money string status string ) // 设置正则匹配关键字 re, _ := regexp.Compile("<.*?>") // 更新页面数据 chromedp.Click("#globalContainer > div.global-common-a > div > div.global-header.fn-clear > div > ul > li.global-nav-item.global-nav-item-current > a").Do(ctx) // 开始获取所有关键字 for id := 10; id > 0; id-- { // 检查账单类型,账单名字 chromedp.OuterHTML("#J-item-"+fmt.Sprint(id)+" > td.name > p", &name).Do(ctx) name := strings.TrimSpace(re.ReplaceAllString(name, "")) // 如果账单类型不是收钱吗首款,则不往下执行,进入下一次循环(变量codePlay参数为true生效) if codePlay && name != "收钱码收款" { continue } // 获取指定时间范围内的确切时间 d, _ := time.ParseDuration(pastTime) oldDay := string(time.Now().Add(d).Format("20060102")) oldTime := string(time.Now().Add(d).Format("1504")) oldDT, _ := strconv.Atoi(oldDay + oldTime) // 检查账单日期和时间 chromedp.OuterHTML("#J-item-"+fmt.Sprint(id)+" > td.time > p.time-d", &day).Do(ctx) chromedp.OuterHTML("#J-item-"+fmt.Sprint(id)+" > td.time > p.time-h.ft-gray", ×).Do(ctx) day := strings.TrimSpace(re.ReplaceAllString(day, "")) times := strings.TrimSpace(re.ReplaceAllString(times, "")) //账单日期和时间转换成数字,用于比较时间范围 fmtDay := strings.Replace(day, ".", "", -1) fmtTimes := strings.Replace(times, ":", "", 1) fmtDT, _ := strconv.Atoi(fmtDay + fmtTimes) // 如果账单日起不是今天的,则不往下执行,进入下一次循环 if fmtDT < oldDT { continue } // 查询其他信息 chromedp.OuterHTML("#J-item-"+fmt.Sprint(id)+" > td.tradeNo.ft-gray > p", &number).Do(ctx) chromedp.OuterHTML("#J-item-"+fmt.Sprint(id)+" > td.amount > span", &money).Do(ctx) chromedp.OuterHTML("#J-item-"+fmt.Sprint(id)+" > td.status > p:nth-child(1)", &status).Do(ctx) // 截取关键字 number := strings.TrimSpace(re.ReplaceAllString(number, "")) money := strings.TrimSpace(re.ReplaceAllString(money, "")) status := strings.TrimSpace(re.ReplaceAllString(status, "")) fmt.Println(day, times, name, number, money, status) } //time.Sleep(time.Duration(live) * time.Second) // 重新加载,保活机制 //chromedp.Click("#globalContainer > div.global-common-a > div > div.global-header.fn-clear > div > ul > li.global-nav-item.global-nav-item-current > a").Do(ctx) } // 获取登录二维码 func getCode(ctx context.Context, wbpath string, comment string) (err error) { // 0. 等待页面渲染 time.Sleep(1 * time.Second) // 1. 用于存储图片的字节切片 var code []byte // 2. 截图 // 注意这里需要注明直接使用ID选择器来获取元素(chromedp.ByID) if err = chromedp.Screenshot(wbpath, &code).Do(ctx); err != nil { return err } // // 3. 保存图片到文件 // if err = ioutil.WriteFile("code.png", code, 0755); err != nil { // return err // } // 打印二维码 和 通知信息到终端 printCode(code) fmt.Printf("%v 超时时间:%ds\n", comment, timeOut) return } // 将byte流格式的二维码图片打印到终端 func printCode(code []byte) (err error) { // 1. 因为我们的字节流是图像,所以我们需要先解码字节流 img, _, err := image.Decode(bytes.NewReader(code)) if err != nil { return err } // 2. 然后使用gozxing库解码图片获取二进制位图 bmp, err := gozxing.NewBinaryBitmapFromImage(img) if err != nil { return err } // 3. 用二进制位图解码获取gozxing的二维码对象 res, err := qrcode.NewQRCodeReader().Decode(bmp, nil) if err != nil { return err } // 4. 用结果来获取go-qrcode对象(注意这里我用了库的别名) qr, err := goQrcode.New(res.String(), goQrcode.High) if err != nil { return } stringCode := qr.ToSmallString(false) // 5. 输出到标准输出流 fmt.Println(stringCode) return } func alive(ctx context.Context) { for { // 重新加载,保活机制 time.Sleep(time.Duration(live) * time.Second) chromedp.Click("#globalContainer > div.global-common-a > div > div.global-header.fn-clear > div > ul > li.global-nav-item.global-nav-item-current > a").Do(ctx) } }
占楼
如果还有需要,请尝试使用chrome浏览器打开连接,然后扫码登录,并详细记录您的操作步骤回复我谢谢
Featured Collection
Popular Ranking
Popular Events
如果您是站长,如果您的网站需要支付模块,那你一定懂我在说什么。
爬虫使用Glang编写,采用了chromedp库,运行依赖于chrome/chromium(运行时不需要安装桌面环境,最小化系统即可运行,使用浏览器无头模式)。
喜欢请支持
,给个评论再走。
看图:
上代码: