赞
踩
网络爬虫(Web Scraper)是从网站自动提取数据的工具。它们被广泛用于数据采集、搜索引擎优化、市场调查等领域。本文将详细介绍如何使用 Go 1.19 实现一个简化的站点模板自动化抓取工具,帮助开发者高效地进行数据采集。
在开始之前,请确保你的系统上已经安装了 Go 1.19。可以通过以下命令检查 Go 的版本:
go version
如果尚未安装 Go,可以从 Go 官方网站 下载并安装最新版本。
网络爬虫的基本工作流程如下:
在 Go 语言中,有多个流行的爬虫框架,例如:
本文将主要使用 Colly 和 Goquery 进行网页爬取和内容解析。
我们将设计一个简化的站点模板自动化抓取工具,其基本流程如下:
首先,创建一个新的 Go 项目:
mkdir go_scraper
cd go_scraper
go mod init go_scraper
然后,安装 Colly 和 Goquery:
go get -u github.com/gocolly/colly
go get -u github.com/PuerkitoBio/goquery
接下来,编写一个简单的爬虫来抓取网页内容:
package main import ( "fmt" "github.com/gocolly/colly" ) func main() { // 创建一个新的爬虫实例 c := colly.NewCollector() // 设置请求时的回调函数 c.OnRequest(func(r *colly.Request) { fmt.Println("Visiting", r.URL.String()) }) // 设置响应时的回调函数 c.OnResponse(func(r *colly.Response) { fmt.Println("Visited", r.Request.URL) fmt.Println("Response:", string(r.Body)) }) // 设置错误处理的回调函数 c.OnError(func(r *colly.Response, err error) { fmt.Println("Error:", err) }) // 设置HTML解析时的回调函数 c.OnHTML("title", func(e *colly.HTMLElement) { fmt.Println("Title:", e.Text) }) // 开始爬取 c.Visit("http://example.com") }
运行以上代码,将会抓取 http://example.com 的内容并打印网页标题。
为了从网页中提取所需的数据,我们需要使用 Goquery 解析 HTML 内容。以下示例展示了如何使用 Goquery 提取网页中的链接和文本:
package main import ( "fmt" "github.com/gocolly/colly" "github.com/PuerkitoBio/goquery" ) func main() { c := colly.NewCollector() c.OnHTML("body", func(e *colly.HTMLElement) { e.DOM.Find("a").Each(func(index int, item *goquery.Selection) { link, _ := item.Attr("href") text := item.Text() fmt.Printf("Link #%d: %s (%s)\n", index, text, link) }) }) c.Visit("http://example.com") }
为了提高爬虫的效率,我们可以使用 Colly 的并发功能:
package main import ( "fmt" "github.com/gocolly/colly" "github.com/PuerkitoBio/goquery" "log" "time" ) func main() { c := colly.NewCollector( colly.Async(true), // 启用异步模式 ) c.Limit(&colly.LimitRule{ DomainGlob: "*", Parallelism: 2, // 设置并发数 Delay: 2 * time.Second, }) c.OnHTML("body", func(e *colly.HTMLElement) { e.DOM.Find("a").Each(func(index int, item *goquery.Selection) { link, _ := item.Attr("href") text := item.Text() fmt.Printf("Link #%d: %s (%s)\n", index, text, link) c.Visit(e.Request.AbsoluteURL(link)) }) }) c.OnRequest(func(r *colly.Request) { fmt.Println("Visiting", r.URL.String()) }) c.OnError(func(r *colly.Response, err error) { log.Println("Error:", err) }) c.Visit("http://example.com") c.Wait() // 等待所有异步任务完成 }
将抓取的数据保存到本地文件或数据库中。这里以 CSV 文件为例:
package main import ( "encoding/csv" "fmt" "github.com/gocolly/colly" "github.com/PuerkitoBio/goquery" "log" "os" "time" ) func main() { file, err := os.Create("data.csv") if err != nil { log.Fatalf("could not create file: %v", err) } defer file.Close() writer := csv.NewWriter(file) defer writer.Flush() c := colly.NewCollector( colly.Async(true), ) c.Limit(&colly.LimitRule{ DomainGlob: "*", Parallelism: 2, Delay: 2 * time.Second, }) c.OnHTML("body", func(e *colly.HTMLElement) { e.DOM.Find("a").Each(func(index int, item *goquery.Selection) { link, _ := item.Attr("href") text := item.Text() fmt.Printf("Link #%d: %s (%s)\n", index, text, link) writer.Write([]string{text, link}) c.Visit(e.Request.AbsoluteURL(link)) }) }) c.OnRequest(func(r *colly.Request) { fmt.Println("Visiting", r.URL.String()) }) c.OnError(func(r *colly.Response, err error) { log.Println("Error:", err) }) c.Visit("http://example.com") c.Wait() }
为了提高爬虫的稳定性,我们需要处理请求错误并实现重试机制:
package main import ( "fmt" "github.com/gocolly/colly" "github.com/PuerkitoBio/goquery" "log" "os" "time" ) func main() { file, err := os.Create("data.csv") if err != nil { log.Fatalf("could not create file: %v", err) } defer file.Close() writer := csv.NewWriter(file) defer writer.Flush() c := colly.NewCollector( colly.Async(true), colly.MaxDepth(1), ) c.Limit(&colly.LimitRule{ DomainGlob: "*", Parallelism: 2, Delay: 2 * time.Second, }) c.OnHTML("body", func(e *colly.HTMLElement) { e.DOM.Find("a").Each(func(index int, item *goquery.Selection) { link, _ := item.Attr("href") text := item.Text() fmt.Printf("Link #%d: %s (%s)\ n", index, text, link) writer.Write([]string{text, link}) c.Visit(e.Request.AbsoluteURL(link)) }) }) c.OnRequest(func(r *colly.Request) { fmt.Println("Visiting", r.URL.String()) }) c.OnError(func(r *colly.Response, err error) { log.Println("Error:", err) // 重试机制 if r.StatusCode == 0 || r.StatusCode >= 500 { r.Request.Retry() } }) c.Visit("http://example.com") c.Wait() }
以下示例展示了如何抓取新闻网站的标题和链接,并保存到 CSV 文件中:
package main import ( "encoding/csv" "fmt" "github.com/gocolly/colly" "log" "os" "time" ) func main() { file, err := os.Create("news.csv") if err != nil { log.Fatalf("could not create file: %v", err) } defer file.Close() writer := csv.NewWriter(file) defer writer.Flush() writer.Write([]string{"Title", "Link"}) c := colly.NewCollector( colly.Async(true), ) c.Limit(&colly.LimitRule{ DomainGlob: "*", Parallelism: 5, Delay: 1 * time.Second, }) c.OnHTML(".news-title", func(e *colly.HTMLElement) { title := e.Text link := e.ChildAttr("a", "href") writer.Write([]string{title, e.Request.AbsoluteURL(link)}) fmt.Printf("Title: %s\nLink: %s\n", title, e.Request.AbsoluteURL(link)) }) c.OnRequest(func(r *colly.Request) { fmt.Println("Visiting", r.URL.String()) }) c.OnError(func(r *colly.Response, err error) { log.Println("Error:", err) if r.StatusCode == 0 || r.StatusCode >= 500 { r.Request.Retry() } }) c.Visit("http://example-news-site.com") c.Wait() }
为了避免被目标网站屏蔽,可以使用代理:
c.SetProxy("http://proxyserver:port")
通过设置用户代理,伪装成不同的浏览器:
c.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
可以使用 Colly 的扩展库 Colly-Redis 实现分布式爬虫:
import (
"github.com/gocolly/redisstorage"
)
func main() {
c := colly.NewCollector()
redisStorage := &redisstorage.Storage{
Address: "localhost:6379",
Password: "",
DB: 0,
Prefix: "colly",
}
c.SetStorage(redisStorage)
}
对于动态网页,可以使用无头浏览器,如 chromedp:
import ( "context" "github.com/chromedp/chromedp" ) func main() { ctx, cancel := chromedp.NewContext(context.Background()) defer cancel() var res string err := chromedp.Run(ctx, chromedp.Navigate("http://example.com"), chromedp.WaitVisible(`#some-element`), chromedp.InnerHTML(`#some-element`, &res), ) if err != nil { log.Fatal(err) } fmt.Println(res) }
通过本文的详细介绍,我们学习了如何使用 Go 1.19 实现一个简化的站点模板自动化抓取工具。我们从基础的爬虫设计流程开始,逐步深入到 HTML 解析、并发处理、数据存储和错误处理等关键环节,并通过具体的代码示例展示了如何抓取和处理网页数据。
Go 语言强大的并发处理能力和丰富的第三方库,使其成为构建高效、稳定的网络爬虫的理想选择。通过不断优化和扩展,可以实现更复杂和高级的爬虫功能,为各种数据采集需求提供解决方案。
希望本文能为你在 Go 语言下实现网络爬虫提供有价值的参考,并激发你在这一领域进行更多探索和创新。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。