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. 点击"清空结果"可重置统计信息和结果列表

运行要求

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

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

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

扩展建议

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

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

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

4、添加结果导出功能

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

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

相关推荐
大猫95273 小时前
抖音(Dy)关键词搜索爬虫实现方案
爬虫
是梦终空15 小时前
Python毕业设计226—基于python+爬虫+html的豆瓣影视数据可视化系统(源代码+数据库+万字论文)
爬虫·python·html·毕业设计·毕业论文·源代码·豆瓣影视数据可视化
谢李由2023032208116 小时前
网络爬虫学习心得
爬虫·python
广州山泉婚姻20 小时前
高并发场景下的智慧零工平台开发:Spring Boot 3+MyBatis-Flex架构深度实践
分布式·爬虫·云原生
waterHBO20 小时前
( github actions + workflow 01 ) 实现爬虫自动化,每2小时爬取一次澎湃新闻
爬虫·自动化·github
q5673152321 小时前
Java使用Selenium反爬虫优化方案
java·开发语言·分布式·爬虫·selenium
xbotcoding1 天前
Scrapeless Crawl:规模化网络数据抓取与爬行解决方案
爬虫
不叫猫先生1 天前
Bright Data网页抓取工具实战:BOSS直聘爬虫 + PandasAI分析洞察前端岗位市场趋势
爬虫·python·ai·代理
华科云商xiao徐1 天前
用Rust如何构建高性能爬虫
爬虫·rust