golang高效分页数据抓取与API爬取插件库walker的使用

Golang高效分页数据抓取与API爬取插件库walker的使用

walker logo

Walker简化了从任何数据源获取分页数据的过程。通过Walker,您可以轻松配置起始位置和要获取的文档数量。此外,Walker支持并行处理,使您能够更高效、更快速地获取数据。

特性

  • 提供遍历API端点分页的walker
  • 支持cursoroffset分页策略
  • 无需额外工作即可实现并发获取和处理数据
  • 支持总获取数量限制
  • 支持速率限制

基本用法示例

// source函数接收start(页码)和fetchCount(每页数量)参数
func source(start, fetchCount int) ([]int, error) {
    return []int{start, fetchCount}, nil
}

// sink函数处理获取的结果
func sink(result []int, stop func()) error {
    fmt.Println(result)
    return nil
}

func main() {
    walker.New(source, sink).Walk()
}

输出:

[0 10]
[1 10]
[4 10]
[2 10]
[3 10]
[5 10]
[8 10]
[9 10]
[7 10]
[6 10]
...
无限继续

说明:

  • source函数接收start(页码)和count(每页数量)参数
  • sink函数接收从source返回的结果和一个stop函数
  • 注意顺序不能保证,因为source和sink是并发调用的

API端点分页遍历示例

从Open Brewery DB获取所有啤酒厂数据:

// 构建请求
func buildRequest(start, fetchCount int) (*http.Request, error) {
    url := fmt.Sprintf("https://api.openbrewerydb.org/breweries?page=%d&per_page=%d", start, fetchCount)
    return http.NewRequest(http.MethodGet, url, http.NoBody)
}

// 处理响应
func sink(res *http.Response, stop func()) error {
    var payload []map[string]any
    json.NewDecoder(res.Body).Decode(&payload)

    if len(payload) == 0 {
        stop()  // 没有数据时停止
        return nil
    }

    return saveBreweries(payload)  // 保存数据
}

func main() {
    walker.NewApiWalker(http.DefaultClient, buildRequest, sink).Walk()
}

创建API walker需要提供:

  • RequestBuilder函数: 使用提供的值创建http请求
  • sink函数: 处理http响应

配置选项

选项 描述 默认值 可用值
WithPagination 定义分页策略 walker.OffsetPagination{} walker.OffsetPagination{}, walker.CursorPagination{}
WithMaxBatchSize 定义停止前获取的最大文档数 10 int
WithParallelism 定义运行source的工作线程数 runtime.NumCPU() int
WithLimiter 定义停止前获取的最大文档数 walker.InfiniteLimiter() walker.InfiniteLimiter(), walker.ConstantLimiter(int)
WithRateLimit 按数量和持续时间定义速率限制 无限制 (int, time.Duration)
WithContext 定义上下文 context.Background() context.Context

贡献

欢迎任何贡献使walker变得更好和功能更丰富。随时贡献您的用例!


更多关于golang高效分页数据抓取与API爬取插件库walker的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang高效分页数据抓取与API爬取插件库walker的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang高效分页数据抓取与Walker库使用指南

在Go语言中进行高效的分页数据抓取是许多爬虫和数据处理应用的核心需求。下面我将介绍如何使用walker库来实现这一目标。

Walker库简介

Walker是一个轻量级的Go爬虫框架,专门为分页数据抓取设计,具有以下特点:

  • 简洁的API设计
  • 自动分页处理
  • 并发控制
  • 请求重试机制
  • 灵活的解析器

安装Walker

go get github.com/henrylee2cn/walker

基础使用示例

package main

import (
	"fmt"
	"log"
	"github.com/henrylee2cn/walker"
)

