【网站内容安全检测】之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.tpcf.cn/pingmian/86506.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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 分块基础知识​ …