Golang实现网页抓取与浏览器自动化速度优化
Golang实现网页抓取与浏览器自动化速度优化 我想使用Go进行网页抓取和Web应用自动化。
如果我希望我的Go程序在某个网站上执行职位搜索,结果是分布在40个页面上的3000条结果,那么让程序在职位搜索页面输入搜索词和地点,点击每个职位发布并抓取该职位的页面,对页面上的所有职位都执行此操作,当到达页面底部时,点击下一页并重复相同的过程,直到到达结果中的最后一页(在本例中是第40页),这对于程序来说工作量会太大吗?
一个人手动打开40个页面上的3000个职位发布中的每一个都需要一段时间,我不确定网页抓取和Web自动化程序做这件事能有多快。我认为网页抓取器会很快并且不会占用太多内存,但对于Web驱动程序,我不确定它执行上述操作是否会太慢?
更多关于Golang实现网页抓取与浏览器自动化速度优化的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你好,你试过看看 https://github.com/gocolly/colly 吗?听起来这正是你要找的。
更多关于Golang实现网页抓取与浏览器自动化速度优化的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
对于网页抓取和浏览器自动化,Go语言可以通过不同的策略来优化速度。以下是具体的技术方案和示例代码:
1. 并发抓取优化
使用colly框架进行高效并发抓取,配合适当的延迟控制:
package main
import (
"fmt"
"sync"
"time"
"github.com/gocolly/colly"
)
func main() {
c := colly.NewCollector(
colly.Async(true),
colly.UserAgent("Mozilla/5.0"),
)
c.Limit(&colly.LimitRule{
DomainGlob: "*",
Parallelism: 10,
Delay: 500 * time.Millisecond,
})
var wg sync.WaitGroup
jobCount := 0
mutex := &sync.Mutex{}
c.OnHTML(".job-listing", func(e *colly.HTMLElement) {
wg.Add(1)
go func() {
defer wg.Done()
jobURL := e.Attr("href")
c.Visit(jobURL)
}()
})
c.OnHTML(".job-details", func(e *colly.HTMLElement) {
mutex.Lock()
jobCount++
fmt.Printf("抓取第%d个职位\n", jobCount)
mutex.Unlock()
})
for page := 1; page <= 40; page++ {
url := fmt.Sprintf("https://example.com/jobs?page=%d", page)
c.Visit(url)
}
c.Wait()
wg.Wait()
}
2. 无头浏览器优化
使用chromedp进行浏览器自动化,通过并行处理多个标签页:
package main
import (
"context"
"fmt"
"sync"
"time"
"github.com/chromedp/chromedp"
)
func scrapeJob(url string, wg *sync.WaitGroup) {
defer wg.Done()
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
defer cancel()
var jobTitle, jobDescription string
err := chromedp.Run(ctx,
chromedp.Navigate(url),
chromedp.WaitVisible(`.job-content`),
chromedp.Text(`h1.job-title`, &jobTitle),
chromedp.Text(`.job-description`, &jobDescription),
)
if err != nil {
fmt.Printf("错误: %v\n", err)
return
}
fmt.Printf("职位: %s\n描述: %s\n", jobTitle, jobDescription)
}
func main() {
var wg sync.WaitGroup
maxConcurrent := 5
semaphore := make(chan struct{}, maxConcurrent)
jobURLs := []string{
"https://example.com/job/1",
"https://example.com/job/2",
// 添加更多URL
}
for _, url := range jobURLs {
wg.Add(1)
semaphore <- struct{}{}
go func(u string) {
defer func() { <-semaphore }()
scrapeJob(u, &wg)
}(url)
}
wg.Wait()
}
3. 混合方案:API探测+直接抓取
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sync"
"time"
)
type Job struct {
ID string `json:"id"`
Title string `json:"title"`
URL string `json:"url"`
}
func fetchJobListings(page int) ([]Job, error) {
url := fmt.Sprintf("https://api.example.com/jobs?page=%d", page)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var jobs []Job
json.Unmarshal(body, &jobs)
return jobs, nil
}
func main() {
var wg sync.WaitGroup
results := make(chan Job, 100)
for page := 1; page <= 40; page++ {
wg.Add(1)
go func(p int) {
defer wg.Done()
jobs, err := fetchJobListings(p)
if err != nil {
fmt.Printf("页面%d错误: %v\n", p, err)
return
}
for _, job := range jobs {
results <- job
}
}(page)
}
go func() {
wg.Wait()
close(results)
}()
for job := range results {
fmt.Printf("获取职位: %s - %s\n", job.ID, job.Title)
}
}
4. 性能优化配置
// 自定义HTTP客户端配置
func createOptimizedClient() *http.Client {
return &http.Client{
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
},
Timeout: 30 * time.Second,
}
}
// 内存池优化
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 32*1024)
},
}
执行时间估算:
- 纯抓取方案:使用10个并发,每页延迟500ms,约需:40页 × 0.5秒 = 20秒基础时间 + 3000个详情页抓取 ≈ 5-10分钟
- 浏览器自动化:使用5个并行Chrome实例,每个页面加载3秒,约需:3000个页面 ÷ 5并发 × 3秒 = 1800秒 ≈ 30分钟
建议方案:
- 首先尝试直接HTTP请求抓取(方案1)
- 如果遇到JavaScript渲染内容,使用无头浏览器(方案2)
- 对于3000个职位,建议采用混合方案,优先使用API接口,必要时使用浏览器自动化
这些方案在16GB内存的机器上处理3000个职位发布完全可行,内存占用通常在500MB-2GB之间,具体取决于并发级别和页面复杂度。

