|
|
@@ -1,14 +1,19 @@
|
|
|
package tool_controller
|
|
|
|
|
|
import (
|
|
|
+ "bytes"
|
|
|
"context"
|
|
|
"fmt"
|
|
|
+ "image"
|
|
|
+ _ "image/jpeg"
|
|
|
+ _ "image/png"
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
"github.com/chromedp/chromedp"
|
|
|
|
|
|
// "os"
|
|
|
+ "net/http"
|
|
|
"net/url"
|
|
|
// "strings"
|
|
|
|
|
|
@@ -77,24 +82,25 @@ func (self *ToolController) GetHaibaoWithGoogle() {
|
|
|
defer cancel()
|
|
|
|
|
|
// 运行任务(导航到网页,并捕获屏幕截图)
|
|
|
- var buf []byte
|
|
|
err = chromedp.Run(ctx,
|
|
|
chromedp.EmulateViewport(1400, 800), // 设置视口宽度为 1400,高度为 800
|
|
|
chromedp.Navigate(decodedUri), // 替换为你想截图的网页地址
|
|
|
- //chromedp.WaitReady("body", chromedp.ByQuery), // 等待页面的 <body> 元素加载完成
|
|
|
- chromedp.WaitReady("#overload", chromedp.ByID),
|
|
|
- //chromedp.Sleep(5*time.Second),
|
|
|
- // chromedp.FullScreenshot(&buf, 90), // 调整质量参数
|
|
|
- chromedp.FullScreenshot(&buf, 60), // 调整质量参数
|
|
|
+ chromedp.WaitReady("body", chromedp.ByQuery),
|
|
|
)
|
|
|
if err != nil {
|
|
|
beego.BeeLogger.Error("GetHaibaoWithGoogle screenshot failed: err=[%s] url=[%s]", err, maskURLForLog(decodedUri))
|
|
|
self.ReturnError(504, apps.NetworkBusy, "", nil)
|
|
|
return
|
|
|
}
|
|
|
+ buf, err := captureNonBlankScreenshot(ctx, maskURLForLog(decodedUri), 60)
|
|
|
+ if err != nil {
|
|
|
+ beego.BeeLogger.Error("GetHaibaoWithGoogle screenshot failed: err=[%s] url=[%s]", err, maskURLForLog(decodedUri))
|
|
|
+ self.ReturnError(504, apps.NetworkBusy, "", nil)
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
beego.BeeLogger.Info("GetHaibaoWithGoogle success url=[%s] bytes=[%d]", maskURLForLog(decodedUri), len(buf))
|
|
|
- self.Ctx.Output.Header("Content-Type", "image/png")
|
|
|
+ self.Ctx.Output.Header("Content-Type", http.DetectContentType(buf))
|
|
|
self.Ctx.Output.Body(buf)
|
|
|
|
|
|
//log.Println("Screenshot saved as screenshot.png")
|
|
|
@@ -122,23 +128,25 @@ func (self *ToolController) GetOtherHaibaoWithGoogle() {
|
|
|
defer cancel()
|
|
|
|
|
|
// 运行任务(导航到网页,并捕获屏幕截图)
|
|
|
- var buf []byte
|
|
|
err = chromedp.Run(ctx,
|
|
|
chromedp.EmulateViewport(1400, 800), // 设置视口宽度为 1400,高度为 800
|
|
|
chromedp.Navigate(decodedUri), // 替换为你想截图的网页地址
|
|
|
chromedp.WaitReady("body", chromedp.ByQuery), // 等待页面的 <body> 元素加载完成
|
|
|
- //chromedp.WaitReady("#overload", chromedp.ByID),
|
|
|
- chromedp.Sleep(5*time.Second),
|
|
|
- chromedp.FullScreenshot(&buf, 90), // 调整质量参数
|
|
|
)
|
|
|
if err != nil {
|
|
|
beego.BeeLogger.Error("GetOtherHaibaoWithGoogle screenshot failed: err=[%s] url=[%s]", err, maskURLForLog(decodedUri))
|
|
|
self.ReturnError(504, apps.NetworkBusy, "", nil)
|
|
|
return
|
|
|
}
|
|
|
+ buf, err := captureNonBlankScreenshot(ctx, maskURLForLog(decodedUri), 90)
|
|
|
+ if err != nil {
|
|
|
+ beego.BeeLogger.Error("GetOtherHaibaoWithGoogle screenshot failed: err=[%s] url=[%s]", err, maskURLForLog(decodedUri))
|
|
|
+ self.ReturnError(504, apps.NetworkBusy, "", nil)
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
beego.BeeLogger.Info("GetOtherHaibaoWithGoogle success url=[%s] bytes=[%d]", maskURLForLog(decodedUri), len(buf))
|
|
|
- self.Ctx.Output.Header("Content-Type", "image/png")
|
|
|
+ self.Ctx.Output.Header("Content-Type", http.DetectContentType(buf))
|
|
|
self.Ctx.Output.Body(buf)
|
|
|
|
|
|
//log.Println("Screenshot saved as screenshot.png")
|
|
|
@@ -206,8 +214,73 @@ func maskURLForLog(rawURL string) string {
|
|
|
func chromedpErrorLogf(format string, args ...interface{}) {
|
|
|
msg := fmt.Sprintf(format, args...)
|
|
|
if strings.Contains(msg, "could not unmarshal event") {
|
|
|
- beego.BeeLogger.Warning("chromedp ignored protocol event: %s", msg)
|
|
|
return
|
|
|
}
|
|
|
beego.BeeLogger.Error("chromedp error: %s", msg)
|
|
|
}
|
|
|
+
|
|
|
+func captureNonBlankScreenshot(ctx context.Context, safeURL string, quality int) ([]byte, error) {
|
|
|
+ waitPlan := []time.Duration{
|
|
|
+ 3 * time.Second,
|
|
|
+ 3 * time.Second,
|
|
|
+ 5 * time.Second,
|
|
|
+ 8 * time.Second,
|
|
|
+ 10 * time.Second,
|
|
|
+ }
|
|
|
+ var last []byte
|
|
|
+ for attempt, wait := range waitPlan {
|
|
|
+ var buf []byte
|
|
|
+ if err := chromedp.Run(ctx,
|
|
|
+ chromedp.Sleep(wait),
|
|
|
+ chromedp.FullScreenshot(&buf, quality),
|
|
|
+ ); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ last = buf
|
|
|
+ if !isBlankScreenshot(buf) {
|
|
|
+ if attempt > 0 {
|
|
|
+ beego.BeeLogger.Info("haibao screenshot ready after retry url=[%s] attempt=[%d] bytes=[%d]", safeURL, attempt+1, len(buf))
|
|
|
+ }
|
|
|
+ return buf, nil
|
|
|
+ }
|
|
|
+ beego.BeeLogger.Warning("haibao screenshot blank, retry url=[%s] attempt=[%d] bytes=[%d]", safeURL, attempt+1, len(buf))
|
|
|
+ }
|
|
|
+ return nil, fmt.Errorf("screenshot stayed blank after retries, last_bytes=%d", len(last))
|
|
|
+}
|
|
|
+
|
|
|
+func isBlankScreenshot(data []byte) bool {
|
|
|
+ if len(data) == 0 {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ img, _, err := image.Decode(bytes.NewReader(data))
|
|
|
+ if err != nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ bounds := img.Bounds()
|
|
|
+ width := bounds.Dx()
|
|
|
+ height := bounds.Dy()
|
|
|
+ if width <= 0 || height <= 0 {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ stepX := maxInt(width/90, 1)
|
|
|
+ stepY := maxInt(height/90, 1)
|
|
|
+ total := 0
|
|
|
+ nonWhite := 0
|
|
|
+ for y := bounds.Min.Y; y < bounds.Max.Y; y += stepY {
|
|
|
+ for x := bounds.Min.X; x < bounds.Max.X; x += stepX {
|
|
|
+ r, g, b, _ := img.At(x, y).RGBA()
|
|
|
+ total++
|
|
|
+ if uint8(r>>8) < 245 || uint8(g>>8) < 245 || uint8(b>>8) < 245 {
|
|
|
+ nonWhite++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return total == 0 || float64(nonWhite)/float64(total) < 0.001
|
|
|
+}
|
|
|
+
|
|
|
+func maxInt(a, b int) int {
|
|
|
+ if a > b {
|
|
|
+ return a
|
|
|
+ }
|
|
|
+ return b
|
|
|
+}
|