并发版百度爬虫:

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