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) }