巧妙利用channel进行golang并发式爬虫
生活随笔
收集整理的這篇文章主要介紹了
巧妙利用channel进行golang并发式爬虫
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
上面一篇博客的代碼是串行化,沒有最大利用go語言的天生協程特性,如下代碼使用channel管道加上goroutine實現高并發編程:
package mainimport ("fmt""io""net/http""os""strconv" )// 爬取單個頁面的函數 func SpiderPage(i int, page chan int) {url := "https://tieba.baidu.com/f?kw=%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F&ie=utf-8&pn=" + strconv.Itoa((i-1)*50)result, err := HttpGet(url)if err != nil {fmt.Println("httpGet err", err)return}//fmt.Println("result=", result)f, err := os.Create("第" + strconv.Itoa(i) + "頁" + ".html")if err != nil {fmt.Println("Create err", err)return}f.WriteString(result)f.Close() // 保存好一個文件,關閉一個文件,不要用deferpage <- i //與主go程完成同步 }func working(start int, end int) {fmt.Printf("正在爬取第%d頁到%d頁", start, end)page := make(chan int)// 循環讀取頁數for i := start; i <= end; i++ {go SpiderPage(i, page)}// 如果不使用channel會直接讓主go程退出,所以使用無緩存的channel進行阻塞for i := start; i <= end; i++ {fmt.Printf("第%d個頁面爬取完成", <-page)}}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 = err2return}// 累加每一次循環讀到的buf數據,存入result一次性讀取result += string(buf[:n])}return}func main() {// 指定爬取起始,終止頁var start, end intfmt.Print("請輸入爬取的起始頁:")fmt.Scan(&start)fmt.Println("請輸入終止頁")fmt.Scan(&end)working(start, end) }測試了下爬取十頁數據,瞬間完成:
總結
以上是生活随笔為你收集整理的巧妙利用channel进行golang并发式爬虫的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用go语言完成爬虫
- 下一篇: 正则表达式加golang爬虫爬取经典案例