【網站內容安全檢測】之3:獲取所有外部域名訪問后圖像

Go語言調用Chrome瀏覽器去進行截圖的操作,對電腦的性能要求比較高,所以速度比較有限,但是目前來看這種方式可以最佳的去獲取網頁加載后的結果。

main.go

package mainimport ("context""errors""flag""fmt""io/ioutil""log""net/url""os""path/filepath""strings""sync""sync/atomic""time""github.com/chromedp/chromedp"
)// 任務結構
type Task struct {URL      stringFilename string
}// 域名黑名單,包含關鍵字的域名將被跳過
var blacklist = []string{"edu.cn", "gov.cn"}var (totalTasks    int64 // 總任務數finishedTasks int64 // 已完成任務數
)func main() {start := time.Now()defer func() {if r := recover(); r != nil {log.Printf("程序異常退出: %v", r)}}()// 定義命令行參數,增加初始等待時間參數urlFile := flag.String("urls", "urls.txt", "包含URL列表的文件路徑")outputDir := flag.String("output", "screenshots", "截圖保存的目錄")workers := flag.Int("workers", 50, "并發工作線程數(建議1~3)")width := flag.Int("width", 1280, "瀏覽器窗口寬度")height := flag.Int("height", 800, "瀏覽器窗口高度")fullPage := flag.Bool("full", false, "是否截取整個頁面")timeout := flag.Int("timeout", 20, "每個任務的超時時間(秒,建議大于頁面加載等待時間,默認120)")retry := flag.Int("retry", 3, "失敗重試次數")initialWait := flag.Int("initialWait", 1, "初始等待時間(秒),用于分散任務啟動")flag.Parse()// 確保timeout參數合理if *timeout <= 30 {log.Printf("警告:timeout參數過小,已自動調整為60秒以避免context canceled錯誤!")*timeout = 60}// 創建輸出目錄if _, err := os.Stat(*outputDir); os.IsNotExist(err) {if err := os.MkdirAll(*outputDir, 0755); err != nil {log.Fatalf("創建輸出目錄失敗: %v", err)}}// 讀取URL列表urls, err := readURLs(*urlFile)if err != nil {log.Fatalf("讀取URL文件失敗: %v", err)}if len(urls) == 0 {log.Fatal("URL列表為空")}// 統計總任務數totalTasks = int64(len(urls))// 創建任務通道,增加緩沖大小taskCh := make(chan Task, len(urls))// 填充任務通道go func() {for _, url := range urls {// 生成文件名filename := generateFilename(url, *outputDir)taskCh <- Task{URL: url, Filename: filename}}close(taskCh)}()// 創建等待組var wg sync.WaitGroup// 啟動進度監控協程go func() {startTime := time.Now()for {done := atomic.LoadInt64(&finishedTasks)total := totalTaskselapsed := time.Since(startTime).Seconds()var speed float64 = 0if elapsed > 0 {speed = float64(done) / elapsed}remain := 0.0if speed > 0 {remain = float64(total-done) / speed}percent := float64(done) / float64(total) * 100fmt.Printf("\r進度: %d/%d (%.2f%%) | 速度: %.2f/秒 | 已用: %.0fs | 預計剩余: %.0fs",done, total, percent, speed, elapsed, remain)if done >= total {fmt.Println()break}time.Sleep(1 * time.Second)}}()// 啟動工作線程,增加啟動間隔log.Printf("開始處理 %d 個URL,使用 %d 個工作線程\n", len(urls), *workers)for i := 0; i < *workers; i++ {// 增加啟動間隔,避免同時啟動過多線程time.Sleep(time.Duration(i*(*initialWait)) * time.Second)wg.Add(1)go func(workerID int) {defer wg.Done()processTasks(workerID, taskCh, *width, *height, *fullPage, *timeout, *retry)}(i)}// 等待所有工作線程完成wg.Wait()elapsed := time.Since(start)log.Printf("所有任務完成,耗時: %s\n", elapsed)
}// 讀取URL文件
func readURLs(filePath string) ([]string, error) {data, err := ioutil.ReadFile(filePath)if err != nil {return nil, err}// 按行分割URLvar urls []stringlines := strings.Split(string(data), "\n")for _, line := range lines {if url := strings.TrimSpace(line); url != "" {if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {url = "https://" + url}// 檢查黑名單blacklisted := falsefor _, keyword := range blacklist {if strings.Contains(url, keyword) {blacklisted = truebreak}}if blacklisted {continue}urls = append(urls, url)}}return urls, nil
}// 生成文件名
func generateFilename(urlStr, outputDir string) string {// 移除URL中的協議部分u, err := url.Parse(urlStr)if err != nil {// 如果解析失敗,使用時間戳作為文件名return filepath.Join(outputDir, fmt.Sprintf("unknown_%d.png", time.Now().UnixNano()))}// 使用主機名和路徑生成文件名filename := strings.ReplaceAll(u.Host+u.Path, "/", "_")if len(filename) > 100 {filename = filename[:100]}return filepath.Join(outputDir, filename+".png")
}// 處理任務
func processTasks(workerID int, taskCh <-chan Task, width, height int, fullPage bool, timeout, retry int) {// 優化Chrome選項,增加更多反檢測設置opts := append(chromedp.DefaultExecAllocatorOptions[:],chromedp.Flag("headless", false),chromedp.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"),chromedp.Flag("disable-blink-features", "AutomationControlled"),chromedp.Flag("disable-web-security", true),           // 禁用Web安全策略chromedp.Flag("allow-running-insecure-content", true), // 允許運行不安全內容chromedp.Flag("ignore-certificate-errors", true),      // 忽略SSL證書錯誤chromedp.WindowSize(width, height),chromedp.Flag("no-sandbox", true),             // 禁用沙盒模式,在某些環境需要chromedp.Flag("disable-setuid-sandbox", true), // 禁用setuid沙盒)// 每個worker只啟動一個Chrome實例allocCtx, allocCancel := chromedp.NewExecAllocator(context.Background(), opts...)defer allocCancel()parentCtx, parentCancel := chromedp.NewContext(allocCtx)defer parentCancel()for task := range taskCh {var success boolvar attempt intfor attempt = 1; attempt <= retry; attempt++ {log.Printf("工作線程 %d 正在處理 %s (嘗試 %d/%d)\n", workerID, task.URL, attempt, retry)if attempt > 1 {time.Sleep(time.Duration(attempt*2) * time.Second)}// 每個任務新建tabctx, cancel := chromedp.NewContext(parentCtx)err := captureScreenshot(ctx, task.URL, fullPage, timeout, task.Filename)cancel()if err == nil {log.Printf("工作線程 %d 成功保存截圖: %s\n", workerID, task.Filename)success = truebreak}log.Printf("工作線程 %d 處理 %s 失敗: %v (嘗試 %d/%d)\n", workerID, task.URL, err, attempt, retry)if err != nil && (strings.Contains(err.Error(), "ERR_NAME_NOT_RESOLVED") ||strings.Contains(err.Error(), "context canceled")) {log.Printf("域名未被解析,停止對此URL的重試: %s", task.URL)break}}// 每個任務完成后,finishedTasks++atomic.AddInt64(&finishedTasks, 1)if !success {log.Printf("工作線程 %d 處理 %s 失敗,已達到最大重試次數\n", workerID, task.URL)f, err := os.OpenFile("failed_urls.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)if err == nil {f.WriteString(task.URL + "\n")f.Close()}}}
}// 截圖函數,優化等待策略
func captureScreenshot(ctx context.Context, url string, fullPage bool, timeout int, outputPath string) error {// 設置更長的超時ctx, cancel := context.WithTimeout(ctx, time.Duration(timeout)*time.Second)defer cancel()var buf []byteerr := chromedp.Run(ctx, chromedp.Tasks{chromedp.Navigate(url),chromedp.ActionFunc(func(ctx context.Context) error {var readyState stringstart := time.Now()for {err := chromedp.Evaluate(`document.readyState`, &readyState).Do(ctx)if err != nil {return err}if readyState == "complete" {time.Sleep(2 * time.Second) // 頁面加載完成后再等2秒return nil}if time.Since(start) > time.Duration(timeout)*time.Second {return errors.New("等待頁面加載超時")}time.Sleep(500 * time.Millisecond)}}),chromedp.FullScreenshot(&buf, 95), // 提高截圖質量})if err != nil {if errors.Is(err, context.DeadlineExceeded) {log.Printf("截圖超時(context deadline exceeded):%s", url)} else if errors.Is(err, context.Canceled) {log.Printf("截圖被取消(context canceled):%s", url)} else {log.Printf("截圖失敗: %s, 錯誤: %+v", url, err)}return err}return ioutil.WriteFile(outputPath, buf, 0644)
}

