Go语言高并发爬虫程序源码

因为最近工作量有点大,都是反复的做那几个事情,正好之前有用GO语言写的爬虫,现在稍微修改下,然后实现高并发实现快速抓取数据,因为有些属于商业机密,我就写成一个通用的模版以供大家参考。

下面是一个使用Go语言编写的高并发爬虫程序模板,采用工作池模式实现高效并发处理,并包含美观的UI界面展示爬取结果。

go 复制代码
package main

import (
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"
	
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/widget"
)

// 爬虫任务结构体
type CrawlTask struct {
	URL string
}

// 爬取结果结构体
type CrawlResult struct {
	URL        string
	Status     int
	Title      string
	Size       int
	Duration   time.Duration
	Error      error
}

func main() {
	// 创建Fyne应用
	myApp := app.New()
	myWindow := myApp.NewWindow("Go高并发爬虫")
	myWindow.Resize(fyne.NewSize(800, 600))

	// 创建数据绑定
	urls := binding.NewStringList()
	results := binding.NewStringList()
	activeWorkers := binding.NewInt()
	completedTasks := binding.NewInt()
	failedTasks := binding.NewInt()
	totalSize := binding.NewInt()

	// 初始化数据
	urls.Set([]string{
		"https://golang.org",
		"https://golang.org/pkg",
		"https://golang.org/pkg/net/http/",
		"https://golang.org/doc",
		"https://golang.org/blog",
		"https://golang.org/pkg/fmt/",
		"https://golang.org/pkg/os/",
		"https://golang.org/pkg/encoding/json/",
	})
	activeWorkers.Set(0)
	completedTasks.Set(0)
	failedTasks.Set(0)
	totalSize.Set(0)

	// 创建UI组件
	title := widget.NewLabelWithStyle("Go高并发爬虫", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})
	urlList := widget.NewListWithData(urls,
		func() fyne.CanvasObject {
			return widget.NewLabel("template")
		},
		func(i binding.DataItem, o fyne.CanvasObject) {
			o.(*widget.Label).Bind(i.(binding.String))
		})

	addUrlEntry := widget.NewEntry()
	addUrlEntry.SetPlaceHolder("输入要爬取的URL...")
	addButton := widget.NewButton("添加URL", func() {
		if addUrlEntry.Text != "" {
			current, _ := urls.Get()
			urls.Set(append(current, addUrlEntry.Text))
			addUrlEntry.SetText("")
		}
	})

	statusGrid := container.NewGridWithColumns(4,
		widget.NewLabel("活跃工作协程:"),
		widget.NewLabelWithData(binding.IntToString(activeWorkers)),
		widget.NewLabel("已完成任务:"),
		widget.NewLabelWithData(binding.IntToString(completedTasks)),
		widget.NewLabel("失败任务:"),
		widget.NewLabelWithData(binding.IntToString(failedTasks)),
		widget.NewLabel("总下载量:"),
		widget.NewLabelWithData(binding.IntToStringWithFormat(totalSize, "%.0f KB")),
	)

	resultList := widget.NewListWithData(results,
		func() fyne.CanvasObject {
			return widget.NewLabel("result template")
		},
		func(i binding.DataItem, o fyne.CanvasObject) {
			o.(*widget.Label).Bind(i.(binding.String))
		})

	// 创建控制按钮
	startButton := widget.NewButton("开始爬取", nil)
	stopButton := widget.NewButton("停止", nil)
	clearButton := widget.NewButton("清空结果", func() {
		results.Set([]string{})
		completedTasks.Set(0)
		failedTasks.Set(0)
		totalSize.Set(0)
	})

	// 创建任务通道和控制通道
	taskQueue := make(chan CrawlTask, 100)
	resultChan := make(chan CrawlResult, 100)
	stopChan := make(chan struct{})
	var wg sync.WaitGroup

	// 更新开始按钮功能
	startButton.OnTapped = func() {
		// 重置统计
		completedTasks.Set(0)
		failedTasks.Set(0)
		totalSize.Set(0)
		results.Set([]string{})
		
		// 获取URL列表
		urlList, _ := urls.Get()
		
		// 启动工作池
		workerCount := 5
		for i := 0; i < workerCount; i++ {
			wg.Add(1)
			go worker(taskQueue, resultChan, stopChan, &wg, activeWorkers)
		}
		
		// 添加任务到队列
		go func() {
			for _, u := range urlList {
				taskQueue <- CrawlTask{URL: u}
			}
			close(taskQueue)
		}()
		
		// 处理结果
		go func() {
			for result := range resultChan {
				// 更新统计信息
				if result.Error != nil {
					failedTasks.Set(failedTasks.Get() + 1)
				} else {
					completedTasks.Set(completedTasks.Get() + 1)
					totalSize.Set(totalSize.Get() + result.Size/1024) // 转换为KB
				}
				
				// 添加结果到列表
				current, _ := results.Get()
				var status string
				if result.Error != nil {
					status = fmt.Sprintf("失败: %s", result.Error)
				} else {
					status = fmt.Sprintf("成功: %d 字节 (耗时: %v)", result.Size, result.Duration)
				}
				
				newResult := fmt.Sprintf("[%s] %s", result.URL, status)
				results.Set(append(current, newResult))
			}
		}()
		
		// 等待所有工作完成
		go func() {
			wg.Wait()
			close(resultChan)
		}()
	}
	
	// 停止按钮功能
	stopButton.OnTapped = func() {
		close(stopChan)
	}
	
	// 布局界面
	topBar := container.NewHBox(addUrlEntry, addButton)
	controlBar := container.NewHBox(startButton, stopButton, clearButton)
	
	content := container.NewBorder(
		container.NewVBox(title, topBar, statusGrid, controlBar),
		nil,
		nil,
		nil,
		container.NewHSplit(
			container.NewBorder(widget.NewLabel("待爬取URL列表"), nil, nil, nil, urlList),
			container.NewBorder(widget.NewLabel("爬取结果"), nil, nil, nil, resultList),
		),
	)
	
	myWindow.SetContent(content)
	myWindow.ShowAndRun()
}