func main() {
	// 创建walker实例
	w := walker.New()

	// 设置并发数
	w.SetThreadNum(3)

	// 定义处理函数
	handleFunc := func(ctx *walker.Context) {
		// 获取响应内容
		body := ctx.GetBody()
		fmt.Printf("抓取到数据: %s\n", string(body))
		
		// 可以在这里解析数据并存储
	}

	// 添加种子URL
	w.AddSeed("https://example.com/api/data?page=1", "GET", nil, handleFunc)

	// 设置分页规则
	w.SetPager(func(ctx *walker.Context) []*walker.Request {
		// 这里实现分页逻辑
		currentPage := ctx.GetExtra().(int)
		if currentPage >= 5 { // 假设只抓取5页
			return nil
		}
		nextPage := currentPage + 1
		nextUrl := fmt.Sprintf("https://example.com/api/data?page=%d", nextPage)
		
		// 返回下一页请求
		return []*walker.Request{
			{
				Url:    nextUrl,
				Method: "GET",
				Extra:  nextPage,
			},
		}
	})

	// 开始抓取
	if err := w.Run(); err != nil {
		log.Fatal(err)
	}
}

高级功能示例

1. 带参数的分页API抓取

func advancedExample() {
	w := walker.New()
	w.SetThreadNum(5) // 设置5个并发

	// 设置请求头
	headers := map[string]string{
		"User-Agent": "walker-spider",
		"Accept":     "application/json",
	}

	// 处理函数
	handleFunc := func(ctx *walker.Context) {
		var data struct {
			Items []map[string]interface{} `json:"items"`
			Total int                      `json:"total"`
		}
		if err := ctx.BindJSON(&data); err != nil {
			log.Printf("解析JSON失败: %v", err)
			return
		}
		
		// 处理数据
		for _, item := range data.Items {
			fmt.Printf("处理条目: %v\n", item)
		}
	}

	// 添加初始请求
	w.AddSeed("https://api.example.com/data?page=1&size=20", "GET", headers, handleFunc)

	// 智能分页处理
	w.SetPager(func(ctx *walker.Context) []*walker.Request {
		var resp struct {
			Page  int `json:"page"`
			Pages int `json:"total_pages"`
		}
		if err := ctx.BindJSON(&resp); err != nil {
			return nil
		}
		
		if resp.Page >= resp.Pages {
			return nil
		}
		
		nextPage := resp.Page + 1
		nextUrl := fmt.Sprintf("https://api.example.com/data?page=%d&size=20", nextPage)
		
		return []*walker.Request{
			{
				Url:    nextUrl,
				Method: "GET",
				Header: headers,
				Extra:  nextPage,
			},
		}
	})

	// 设置请求间隔避免被封
	w.SetDelay(500 * time.Millisecond)

	if err := w.Run(); err != nil {
		log.Fatal(err)
	}
}

2. 使用代理和重试机制

func withProxyAndRetry() {
	w := walker.New()
	
	// 设置代理
	w.SetProxy("http://proxy.example.com:8080")
	
	// 设置重试次数和间隔
	w.SetRetryTimes(3, 2*time.Second)
	
	// 自定义错误处理
	w.SetErrorHandler(func(ctx *walker.Context, err error) {
		log.Printf("请求 %s 失败: %v", ctx.GetUrl(), err)
	})
	
	// 其余配置...
}

最佳实践

  1. 合理设置并发数:根据目标网站的承受能力和自身网络条件调整
  2. 遵守robots.txt:检查目标网站的爬虫政策
  3. 设置适当的延迟:避免被封禁
  4. 处理反爬机制:考虑使用代理、随机User-Agent等
  5. 错误处理和日志:完善的错误处理能提高稳定性
  6. 资源管理:及时释放资源,避免内存泄漏

性能优化技巧

  1. 复用http.Client:walker内部已经做了优化
  2. 连接池:调整MaxIdleConns等参数
  3. 压缩传输:启用Accept-Encoding
  4. 异步处理:将数据解析和存储放到单独的goroutine
  5. 内存管理:及时清理不需要的数据

通过合理使用walker库的这些功能,你可以构建高效稳定的分页数据抓取程序。记得始终遵守目标网站的使用条款和法律法规。

回到顶部