go.mod

module screenshot-toolgo 1.24.4require (github.com/chromedp/cdproto v0.0.0-20250403032234-65de8f5d025b // indirectgithub.com/chromedp/chromedp v0.13.7 // indirectgithub.com/chromedp/sysutil v1.1.0 // indirectgithub.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 // indirectgithub.com/gobwas/httphead v0.1.0 // indirectgithub.com/gobwas/pool v0.2.1 // indirectgithub.com/gobwas/ws v1.4.0 // indirectgolang.org/x/sys v0.29.0 // indirect
)

運行命令:

go run main.go

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/86489.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/86489.shtml
英文地址,請注明出處:http://en.pswp.cn/web/86489.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

華曦達港股IPO遞表,AI Home生態構建智能生活新藍圖

在智能家居逐漸普及的當下&#xff0c;華曦達打造的AI Home生態為用戶提供了更智能、便捷的生活解決方案&#xff0c;在行業中展現出獨特優勢。 華曦達AI Home生態由AI Home系統平臺、AI Home基礎設施、AI Home設備以及可連接外部設備的開放式設備矩陣構成&#xff0c;是一個開…

java+vue+SpringBoo智慧農業專家遠程指導系統(程序+數據庫+報告+部署教程+答辯指導)

源代碼數據庫LW文檔&#xff08;1萬字以上&#xff09;開題報告答辯稿ppt部署教程代碼講解代碼時間修改工具 技術實現 開發語言&#xff1a;后端&#xff1a;Java 前端&#xff1a;vue框架&#xff1a;springboot數據庫&#xff1a;mysql 開發工具 JDK版本&#xff1a;JDK1.…

