Go Colly异步爬虫请求失败,部分元素缺失如何解决?
问题分析与解决方案
从错误日志(请求超时20秒且无状态码)和代码来看,核心问题集中在反爬拦截、并发安全、URL处理错误、缺失错误捕获这几个方面,以下是针对性修复方案:
1. 补全错误捕获,明确失败原因
当前代码未处理请求错误,无法定位是被反爬拦截、DNS失败还是超时,先添加错误回调:
collector.OnError(func(r *colly.Response, err error) { fmt.Printf("请求 %s 失败: %v\n", r.Request.URL, err) })
同时不要忽略Visit的返回错误:
if err := collector.Visit(baseURL); err != nil { fmt.Printf("初始请求失败: %v\n", err) }
2. 修复并发安全问题
全局切片aggregator在异步场景下被多goroutine同时append,会导致数据丢失或 panic,必须加锁:
import "sync" func main() { var ( aggregator []string mu sync.Mutex ) // ... 其他代码 collector.OnHTML(".my-data-container", func(e *colly.HTMLElement) { item := e.ChildText(".my-beautiful-item") mu.Lock() aggregator = append(aggregator, item) mu.Unlock() }) }
3. 优化URL处理逻辑
手动拼接URL容易出现参数重复、相对路径转绝对路径错误,改用Colly内置方法和标准库处理:
- 分类列表页URL拼接:
h, exists := e.Attr("href") if !exists { return // 跳过无有效href的标签 } url := ev.Request.AbsoluteURL(h) u, err := url.Parse(url) if err != nil { fmt.Printf("解析URL失败: %v\n", err) return } q := u.Query() q.Set("page", "1") u.RawQuery = q.Encode() collector.Visit(u.String())
- 分页URL处理:
u, err := url.Parse(e.Request.URL.String()) if err != nil { fmt.Printf("解析分页URL失败: %v\n", err) return } q := u.Query() q.Set("absolutepage", strconv.Itoa(i)) u.RawQuery = q.Encode() collector.Visit(u.String())
- 详情页链接处理:
link := e.Attr("href") absLink := e.Request.AbsoluteURL(link) collector.Visit(absLink)
4. 调整反爬规避策略
之前JS爬虫正常,说明目标站点对Go的请求特征有拦截,调整以下参数:
- 设置浏览器级User-Agent:
collector.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
- 降低并行度、延长随机延迟:
collector.Limit(&colly.LimitRule{ Parallelism: 2, // 从4降至2,减少反爬触发概率 RandomDelay: 3 * time.Second, // 延迟增加到3秒 })
- 禁用HTTP2(部分站点对Go的HTTP2支持不佳):
collector.WithTransport(&http.Transport{ DisableHTTP2: true, })
5. 修复正则解析的panic风险
extractMaxItemsAndOffsetFromPagination中,正则匹配失败时直接取[1]会触发panic,先做长度判断:
func extractMaxItemsAndOffsetFromPagination(paginator string) (float64, float64) { totaleItemsRegexp := regexp.MustCompile("<([1-9]\\d{0,3})>") pageOffsetRegexp := regexp.MustCompile("-([1-9]\\d{0,3});") totaleItemsSub := totaleItemsRegexp.FindStringSubmatch(paginator) if len(totaleItemsSub) < 2 { fmt.Println("未匹配到总条目数") return -1, -1 } pageOffsetSub := pageOffsetRegexp.FindStringSubmatch(paginator) if len(pageOffsetSub) < 2 { fmt.Println("未匹配到分页偏移量") return -1, -1 } // ... 后续解析代码不变 }
6. 验证动态渲染场景
如果目标站点内容是JS动态加载的,Colly默认不执行JS,需集成渲染扩展:
import "github.com/gocolly/colly/v2/extensions" // 初始化collector后添加 extensions.Render(collector)
测试时可先关闭异步(colly.Async(false)),单线程验证逻辑正确性,再开启异步调试。
内容的提问来源于stack exchange,提问作者Alejandro Alvarado
相关产品推荐
相关产品推荐

