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)
}
&http.Client{}
创建可配置的客户端实例获取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)
}
ElementNode
:HTML元素节点(标签)TextNode
:文本内容节点strings.TrimSpace
去除空白字符title
)定位特定内容对于复杂爬取任务,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("爬取完成")
}
智能限速控制:
强大的选择器:
异步高性能:
扩展性强:
对于非技术人员或快速原型开发,可视化爬虫工具是绝佳选择:
无代码可视化爬虫
易采集EasySpider 核心特点:
适用场景:快速数据采集原型、非技术用户、简单爬取任务
遵守Robots协议:
User-agent: *
Allow: /public/
Disallow: /private/
道德规范:
反爬虫对策:
错误处理:
数据存储:
Go爬虫开发技术栈演进:
学习建议:
资源推荐:
- 官方文档:Go net/http包
- Colly框架:GitHub仓库
- GoQuery文档:官方指南