Golang实现的搜索引擎爬虫机器人分享

Golang实现的搜索引擎爬虫机器人分享 大家好, 来看看我新开发的机器人,它可以通过搜索语法和关键词爬取必应搜索引擎。

这个机器人是多线程的,你可以限制线程数量。

它会在你的本地主机上输出结果。

它能够爬取到必应搜索的最后一页(无需指定需要爬取的页面数量)。

而且它不需要任何外部依赖包。

以下是代码:

GitHub

AnikHasibul/BingBot

头像

AnikHasibul/BingBot

BingBot - 一个用于网站收集的简单多线程必应搜索客户端。


更多关于Golang实现的搜索引擎爬虫机器人分享的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

也许我能理解70%

让我来处理这个问题。我会尽我所能。

你能推荐一些精通并发的资源吗?

提前感谢 😊

更多关于Golang实现的搜索引擎爬虫机器人分享的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢朋友!

终于我解决了竞态条件问题! 而且我已经移除了机器人所有不必要的部分!

感谢你提供的宝贵建议! 我学到了新知识!

你好 @giulio_iotti

我已经尽力解决这个问题 😞

但还是没能成功。

你能帮帮我吗?

谢谢!

GitHub

头像

golang/go

go - Go 编程语言

这很不错,但请确保使用竞态检测器进行构建和运行(“go install -race”),你会发现一些问题。

粗略来看,你用于计算速度的全局变量"total"需要在goroutine之间安全传递…

func main() {
    fmt.Println("hello world")
}

当然!你需要解决两个主要问题:

  1. 第一个打印进度统计信息的 Go 协程:它必须在一个 select 语句中读取一个通道,同时还要处理定时器。例如,当扫描新页面时,该通道会收到一个数字(通常就是 1)。你可以接收这个数字,并将其累加到(局部变量)已扫描页面的计数器中。在 select 语句的定时器分支中,你打印出秒数和总数。

  2. 你使用“发射后不管”的协程来写入一些文件。简单的解决方案是不使用协程。但务必检查返回的错误!写入文件经常会产生错误(主要是权限问题…) 如果你确实想使用协程,你仍然需要等待它完成,否则你的软件可能会在磁盘写入完成之前就结束了,导致文件只写入了一半。提示:你可以使用一个全局的 sync.WaitGroup 来实现…

PS:这些东西很难。别灰心,你正在编写一个很棒的软件。当你掌握了并发,你就掌握了编程中的一切。

这是一个非常实用的Golang项目,展示了如何构建一个轻量级但功能完整的搜索引擎爬虫。以下是对代码结构和关键实现的详细分析:

核心架构分析

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "regexp"
    "strconv"
    "strings"
    "sync"
    "time"
)

// 配置结构体
type Config struct {
    Query      string
    Threads    int
    OutputFile string
}

// 结果结构体
type Result struct {
    Title string
    URL   string
}

多线程爬取实现

func worker(queries <-chan string, results chan<- Result, wg *sync.WaitGroup) {
    defer wg.Done()
    
    for query := range queries {
        urls := scrapeBing(query)
        for _, result := range urls {
            results <- result
        }
    }
}

func scrapeBing(query string) []Result {
    var results []Result
    page := 0
    
    for {
        searchURL := buildBingURL(query, page)
        resp, err := http.Get(searchURL)
        if err != nil {
            break
        }
        defer resp.Body.Close()
        
        body, _ := ioutil.ReadAll(resp.Body)
        pageResults := parseBingResults(string(body))
        
        if len(pageResults) == 0 {
            break // 没有更多结果
        }
        
        results = append(results, pageResults...)
        page++
        time.Sleep(1 * time.Second) // 礼貌延迟
    }
    
    return results
}

URL构建和结果解析

func buildBingURL(query string, page int) string {
    baseURL := "https://www.bing.com/search"
    params := url.Values{}
    params.Add("q", query)
    params.Add("first", strconv.Itoa(page*10+1))
    return baseURL + "?" + params.Encode()
}

func parseBingResults(html string) []Result {
    var results []Result
    // 使用正则表达式提取标题和URL
    titleRegex := regexp.MustCompile(`<h2><a[^>]*href="([^"]*)"[^>]*>([^<]*)</a></h2>`)
    
    matches := titleRegex.FindAllStringSubmatch(html, -1)
    for _, match := range matches {
        if len(match) == 3 {
            results = append(results, Result{
                Title: strings.TrimSpace(match[2]),
                URL:   match[1],
            })
        }
    }
    return results
}

主控制流程

func main() {
    config := Config{
        Query:      "Golang programming",
        Threads:    5,
        OutputFile: "results.txt",
    }
    
    queries := make(chan string, 100)
    results := make(chan Result, 1000)
    var wg sync.WaitGroup
    
    // 启动工作线程
    for i := 0; i < config.Threads; i++ {
        wg.Add(1)
        go worker(queries, results, &wg)
    }
    
    // 发送查询任务
    go func() {
        queries <- config.Query
        close(queries)
    }()
    
    // 收集结果
    go func() {
        wg.Wait()
        close(results)
    }()
    
    // 输出结果
    for result := range results {
        fmt.Printf("Title: %s\nURL: %s\n\n", result.Title, result.URL)
    }
}

技术亮点

  1. 零依赖实现:仅使用标准库,便于部署和维护
  2. 自动分页处理:通过检测结果数量自动判断是否还有下一页
  3. 并发控制:通过channel和sync.WaitGroup实现安全的并发爬取
  4. 礼貌爬取:添加延时避免对搜索引擎造成过大压力

这个项目的代码结构清晰,展示了Golang在并发网络爬虫方面的优势,是一个很好的学习范例。

回到顶部