GO爬虫爬取百度贴吧-并发版
并发版百度爬虫:
1. 封装 爬取一个网页内容的 代码 到 SpiderPage(index)函数中
2. 在 working 函数 for 循环启动 go 程 调用 SpiderPage() —— > n个待爬取页面,对应n个go程
3. 为防止主 go 程提前结束,引入 channel 实现同步。 SpiderPage(index,channel)
4. 在SpiderPage() 结尾处(一个页面爬取完成), 向channel中写内容 。 channel <- index
5. 在 working 函数 添加新 for 循环, 从 channel 不断的读取各个子 go 程写入的数据。 n个子go程 —— 写n次channel —— 读n次channel
并发CHANNEL示例
package main
import “fmt”
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 把 sum 发送到通道 c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 从通道 c 中接收
fmt.Println(x, y, x+y)
}
爬虫示例
package main
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
)
func HttpGet(url string) (result string,err error){
resp,err1 := http.Get(url)
if err1 != nil{
err = err1 //出错时将内部错误传出给调用者
return
}
defer resp.Body.Close()
//循环接收数据
buf := make([]byte,4096)
for{
n,err2 := resp.Body.Read(buf)
if n == 0{
//fmt.Println("读取网页完成")
break
}
if err2 != nil && err2 != io.EOF{
err = err2
return
}
result += string(buf[:n])
}
return
}
func SpiderWeb(i int,page chan int){
url := "https://tieba.baidu.com/f?kw=%E7%8E%8B%E8%80%85%E8%8D%A3%E8%80%80&ie=utf-8&cid=&tab=corearea&pn="+strconv.Itoa((i-1)*50)
result,err := HttpGet(url)
if err != nil{
fmt.Printf("页码%d出错跳过",i)
return
}
//fmt.Println("result=",result[:10])
//写入文件
fp,err := os.Create("D:\\www\\gostudy\\pachong\\html\\第"+strconv.Itoa(i)+"页.html")
if err != nil{
fmt.Println("创建失败",err)
return
}
fp.WriteString(result)
fp.Close() //每次都关闭
page <- i
}
func working(start int,end int) {
fmt.Printf("准备爬取页码%d-%d页\n",start,end)
//创建通道
var page = make(chan int)
for i:=start;i < end;i++{
go SpiderWeb(i,page) //并发函数
}
//通道数据接收
for i:=start;i < end;i++{
fmt.Printf("正在爬取%d页\n",<-page)
}
}
func main() {
var start, end int
fmt.Print("请输入要爬取的起始页码:")
fmt.Scan(&start)
fmt.Print("请输入要爬取的结束页码:")
fmt.Scan(&end)
working(start, end)
}