Go爬虫开发学习记录

发布于:2025-06-09 ⋅ 阅读:(14) ⋅ 点赞:(0)

Go爬虫开发学习记录

基础篇:使用net/http库

Go的标准库net/http提供了完善的HTTP客户端功能,是构建爬虫的基石:

package main

import (
    "fmt"
    "io"
    "net/http"
)

func fetchPage(url string) string {
    // 创建自定义HTTP客户端
    client := &http.Client{}
    
    // 构建GET请求
    req, _ := http.NewRequest("GET", url, nil)
    
    // 设置请求头模拟浏览器
    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
    req.Header.Add("Cookie", "example_cookie=value")
    
    // 发送请求
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("请求错误:", err)
        return ""
    }
    defer resp.Body.Close()  // 确保关闭响应体
    
    // 检查状态码
    if resp.StatusCode != 200 {
        fmt.Println("状态码错误:", resp.StatusCode)
        return ""
    }
    
    // 读取响应内容
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("读取失败:", err)
        return ""
    }
    return string(body)
}

func main() {
    url := "https://www.runoob.com/go/go-tutorial.html"
    htmlContent := fetchPage(url)
    fmt.Println(htmlContent)
}

解析:

  1. 自定义HTTP客户端:通过&http.Client{}创建可配置的客户端实例
  2. 请求头设置:添加User-Agent和Cookie模拟浏览器行为
  3. 错误处理:全面处理网络请求、状态码和读取错误
  4. 资源清理:使用defer确保响应体正确关闭

进阶篇:HTML解析与内容提取

获取HTML只是第一步,关键是从中提取有价值的信息:

import (
    "golang.org/x/net/html"
    "strings"
)

func parseHTML(htmlStr string) (title, content string) {
    // 解析HTML文档
    doc, err := html.Parse(strings.NewReader(htmlStr))
    if err != nil {
        fmt.Println("解析错误:", err)
        return
    }
    
    // 递归查找标题
    var findTitle func(*html.Node)
    findTitle = func(n *html.Node) {
        if n.Type == html.ElementNode && n.Data == "title" {
            for c := n.FirstChild; c != nil; c = c.NextSibling {
                if c.Type == html.TextNode {
                    title = c.Data
                    return
                }
            }
        }
        for c := n.FirstChild; c != nil; c = c.NextSibling {
            findTitle(c)
        }
    }
    findTitle(doc)
    
    // 提取所有文本内容
    var extractText func(*html.Node)
    extractText = func(n *html.Node) {
        if n.Type == html.TextNode {
            trimmed := strings.TrimSpace(n.Data)
            if trimmed != "" {
                content += trimmed + "\n"
            }
        }
        for c := n.FirstChild; c != nil; c = c.NextSibling {
            extractText(c)
        }
    }
    extractText(doc)
    
    return
}

func main() {
    htmlContent := fetchPage("https://www.runoob.com/go/go-tutorial.html")
    title, content := parseHTML(htmlContent)
    fmt.Println("标题:", title)
    fmt.Println("内容:\n", content)
}

解析:

  1. 递归遍历DOM树:深度优先搜索(DFS)遍历所有节点
  2. 节点类型判断
    • ElementNode:HTML元素节点(标签)
    • TextNode:文本内容节点
  3. 内容清洗strings.TrimSpace去除空白字符
  4. 精确提取:通过标签名(title)定位特定内容

高效篇:使用Colly+GoQuery框架

对于复杂爬取任务,Colly+GoQuery组合提供更强大的解决方案:

package main

import (
    "fmt"
    "log"
    "strings"
    "time"
    "bytes"
    
    "github.com/gocolly/colly"
    "github.com/PuerkitoBio/goquery"
)

func main() {
    // 1. 创建Collector实例
    c := colly.NewCollector(
        colly.AllowedDomains("runoob.com", "www.runoob.com"),
        colly.UserAgent("Mozilla/5.0..."),
        colly.Async(true), // 启用异步
    )
    
    // 2. 设置爬取规则
    c.Limit(&colly.LimitRule{
        DomainGlob:  "*runoob.com*",
        Parallelism: 2, // 并发数
        Delay:       1 * time.Second,
        RandomDelay: 1 * time.Second,
    })
    
    // 3. 注册回调函数
    c.OnRequest(func(r *colly.Request) {
        fmt.Println("访问:", r.URL)
    })
    
    c.OnError(func(_ *colly.Response, err error) {
        log.Println("错误:", err)
    })
    
    // 4. 使用GoQuery解析
    c.OnHTML("html", func(e *colly.HTMLElement) {
        doc, err := goquery.NewDocumentFromReader(bytes.NewReader(e.Response.Body))
        if err != nil {
            log.Println("解析失败:", err)
            return
        }
        
        // 提取标题
        title := doc.Find("title").Text()
        fmt.Println("页面标题:", title)
        
        // 提取导航菜单
        doc.Find("#leftcolumn a").Each(func(i int, s *goquery.Selection) {
            fmt.Printf("菜单%d: %s\n", i+1, strings.TrimSpace(s.Text()))
        })
        
        // 提取文章内容
        doc.Find("div.article").Each(func(i int, s *goquery.Selection) {
            section := s.Find("h1").Text()
            content := strings.TrimSpace(s.Text())
            fmt.Printf("\n章节%d: %s\n内容: %s\n", i+1, section, content)
        })
    })
    
    // 5. 开始爬取
    c.Visit("https://www.runoob.com/go/go-tutorial.html")
    c.Wait() // 等待异步任务
    fmt.Println("爬取完成")
}

Colly核心优势:

  1. 智能限速控制

    • 自动延迟请求
    • 随机延迟避免检测
    • 并发控制保护服务器
  2. 强大的选择器

    • CSS选择器语法
    • 链式调用
    • 支持复杂嵌套选择
  3. 异步高性能

    • 协程并发处理
    • 自动队列管理
    • 高效资源利用
  4. 扩展性强

    • 中间件支持
    • 自定义存储后端
    • 请求重试机制

可视化爬虫工具:易采集EasySpider

对于非技术人员或快速原型开发,可视化爬虫工具是绝佳选择:
无代码可视化爬虫

易采集EasySpider 核心特点:

  • 零代码可视化操作
  • 浏览器自动化录制
  • 智能数据提取
  • 定时任务调度
  • 云存储支持

适用场景:快速数据采集原型、非技术用户、简单爬取任务

爬虫开发最佳实践

  1. 遵守Robots协议

    User-agent: *
    Allow: /public/
    Disallow: /private/
    
  2. 道德规范

    • 尊重网站版权声明
    • 避免高频请求
    • 不爬取敏感信息
  3. 反爬虫对策

    • 轮换User-Agent
    • 使用代理IP池
    • 模拟人类操作间隔
    • 处理验证码机制
  4. 错误处理

    • 网络异常重试
    • 状态码处理
    • 超时控制
  5. 数据存储

    • 结构化数据:MySQL/PostgreSQL
    • 半结构化:MongoDB/Elasticsearch
    • 文件存储:CSV/JSON/Parquet

总结与学习路径

Go爬虫开发技术栈演进:

基础 net/http
HTML解析
Colly框架
分布式爬虫
云原生部署

学习建议:

  1. 掌握基础:熟练使用net/http和HTML解析
  2. 框架实践:深入Colly+GoQuery组合应用
  3. 项目实战:构建完整爬虫系统
  4. 拓展进阶:研究分布式爬虫架构
  5. 工具互补:了解可视化工具辅助开发

资源推荐:


网站公告

今日签到

点亮在社区的每一天
去签到