免費AI助手工具深度測評:Claude4本地化部署與實戰應用指南

免費AI助手工具深度測評&#xff1a;Claude4本地化部署與實戰應用指南 AI無限對話免費Rovo工具Claude4碾壓cursor和augment 前言 在AI工具日益普及的今天&#xff0c;大多數高質量的AI助手都需要付費訂閱或有使用限制。然而&#xff0c;最近發現了一款基于Claude 4的免費AI助手…

MCP瀏覽器工具:playwright、chrome-mcp

參考&#xff1a; https://github.com/microsoft/playwright-mcp https://github.com/hangwin/mcp-chrome chrome-mcp安裝需要額外安裝成瀏覽器插件 用cherrystudio v1.4.5測試 mcp配置&#xff1a; "chrome-mcp-server": {"name": "chrome-mcp-serve…

水利水電安全員考試不同等級的考試內容有哪些區別?

水利水電安全員考試一般分為企業主要負責人&#xff08;A 類&#xff09;、項目負責人&#xff08;B 類&#xff09;和專職安全生產管理人員&#xff08;C 類&#xff09;三個等級。不同等級的考試內容都包括安全生產知識和管理能力兩部分&#xff0c;但具體的側重點有所不同。…

關于USB模式的一些內容(附USB接口顏色釋義圖)

今天在處理工作中的事情的時候,突然有個產品的小伙伴來問關于USB的事情,順便給她簡單說了下。USB接口模式主要包括以下幾種:Host(主機模式)、Device(設備模式)、OTG(On-The-Go),以及較少使用的Accessory模式。以下是對這些模式的詳細說明、區別差異及應用場景: 1. H…

React中的ErrorBoundary

文章目錄 前言? 一、使用類組件實現 ErrorBoundary&#xff08;官方推薦方式&#xff09;用法示例&#xff1a; ? 二、用函數組件實現 ErrorBoundary&#xff08;借助 Hook react-error-boundary 庫&#xff09;1. 安裝 react-error-boundary2. 使用 ErrorBoundary 組件&…

歷年西北工業大學計算機保研上機真題

西北工業大學計算機保研上機真題 在線測評鏈接&#xff1a;https://pgcode.cn/problem 海倫公式求面積 題目描述 給定三角形的三條邊長 a a a, b b b, c c c&#xff0c;先判斷這三條邊是否能構成一個三角形。 如果不能構成三角形&#xff0c;輸出 N a N NaN NaN&#…

掃地機產品認證--黑名單制裁公司能否拿到美國產品準入許可(FCC認證)

掃地機產品認證–黑名單制裁公司能否拿到美國產品準入許可(FCC認證) 文章目錄 掃地機產品認證--黑名單制裁公司能否拿到美國產品準入許可(FCC認證)?? **一、核心限制規則**?? **二、企業需滿足的額外條件**??? **三、黑名單企業的應對可能性**?? **四、總結**產品認證…

數據結構復習2