// 工作协程函数
func worker(tasks <-chan CrawlTask, results chan<- CrawlResult, stopCh <-chan struct{}, wg *sync.WaitGroup, active binding.Int) {
	defer wg.Done()
	
	active.Set(active.Get() + 1)
	defer func() {
		active.Set(active.Get() - 1)
	}()
	
	for task := range tasks {
		select {
		case <-stopCh:
			return
		default:
			start := time.Now()
			
			// 执行HTTP请求
			resp, err := http.Get(task.URL)
			if err != nil {
				results <- CrawlResult{
					URL:   task.URL,
					Error: err,
				}
				continue
			}
			defer resp.Body.Close()
			
			// 读取响应体
			body, err := io.ReadAll(resp.Body)
			if err != nil {
				results <- CrawlResult{
					URL:   task.URL,
					Error: err,
				}
				continue
			}
			
			// 创建结果
			duration := time.Since(start)
			results <- CrawlResult{
				URL:      task.URL,
				Status:   resp.StatusCode,
				Size:     len(body),
				Duration: duration,
			}
		}
	}
}

程序功能说明

这个Go语言爬虫程序具有以下特点:

1、高并发处理

  • 使用工作池模式(worker pool)管理并发
  • 通过通道(channel)实现任务队列
  • 使用sync.WaitGroup等待所有任务完成

2、用户友好界面

  • 使用Fyne框架构建跨平台GUI
  • 实时显示爬取进度和结果
  • 清晰的统计信息展示

3、核心功能

  • 添加/管理待爬取的URL列表
  • 启动/停止爬取过程
  • 显示每个URL的爬取结果(状态、大小、耗时)
  • 实时统计:活跃工作协程、已完成任务、失败任务、总下载量

4、错误处理

  • 网络请求错误处理
  • 响应读取错误处理
  • 通过停止通道实现优雅停止

使用说明

  1. 在顶部输入框中输入要爬取的URL,点击"添加URL"按钮
  2. 点击"开始爬取"按钮启动爬虫
  3. 右侧结果面板将实时显示爬取进度
  4. 统计信息区域显示当前状态
  5. 可随时点击"停止"按钮终止爬取过程
  6. 点击"清空结果"可重置统计信息和结果列表

运行要求

运行此程序需要安装以下依赖:

复制代码
go get fyne.io/fyne/v2

此程序可在Windows、macOS和Linux上运行,并自动适配本地主题。

扩展建议

1、增加深度爬取功能(从页面中提取新链接)

2、添加请求延迟控制,避免对目标服务器造成过大压力

3、实现更复杂的结果解析(如提取标题、关键词等)

4、添加结果导出功能

5、实现更精细的错误分类和统计

这个模板提供了高并发爬虫的核心架构,根据自己项目要求可以进一步扩展功能,如果遇到技术上的问题,欢迎随时留言讨论。

相关推荐
liujing102329291 小时前
Day13_C语言基础&项目实战
c语言·开发语言
周振超的1 小时前
c++编译第三方项目报错# pragma warning( disable: 4273)
开发语言·c++
JH30733 小时前
Java Stream API 在企业开发中的实战心得:高效、优雅的数据处理
java·开发语言·oracle
呆呆的小草5 小时前
Cesium距离测量、角度测量、面积测量
开发语言·前端·javascript
uyeonashi5 小时前
【QT系统相关】QT文件
开发语言·c++·qt·学习
冬天vs不冷6 小时前
Java分层开发必知:PO、BO、DTO、VO、POJO概念详解
java·开发语言
sunny-ll6 小时前
【C++】详解vector二维数组的全部操作(超细图例解析!!!)
c语言·开发语言·c++·算法·面试
猎人everest7 小时前
Django的HelloWorld程序
开发语言·python·django
嵌入式@秋刀鱼8 小时前
《第四章-筋骨淬炼》 C++修炼生涯笔记(基础篇)数组与函数
开发语言·数据结构·c++·笔记·算法·链表·visual studio code
嵌入式@秋刀鱼8 小时前
《第五章-心法进阶》 C++修炼生涯笔记(基础篇)指针与结构体⭐⭐⭐⭐⭐
c语言·开发语言·数据结构·c++·笔记·算法·visual studio code