Go写的爬虫

今天整理资料,惊奇发现去年7月份参加GDG的“七周七语言”活动时候,写的一个Go语言程序的。程序很简单,主要是访问一个博客网站,下载并保存网页,具体要求请见[url]http://be001.com/jams/110[/url]

先上程序:

package main

import (
"fmt"
"os"
"log"
"net/http"
"io/ioutil"
"bytes"
"encoding/base64"
"path"
"strings"
"regexp"
)

const (
BASEURL = "http://blog.youkuaiyun.com/xushiweizh"
PATTERN = "href=\"([^<\"]+)\""
INDEX = len(BASEURL)
ROOT = "C:/docs/GoCode/disk/"
)

func getContent(url string) string{
resp,err := http.Get(url)
if err != nil{
//handle error
log.Fatal(err)
}
defer resp.Body.Close()
body,err := ioutil.ReadAll(resp.Body)
return string(body)
}

func base64Encoding(s string)string{
var buf bytes.Buffer
encoder := base64.NewEncoder(base64.StdEncoding, &buf)
defer encoder.Close()
encoder.Write([]byte(s))
return buf.String()
}

func saveFile(content,filename string)error{
base64Name := base64Encoding(filename)
if base64Name == "" {
return nil
}
fout,err := os.Create(path.Join(ROOT,base64Name))
defer fout.Close()
if err != nil{
//handler error
log.Fatal(err)
return err
}
for _,line := range strings.Split(content,"\r\n"){
fout.WriteString(line + "\r\n")
}
return nil
}

func save(url string,links map[string]bool){
content := getContent(url)
err := saveFile(content,url[INDEX:])
if err != nil{
log.Fatal(err)
}
links[url]=true
}

func traverse(regxp *regexp.Regexp, url string, links map[string]bool){
LAST := strings.LastIndex(BASEURL,"/")
for _, scan := range regxp.FindAllStringSubmatch(getContent(BASEURL),-1){
var url string
if strings.Contains(scan[1],"http://"){
if strings.Contains(scan[1],BASEURL){
url = scan[1]
}else{
continue
}
}else{
if strings.Contains(scan[1],BASEURL[LAST:]){
url = BASEURL[:LAST]+scan[1]
}else{
continue
}
}
if v,ok := links[url];ok{
if v == true {
fmt.Println("Has download")
}else{
save(url,links)
}
}else{
save(url,links)
}
}
}

func main(){
links := make(map[string] bool)
regxp,err := regexp.Compile(PATTERN)
if err != nil{
log.Fatal(err)
}
traverse(regxp,BASEURL,links)
for key,val := range links{
if !val{
traverse(regxp,key,links)
}
}
}


在使用 Go 语言实现多线程网络爬虫时,主要依赖于 Go 的并发特性,特别是 goroutine 和 channel。Go 协程(goroutine)是一种轻量级的线程机制,由 Go 运行时管理,可以高效地创建和调度成千上万的并发任务[^3]。 ### 多线程爬虫的核心设计 1. **任务分发机制** 使用 channel 来传递需要抓取的 URL 或者任务队列,多个 goroutine 并发地从 channel 中取出任务进行处理,这样可以有效地实现任务的并行处理。 2. **限制并发数量** 在实际应用中,并非并发数越多越好,过多的并发可能会导致目标服务器压力过大或触发反爬机制。可以通过使用带缓冲的 channel 或者 sync.WaitGroup 来控制最大并发数。 3. **数据采集与解析** 每个 goroutine 负责一个网页的下载和解析工作。使用 `net/http` 包发送请求,获取响应内容后,通过 HTML 解析库(如 `goquery`)提取所需的数据。 4. **持久化存储** 抓取到的数据可以通过另一个 channel 发送给专门负责入数据库或文件的 goroutine,以避免阻塞主抓取流程。 ### 示例代码结构 以下是一个简单的 Go 爬虫模板示例: ```go package main import ( "fmt" "net/http" "sync" ) const maxConcurrency = 5 // 最大并发数 func fetch(url string, wg *sync.WaitGroup) { defer wg.Done() resp, err := http.Get(url) if err != nil { fmt.Printf("Error fetching %s: %v\n", url, err) return } defer resp.Body.Close() // 此处添加页面解析逻辑 fmt.Printf("Fetched %s, status code: %d\n", url, resp.StatusCode) } func main() { urls := []string{ "https://example.com/page1", "https://example.com/page2", "https://example.com/page3", // 添加更多 URL... } var wg sync.WaitGroup semaphore := make(chan struct{}, maxConcurrency) // 控制并发数量 for _, url := range urls { wg.Add(1) go func(u string) { defer func() { <-semaphore }() fetch(u, &wg) }(url) semaphore <- struct{}{} } wg.Wait() } ``` ### 注意事项 - **错误处理**:确保在网络请求和解析过程中有完善的错误处理机制。 - **速率控制**:避免对单一网站发起过快请求,可适当加入随机延迟。 - **User-Agent 设置**:设置合理的 User-Agent,模拟浏览器访问,减少被封锁的风险。 - **Robots.txt 遵守**:遵守目标网站的 robots.txt 规则,尊重网站的爬取政策。 通过上述方法,你可以构建一个高效的多线程网络爬虫系统,适用于各种数据采集需求[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值