第二章 線性表 2.1線性表的定義和基本操作 線性表&#xff1a;一種邏輯結構&#xff0c;表示數據元素之間的一對一線性關系&#xff08;如數組、鏈表、棧、隊列等&#xff09;。 2.1.1線性表的定義 線性表是具有相同數據類型的n(n>0)個數據元素的有限序列。 (其中n為表長…

空間轉錄組benchmark 相關 讀完scGPT spatial 和 空間單細胞基因乳房細胞數據集文章之后

文章目錄 ? 空間轉錄組測序方式總體劃分&#x1f9ec; 成像型空間轉錄組&#xff08;Imaging-based ST&#xff09;原理&#xff1a;技術代表 & 特點&#xff1a;優點&#xff1a;局限&#xff1a; &#x1f9ec; 測序型空間轉錄組&#xff08;Sequencing-based ST&#x…

清理華為云服務器內存使用率

這里寫自定義目錄標題 一、正確終止進程&#xff1a;不要帶尖括號二、看清楚誰“真吃”了內存三、臨時清掉緩存&#xff08;謹慎用&#xff09;四、長期優化1. 給系統加個 Swap2. 調整 MySQL 內存配置3. 水平&#xff0f;垂直擴容4. 告警 總結與下一步 華為云的“內存使用率”默…

Go 語言中的 package 和 go modules

1、package 的定義和導入 在任何大型軟件項目中&#xff0c;代碼的組織和管理都是至關重要的。Go 語言通過 包&#xff08;Package&#xff09; 的概念來解決這個問題&#xff0c;它不僅是代碼組織的基礎&#xff0c;也是代碼復用的關鍵。本文將深入探討 Go 語言中包的定義、規…

C#語言入門-task4 :C#語言的高級應用

C# 作為一門現代化、面向對象的編程語言&#xff0c;在企業級應用、游戲開發、移動應用、云計算等領域有著廣泛的應用。以下是 C# 語言的一些高級應用場景和技術方向&#xff1a; 一、高級語言特性與編程范式 1. 異步編程&#xff08;Async/Await&#xff09; 應用場景&…

FastAPI vs Flask vs Django:Python Web框架全面對比

Python 作為最受歡迎的編程語言之一&#xff0c;其 Web 開發生態極為豐富。FastAPI、Flask 和 Django 是當前主流的三大 Python Web 框架&#xff0c;各有千秋。本文將從架構設計、開發效率、性能表現、生態支持、適用場景等方面&#xff0c;全面對比這三大框架&#xff0c;幫助…

如何從零開始掌握Pandas的DataFrame使用

視頻演示 如何通過實例學習Pandas DataFrame的創建與數據訪問 &#x1f9e9; 理解 Pandas DataFrame&#xff1a;數據分析的核心結構 Pandas 是 Python 中用于數據分析與處理的主力庫&#xff0c;而 DataFrame 是 Pandas 最常用的二維表格數據結構。我們可以將其想象成一個 Ex…

LaTeX下載與實踐入門指南

LaTeX下載與實踐入門指南 簡單來說&#xff0c;LaTeX 是一種以代碼驅動的排版系統。和 Word 那種所見即所得&#xff08;WYSIWYG&#xff09;的編輯方式不同&#xff0c;LaTeX 更像是你寫代碼、它幫你生成精美排版。你寫的不是文字排版&#xff0c;而是一種“結構化內容&#…

Java--數組

目錄 1.1 介紹&#xff1a;數據可以存放多個同一類型的數據。 1.2 排序&#xff1a; 冒泡排序法&#xff1a; 1.3 查找 1. 順序查找 2. 二分查找 二維數組&#xff1a; 楊輝三角&#xff1a; 1.1 介紹&#xff1a;數據可以存放多個同一類型的數據。 數組的引用&#xf…

地址簇與數據序列

深入理解IP地址與端口號&#xff1a;網絡通信的基礎 IP地址&#xff1a;互聯網的門牌號 IP地址&#xff08;Internet Protocol Address&#xff09;是分配給網絡中每臺設備的唯一標識符&#xff0c;就像現實世界中的門牌號一樣。在計算機上&#xff0c;一個網卡對應一個IP地址…

中學數集相等概念凸顯無窮集不可~其真子集——初數一直將不是N的真子集誤為?N

中學數集相等概念凸顯無窮集不可&#xff5e;其真子集——初數一直將不是N的真子集誤為?N 黃小寧 [摘要]證明了初等數學應有幾何起碼常識&#xff1a;當且僅當平移的距離0時才能使平移前、后的點集&#xff08;元點不少于兩個&#xff09;重合。從而表明初中的直線公理使中學…