study_xxqg/lib/core.go

300 lines
7.2 KiB
Go
Raw Normal View History

2021-11-12 07:46:33 +00:00
package lib
import (
"bytes"
"encoding/base64"
"errors"
2021-11-12 07:46:33 +00:00
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"io"
2021-11-12 07:46:33 +00:00
"os"
"strings"
"time"
2021-11-12 07:46:33 +00:00
qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go"
"github.com/mxschmitt/playwright-go"
"github.com/nfnt/resize"
2021-11-12 07:46:33 +00:00
log "github.com/sirupsen/logrus"
"github.com/tuotoo/qrcode"
"golang.org/x/image/bmp"
2021-11-12 07:46:33 +00:00
)
type Core struct {
2021-11-12 08:44:19 +00:00
pw *playwright.Playwright
browser playwright.Browser
context *playwright.BrowserContext
2021-11-12 08:44:19 +00:00
ShowBrowser bool
Push func(kind string, message string)
2021-11-12 07:46:33 +00:00
}
type Cookie struct {
2021-11-12 07:46:33 +00:00
Name string `json:"name" yaml:"name"`
Value string `json:"value" yaml:"value"`
Domain string `json:"domain" yaml:"domain"`
Path string `json:"path" yaml:"path"`
Expires int `json:"expires" yaml:"expires"`
HTTPOnly bool `json:"httpOnly" yaml:"http_only"`
Secure bool `json:"secure" yaml:"secure"`
SameSite string `json:"same_site" yaml:"same_site"`
}
func (c *Core) Init() {
pwt, err := playwright.Run()
if err != nil {
log.Errorln("[core]", "初始化playwright失败")
log.Errorln("[core] ", err.Error())
return
}
c.pw = pwt
browser, err := pwt.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
Args: []string{
"--disable-extensions",
"--disable-gpu",
"--no-sandbox",
"--window-size=500,450",
2021-11-12 07:46:33 +00:00
"--start-maximized",
"--mute-audio",
"--window-position=0,0",
"--ignore-certificate-errors",
"--ignore-ssl-errors",
"--disable-features=RendererCodeIntegrity",
"--disable-blink-features",
"--disable-blink-features=AutomationControlled",
},
Channel: nil,
ChromiumSandbox: nil,
Devtools: nil,
DownloadsPath: nil,
ExecutablePath: nil,
HandleSIGHUP: nil,
HandleSIGINT: nil,
HandleSIGTERM: nil,
Headless: playwright.Bool(!c.ShowBrowser),
2021-11-12 07:46:33 +00:00
Proxy: nil,
SlowMo: nil,
Timeout: nil,
})
if err != nil {
log.Errorln("[core] ", "初始化chrome失败")
log.Errorln("[core] ", err.Error())
return
}
c.browser = browser
context, err := c.browser.NewContext()
if err != nil {
return
}
c.context = &context
2021-11-12 07:46:33 +00:00
}
func (c *Core) Quit() {
err := (*c.context).Close()
2021-11-12 07:46:33 +00:00
if err != nil {
return
}
err = c.browser.Close()
if err != nil {
return
}
err = c.pw.Stop()
if err != nil {
return
}
}
func (c *Core) Login() ([]Cookie, error) {
page, err := (*c.context).NewPage()
2021-11-12 07:46:33 +00:00
if err != nil {
return nil, err
}
_, err = page.Goto("https://pc.xuexi.cn/points/login.html", playwright.PageGotoOptions{
Referer: nil,
Timeout: playwright.Float(30000),
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
})
if err != nil {
log.Errorln("[core] ", "打开登录页面失败")
log.Errorln("[core] ", err.Error())
return nil, err
}
log.Infoln("[core] ", "正在等待二维码加载")
2021-11-12 07:46:33 +00:00
_, _ = page.WaitForSelector(`#app > div > div.login_content > div > div.login_qrcode `)
_, err = page.Evaluate(`let h = document.body.scrollWidth/2;document.documentElement.scrollTop=h;`)
if err != nil {
fmt.Println(err.Error())
return nil, err
}
log.Infoln("[core] ", "加载验证码中,请耐心等待")
frame := page.Frame(playwright.PageFrameOptions{
Name: playwright.String(`ddlogin-iframe`),
URL: nil,
})
if frame == nil {
log.Errorln("获取frame失败")
}
removeNode(page)
2021-11-12 07:46:33 +00:00
selector, err := frame.QuerySelector(`img`)
if err != nil {
log.Errorln(err.Error())
return nil, err
}
img, err := selector.GetAttribute(`src`)
if err != nil {
log.Errorln(err.Error())
return nil, err
}
screen, _ := page.Screenshot()
var result []byte
buffer := bytes.NewBuffer(result)
_ = Clip(bytes.NewReader(screen), buffer, 0, 0, 525, 35, 755, 255, 0)
c.Push("markdown", fmt.Sprintf("![screenshot](%v) \n>点开查看登录二维码\n>请在五分钟内完成扫码", "data:image/png;base64,"+base64.StdEncoding.EncodeToString(buffer.Bytes())))
os.WriteFile("screen.png", buffer.Bytes(), 0666)
2021-11-12 07:46:33 +00:00
img = strings.ReplaceAll(img, "data:image/png;base64,", "")
data, err := base64.StdEncoding.DecodeString(img)
if err != nil {
return nil, err
}
2021-11-12 07:46:33 +00:00
os.WriteFile("qrcode.png", data, 0666)
matrix, err := qrcode.Decode(bytes.NewReader(data))
if err != nil {
return nil, err
}
qrcodeTerminal.New().Get(matrix.Content).Print()
_, err = page.WaitForNavigation(playwright.PageWaitForNavigationOptions{
Timeout: playwright.Float(30 * 1000 * 5),
URL: nil,
WaitUntil: nil,
})
if err != nil {
log.Errorln(err.Error())
return nil, err
}
cookies, err := (*c.context).Cookies() //nolint:wsl
2021-11-12 07:46:33 +00:00
if err != nil {
log.Errorln("[core] ", "获取cookie失败")
return nil, err
}
var (
cos []Cookie
2021-11-12 07:46:33 +00:00
)
for _, c := range cookies {
co := Cookie{}
2021-11-12 07:46:33 +00:00
co.Name = c.Name
co.Path = c.Path
co.Value = c.Value
co.Domain = c.Domain
co.Expires = c.Expires
co.HTTPOnly = c.HttpOnly
co.SameSite = c.SameSite
co.Secure = c.Secure
cos = append(cos, co)
}
info, nick, err := GetUserInfo(cos)
if err != nil {
return nil, err
}
c.Push("text", "登录成功,用户名:"+nick)
2021-11-12 07:46:33 +00:00
err = SaveUser(User{
Cookies: cos,
Nick: nick,
Uid: info,
Time: time.Now().Add(time.Hour * 24).Unix(),
2021-11-12 07:46:33 +00:00
})
if err != nil {
return nil, err
}
return cos, err
}
func removeNode(page playwright.Page) {
page.Evaluate(`document.getElementsByClassName("layout-header")[0].remove()`) //nolint:errcheck
page.Evaluate(`document.getElementsByClassName("layout-footer")[0].remove()`) //nolint:errcheck
page.Evaluate(`document.getElementsByClassName("redflag-2")[0].remove()`) //nolint:errcheck
page.Evaluate(`document.getElementsByClassName("ddlogintext")[0].remove()`) //nolint:errcheck
}
// Clip
//* 图片裁剪
//* 入参:图片输入、输出、缩略图宽、缩略图高、Rectangle{Pt(x0, y0), Pt(x1, y1)},精度
//* 规则:如果精度为0则精度保持不变
//*
//* 返回:error
// */
func Clip(in io.Reader, out io.Writer, wi, hi, x0, y0, x1, y1, quality int) (err error) {
err = errors.New("unknow error")
defer func() {
if r := recover(); r != nil {
log.Println(r)
}
}()
var origin image.Image
var fm string
origin, fm, err = image.Decode(in)
if err != nil {
log.Println(err)
return err
}
if wi == 0 || hi == 0 {
wi = origin.Bounds().Max.X
hi = origin.Bounds().Max.Y
}
var canvas image.Image
if wi != origin.Bounds().Max.X {
//先缩略
canvas = resize.Thumbnail(uint(wi), uint(hi), origin, resize.Lanczos3)
} else {
canvas = origin
}
switch fm {
case "jpeg":
img := canvas.(*image.YCbCr)
subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.YCbCr)
return jpeg.Encode(out, subImg, &jpeg.Options{quality})
case "png":
switch canvas.(type) {
case *image.NRGBA:
img := canvas.(*image.NRGBA)
subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.NRGBA)
return png.Encode(out, subImg)
case *image.RGBA:
img := canvas.(*image.RGBA)
subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.RGBA)
return png.Encode(out, subImg)
}
case "gif":
img := canvas.(*image.Paletted)
subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.Paletted)
return gif.Encode(out, subImg, &gif.Options{})
case "bmp":
img := canvas.(*image.RGBA)
subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.RGBA)
return bmp.Encode(out, subImg)
default:
return errors.New("ERROR FORMAT")
}
return nil
}