study
最近几年,golang挺热门的,使用这个技术栈的公司也不少,前段时间也一直想学习这个来着,但是一直断断续续,忘了又忘,这几天正好看到一个小例子,还挺好玩,感兴趣的可以从这里慢慢入门:
就是一个go的爬虫例子,但是在这个示例中,可以看到go里面一个很有趣的特性,相信这也是为什么很多人喜欢使用go。
首先说下什么是爬虫:
大部分应该都能理解,爬虫其实就是访问各种web服务器,然后获取其中的数据信息。
爬取的流程:
本次示例(百度贴吧爬取实例)---常规爬取 :
1.指定用户爬取的起始页 创建working函数
2.使用start end 循环爬取每一页数据
3.获取每一页的url---下一页=前一页+50
4.封装HTTP GET函数,实现httpGet,
目的是获取一个url数据内容,通过result返回。
5. 创建.html文件,分页保存。
使用go并发流程:
封装爬取一个网页的内容,到函数中(SpiderPage),修改相关参数
在working函数中,for循环启动go程调用,相当于爬取多少个页面,起多少个go子程
为防止主go程提前结束,引入chan,实现同步,传入进去spiderPage(chan)
在spiderPage结尾处,向channel写内容,channel<-index
在working函数中,添加新的for循环,从channel中b不断地读取各个子进程的写入的数据
代码如下所示:
package main
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
)
//crawl single page function
func spiderPage(index 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((index-1)*50)
result, err := httpGet(url)
if err != nil {
fmt.Println("httpGet err:", err)
return
}
//fmt.Println("result=", result)
//save read web data in file
f, err := os.Create("第 " + strconv.Itoa(index) + "页 " + ".html")
if err != nil {
fmt.Println("Create err:", err)
return
}
f.WriteString(result)
f.Close() //save file and close file
page <- index
}
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
}
//累加每一次循环读到的buf数据,存到result中,一次性返回
result += string(buf[:n])
}
return
}
//爬取页面操作
func working(start, end int) {
fmt.Print("正在爬取第%d页到%d页......\n", start, end)
page := make(chan int)
//循环爬取每一页的数据
for i := start; i <= end; i++ {
go spiderPage(i, page)
}
for i := start; i <= end; i++ {
fmt.Print("爬取第%d页......\n", <-page)
}
}
func main() {
//指定爬取起始 终止
var start, end int
fmt.Print("请输入爬取的起始页(>=1):")
fmt.Scan(&start)
fmt.Print("请输入爬取的终止页(>=1):")
fmt.Scan(&end)
working(start, end)
}
结果如下: