【網站內容安全檢測】之1:獲取網站所有鏈接sitemap數據

不多BB,直接上代碼:
main.go

package mainimport ("bufio""crypto/tls""fmt""io""net/http""net/url""os""strings""sync""time"_ "net/http/pprof""log""github.com/PuerkitoBio/goquery""github.com/schollz/progressbar/v3"
)type WebCrawler struct {startURLs     []stringbaseDomains   map[string]boolvisitedURLs   sync.MapurlsToVisit   chan stringsemaphore     chan struct{}timeout       time.DurationverifySSL     boolclient        *http.ClientprogressBar   *progressbar.ProgressBarwg            sync.WaitGroup
}func NewWebCrawler(startURLs []string, maxConnections int, timeout int, verifySSL bool) *WebCrawler {baseDomains := make(map[string]bool)for _, u := range startURLs {parsed, _ := url.Parse(u)baseDomains[parsed.Host] = true}return &WebCrawler{startURLs:   startURLs,baseDomains: baseDomains,urlsToVisit: make(chan string, 1000),semaphore:   make(chan struct{}, maxConnections),timeout:     time.Duration(timeout) * time.Second,verifySSL:   verifySSL,}
}func (c *WebCrawler) initClient() {tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !c.verifySSL},}c.client = &http.Client{Timeout:   c.timeout,Transport: tr,}
}func (c *WebCrawler) normalizeURL(rawURL string, baseURL string) (string, error) {base, err := url.Parse(baseURL)if err != nil || base == nil {return "", fmt.Errorf("invalid base URL: %v", err)}u, err := url.Parse(rawURL)if err != nil || u == nil {return "", fmt.Errorf("invalid URL: %v", err)}return base.ResolveReference(u).String(), nil
}func (c *WebCrawler) isValidURL(rawURL string) bool {parsed, err := url.Parse(rawURL)if err != nil {return false}if parsed.Scheme != "http" && parsed.Scheme != "https" {return false}if !c.baseDomains[parsed.Host] {return false}extensions := []string{".jpg", ".jpeg", ".png", ".gif", ".pdf", ".zip"}for _, ext := range extensions {if strings.HasSuffix(strings.ToLower(parsed.Path), ext) {return false}}return true
}func (c *WebCrawler) fetchURL(url string) (string, error) {c.semaphore <- struct{}{}defer func() { <-c.semaphore }()req, err := http.NewRequest("GET", url, nil)if err != nil {return "", fmt.Errorf("request creation failed: %v", err)}req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")resp, err := c.client.Do(req)if err != nil {if strings.Contains(err.Error(), "no such host") {return "", fmt.Errorf("DNS lookup failed for %s", url)}return "", fmt.Errorf("request failed: %v", err)}defer resp.Body.Close()if resp.StatusCode != 200 {return "", fmt.Errorf("non-200 status: %d", resp.StatusCode)}if !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {return "", fmt.Errorf("non-HTML content type: %s", resp.Header.Get("Content-Type"))}body, err := io.ReadAll(resp.Body)if err != nil {return "", fmt.Errorf("error reading response: %v", err)}return string(body), nil
}func (c *WebCrawler) parseLinks(html string, baseURL string) []string {doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))if err != nil {log.Printf("Error parsing HTML: %v", err)return nil}var links []stringdoc.Find("a[href]").Each(func(i int, s *goquery.Selection) {href, exists := s.Attr("href")if !exists || strings.HasPrefix(href, "javascript:") || href == "#" {return}normalized, err := c.normalizeURL(href, baseURL)if err != nil {log.Printf("Error normalizing URL %s: %v", href, err)return}if c.isValidURL(normalized) {links = append(links, normalized)}})doc.Find("[src]").Each(func(i int, s *goquery.Selection) {src, exists := s.Attr("src")if !exists || strings.HasPrefix(src, "data:") {return}normalized, err := c.normalizeURL(src, baseURL)if err != nil {log.Printf("Error normalizing URL %s: %v", src, err)return}if c.isValidURL(normalized) {links = append(links, normalized)}})return links
}func (c *WebCrawler) processURL(url string) {defer c.wg.Done()if _, exists := c.visitedURLs.Load(url); exists {return}c.visitedURLs.Store(url, true)html, err := c.fetchURL(url)if err != nil {fmt.Printf("Error fetching %s: %v\n", url, err)return}newLinks := c.parseLinks(html, url)for _, link := range newLinks {if _, exists := c.visitedURLs.Load(link); !exists {c.urlsToVisit <- link}}if c.progressBar != nil {c.progressBar.Add(1)}
}func (c *WebCrawler) crawl() {c.initClient()c.progressBar = progressbar.Default(-1, "爬取進度")defer c.progressBar.Close()for _, url := range c.startURLs {c.wg.Add(1)go c.processURL(url)}go func() {for newURL := range c.urlsToVisit {if _, exists := c.visitedURLs.Load(newURL); !exists {c.wg.Add(1)go c.processURL(newURL)}}}()c.wg.Wait()
}func (c *WebCrawler) saveResults(filename string) {file, err := os.Create(filename)if err != nil {fmt.Printf("Error creating file: %v\n", err)return}defer file.Close()c.visitedURLs.Range(func(key, _ interface{}) bool {file.WriteString(key.(string) + "\n")return true})
}func (c *WebCrawler) run() {startTime := time.Now()c.crawl()elapsed := time.Since(startTime)fmt.Printf("\n爬取完成!\n")// 修復語法錯誤:添加缺少的括號和逗號visitedCount := 0c.visitedURLs.Range(func(key, _ interface{}) bool {visitedCount++return true})fmt.Printf("共爬取 %d 個URL\n", visitedCount)fmt.Printf("用時: %.2f 秒\n", elapsed.Seconds())outputFile := "multi_domain_links.txt"c.saveResults(outputFile)fmt.Printf("結果已保存到 %s\n", outputFile)
}func main() {go func() {log.Println(http.ListenAndServe("localhost:6060", nil))}()if len(os.Args) < 2 {fmt.Println("用法: go run web_crawler.go <URL文件路徑> [verify_ssl]")fmt.Println("例如: go run web_crawler.go urls.txt")fmt.Println("或: go run web_crawler.go urls.txt true")return}urlFile := os.Args[1]file, err := os.Open(urlFile)if err != nil {fmt.Printf("錯誤:文件 %s 不存在\n", urlFile)return}defer file.Close()var startURLs []stringscanner := bufio.NewScanner(file)for scanner.Scan() {if url := strings.TrimSpace(scanner.Text()); url != "" {startURLs = append(startURLs, url)}}if len(startURLs) == 0 {fmt.Println("錯誤:URL文件為空")return}verifySSL := falseif len(os.Args) > 2 {verifySSL = os.Args[2] == "true"}crawler := NewWebCrawler(startURLs, 50, 20, verifySSL)// 添加開始運行提示fmt.Printf("開始爬取網站,起始URL數量: %d,是否驗證SSL: %v\n", len(startURLs), verifySSL)crawler.run()
}

go.mod

module webcrawlergo 1.24.4require (github.com/PuerkitoBio/goquery v1.10.3 // indirectgithub.com/andybalholm/cascadia v1.3.3 // indirectgithub.com/mattn/go-sqlite3 v1.14.28 // indirectgithub.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirectgithub.com/rivo/uniseg v0.4.7 // indirectgithub.com/schollz/progressbar/v3 v3.18.0 // indirectgolang.org/x/net v0.39.0 // indirectgolang.org/x/sys v0.32.0 // indirectgolang.org/x/term v0.31.0 // indirect
)	

domains.txt

www.網址.com
www.網址2.com

運行命令

go run web_crawler.go .\domains.txt

結束后會自動將結果生成到當前目錄中

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

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

相關文章

從零構建vue3項目(二)

Vue3項目增強配置&#xff1a;Axios封裝、鑒權與代碼掃描 1. Axios二次封裝與攔截器配置 安裝Axios npm install axios創建Axios實例 src/utils/request.js import axios from axios import { useUserStore } from /stores/user import router from /router// 創建axios實例…

哪家香港站群服務器比較好用?

面對魚龍混雜的服務商市場&#xff0c;哪家的香港站群服務器真正穩定&#xff1f;畢竟搞站群最怕的就是服務器抽風&#xff0c;輕則掉排名&#xff0c;重則客戶跑光光。今天咱就重點聊聊哪家香港站群服務器比較好用&#xff1f; 一般來說&#xff0c;在選擇香港站群服務器提供…

Python的科學計算庫NumPy(二)

5. 索引和切片 5.1 一維數組的索引和切片 import numpy as np# 一維數組索引和切片&#xff0c;跟python中的集合同樣使用 bin_list[1,2,3,4,5,6] bin_arraynp.array(bin_list) print(bin_array[3]) print(bin_array[1:4]) print(bin_array[-2:-1])5.2 多維數組的索引 # 多維…

STM32和C++ 實現配置文件導入、導出功能

一.配置文件導出功能 // 導出流程 // 1. 客戶端 → 設備:導出配置請求,例如:GetFlashData[d6fe30323454]:{ini} ,其中[]里面是設備序列號 // 2. 設備 → 客戶端:配置文件元數據(總大小、塊數量) // 3. 設備 → 客戶端:發送塊1(包含塊序號和大小) // 4. 設備 → 客戶端:…

HTTP 請求基礎知識

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言HTTP 請求方法GETPOSTPUTDELETE其他方法 HTTP 請求結構常用請求頭實際應用示例響應狀態碼 前言 HTTP (Hypertext Transfer Protocol) 是互聯網上應用最廣泛的協…

Django ORM 1. 創建模型(Model)

1. ORM介紹 什么是ORM&#xff1f; ORM&#xff0c;全稱 Object-Relational Mapping&#xff08;對象關系映射&#xff09;&#xff0c;一種通過對象操作數據庫的技術。 它的核心思想是&#xff1a;我們不直接寫 SQL&#xff0c;而是用 Python 對象&#xff08;類/實例&…

【C/C++】C++ 編程規范:101條規則準則與最佳實踐

C 編程規范&#xff1a;101條規則準則與最佳實踐 引言 C 是一門強大而復雜的語言&#xff0c;能高效控制硬件&#xff0c;也能寫出優雅抽象。然而&#xff0c;正因其復雜性&#xff0c;項目中若缺乏統一規范&#xff0c;極易陷入混亂、難維護、易出錯的泥潭。 本文總結了 10…

柔性屏激光修屏禁區突破:新啟航如何實現曲面 OLED 面板的無損修復?

一、引言 柔性 OLED 面板憑借其輕薄、可彎曲等特性&#xff0c;在智能終端、可穿戴設備等領域廣泛應用。然而&#xff0c;生產過程中面板易出現缺陷&#xff0c;傳統修復方法難以滿足曲面 OLED 面板的無損修復需求。新啟航半導體有限公司在激光修屏技術上取得突破&#xff0c;…

UI前端與數字孿生結合案例分享:智慧零售的可視化解決方案

hello寶子們...我們是艾斯視覺擅長ui設計、前端開發、數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩! 一、引言&#xff1a;智慧零售的可視化變革 在數字化浪潮下&#xff0c;零售行業正從 “人貨場…

Docker 入門教程(四):容器命令

文章目錄 &#x1f433; Docker 入門教程&#xff08;四&#xff09;&#xff1a;容器命令創建并運行容器&#xff1a;docker run查看容器列表&#xff1a;docker ps停止、啟動、重啟容器刪除容器&#xff1a;docker rm進入容器&#xff1a;exec 和 attach查看容器日志&#xf…

2025.06.27【技術觀察L0】AlphaGenome:DeepMind推出的全新AI基因組解讀平臺

AlphaGenome&#xff1a;DeepMind推出的全新AI基因組解讀平臺詳解 2025年6月&#xff0c;Google DeepMind團隊正式發布了AlphaGenome——一款面向基因組功能解讀和變異效應預測的全新人工智能模型。AlphaGenome的出現&#xff0c;標志著AI在基因組學領域邁出了重要一步&#x…

[ARM-2D 專題]7. OOP實現之繼承,宏implement_ex的實現和解析

implement_ex宏是 Arm-2D 庫中用于面向對象編程&#xff08;OOP&#xff09;支持的核心宏定義。 implement_ex 宏的定義和作用 implement_ex 宏在 Library/Include/arm_2d_utils.h 中定義&#xff0c;用于在 C 語言中實現類似繼承的功能&#xff1a; /*!* \note do NOT use t…

默認構造函數

1、構造函數 一、什么是構造函數 c中有一種特殊的成員函數&#xff0c;他的名字和類名相同&#xff0c;沒有返回值&#xff0c;而在創建對象時會自動執行&#xff0c;類中的數據成員的初始化往往通過構造函數來實現。完成類中數據成員的初始化&#xff0c;同時也是類中的成員…

帶標簽的 Docker 鏡像打包為 tar 文件

現在還有人用docker嗎 要將帶標簽的 Docker 鏡像打包為 tar 文件&#xff0c;請使用 docker save 命令。以下是詳細操作指南&#xff1a; 一、單鏡像打包&#xff08;推薦方式&#xff09; # 基礎格式 docker save -o [輸出文件名].tar [鏡像名]:[標簽]# 示例&#xff1a;將…

基于GPS-RTK的履帶吊車跑偏檢測技術方案

基于GPS-RTK的履帶吊車跑偏檢測技術方案 1. 引言 1.1 項目背景 履帶吊車作為重型工程機械&#xff0c;其行駛穩定性直接關系到作業安全和設備壽命。跑偏現象會導致履帶異常磨損、轉向系統過載&#xff0c;嚴重時可能引發側翻事故。傳統檢測方法&#xff08;如激光測距或人工觀…

勾正數據大數據開發面試題整理-20250625

最近面了家公司&#xff0c;想看看自己多年不準備面試&#xff0c;靠著老本能面試成啥樣&#xff0c;算是試試水吧&#xff0c;一面過了&#xff0c;二面有個算法題沒答出來&#xff0c;整體答得狀態也不太好&#xff0c;應該是沒過。 一面 先來說說一面吧&#xff0c;一面是…

基于中國香港會計準則差異,中國企業在香港推廣ERP(SAP、Oracle)系統需要注意的細節

核心在于&#xff1a;ERP通常按單一會計準則設計主數據架構&#xff0c;但跨國企業需要同時滿足兩地報表要求。 用戶常見的場景包括&#xff1a; 1 科目體系能否同時承載CAS的專項儲備和HKFRS的禁止計提&#xff1f; 2 資產模塊如何兼容不同的減值轉回規則&#xff1f; 3 關聯…

【編譯原理】期末復習知識總結

目錄 題型 總結 編譯五大組成部分 編譯與解釋方式區別&#xff1f; 前端&#xff0c;后端&#xff0c;Why&#xff1f; 概念 推導、歸約 短語、簡單短語、句柄 文法 分類 正則文法&#xff08;3型&#xff09; NFA、DFA、最小化 自上而下語法分析&#xff08;推導…

【軟考高級系統架構論文】論微服務架構及其應用

論文真題 論微服務架構及其應用近年來,隨著互聯網行業的迅猛發展,公司或組織業務的不斷擴張,需求的快速變化以及用戶量的不斷增加,傳統的單塊(Monolithic) 軟件架構面臨著越來越多的挑戰,已逐漸無法適應互聯網時代對軟件的要求。在這一背景下,微服務架構模式(Microservi…

【人工智能】RAG分塊

在RAG&#xff08;檢索增強生成&#xff09;系統中&#xff0c;文檔分塊&#xff08;Chunking&#xff09;是決定系統性能的核心環節&#xff0c;直接影響檢索精度和生成質量。分塊需平衡語義完整性、檢索效率和上下文保留三大目標。 一、分塊的核心標準 1.1 分塊基礎知識? …