Golang诞生已经超过十个年头了,发展得愈发完善,其简单方便的协程并发机制使得其在爬虫领域有着一定的天赋。

    首先我们来看一看,Golang相对于Python这个爬虫领域的传统强者,有哪些优点和缺点。

    优点:

    1. 完善简便的协程并发机制
    2. 并发数量大
    3. 占用资源少
    4. 运行速度更快
    5. 部署方便

    缺点:

    数据处理比较繁琐
    成熟工具不是很多
    资料较少
    实现相同逻辑需要的代码更多
    

    由于Golang本身静态语言的特性,和其特别的异常处理方式等等原因,在发起较复杂的请求时需要的代码量自然会比Python多不少,但是其并发的数量也是远超Python的,所以两者应用的场景并不十分相同,我们可以根据需要灵活的选择。

    demo1.go代码如下:

    package main
    
    import (
        "bufio"
        "fmt"
        "io/ioutil"
        "net/http"
        "os"
        "regexp"
    )
    
    var (
        //这个\d表示数字
        reQQEmail = `\d+@qq.com`
        //w代表大小写字母+数字+下划线
        reEmail = `\w+@\w+\.\w+`
        //s?有或者没有s
        //+代表出1次或多次
        //\s\S各种字符
        //+?代表贪婪模式
        reLinke = `href="(https?://[\s\S]+?)"`
        rePhone = `1[3456789]\d\s?\d{4}\s?\d{4}`
        reImg   = `https?://[^"]+?(\.((jpg)|(png)|(jpeg)|(gif)))`
    )
    
    //抽取数据根据url获取内容
    func GetPageStr(url string) (pageStr string) {
        resp, err := http.Get(url)
        HandleError(err, "http.Get url")
        defer resp.Body.Close()
    
        //读取页面内容
        pageBytes, err := ioutil.ReadAll(resp.Body)
        HandleError(err, "ioutil.ReadAll")
        //字节转字符串
        pageStr = string(pageBytes)
        return pageStr
    }
    
    //爬邮箱方法二
    func GetEmail2(url string) {
        pageStr := GetPageStr(url)
        re := regexp.MustCompile(reEmail)
        results := re.FindAllStringSubmatch(pageStr, -1)
    
        for _, result := range results {
            fmt.Println(result)
        }
    }
    
    //爬邮箱
    func GetEmail() {
        //1.去网站拿数据
        resp, err := http.Get("https://tieba.baidu.com/p/6051076813?red_tag=1573533731")
        HandleError(err, "Http.Get url")
        defer resp.Body.Close()
        //2.读取页面内容
        pageBytes, err := ioutil.ReadAll(resp.Body)
        HandleError(err, "Readall Error")
        //字节转字符串
        pageStr := string(pageBytes)
        // fmt.Println(pageStr)
        //3.过滤数据,过滤qq邮箱
        re := regexp.MustCompile(reQQEmail)
        results := re.FindAllStringSubmatch(pageStr, -1)
        // WriteFiles(results[0][0])
        // WriteFiles(results[1][0])
        // WriteFiles(results[2][0])
    
        //遍历结果
        for i := 0; i < len(results); i++ {
            // fmt.Println(results[i][0])
            WriteFiles(results[i][0])
        }
        fmt.Println("写入成功")
    }
    
    //处理异常
    func HandleError(err error, why string) {
        if err != nil {
            fmt.Println(why, err)
        }
    }
    
    //爬链接
    func GetLink(url string) {
        pageStr := GetPageStr(url)
        re := regexp.MustCompile(reLinke)
        results := re.FindAllStringSubmatch(pageStr, -1)
        for _, result := range results {
            fmt.Println(result[1])
        }
    }
    
    //爬手机号
    func GetPhone(url string) {
        pageStr := GetPageStr(url)
        re := regexp.MustCompile(rePhone)
        results := re.FindAllStringSubmatch(pageStr, -1)
        for _, result := range results {
            fmt.Println(result)
        }
    }
    
    //爬图片
    func GetImg(url string) {
        pageStr := GetPageStr(url)
        re := regexp.MustCompile(reImg)
        results := re.FindAllStringSubmatch(pageStr, -1)
        for _, result := range results {
            fmt.Println(result[0])
        }
    }
    
    //写文件
    func WriteFiles(str string) {
        fileName := "/Users/imac/<a href="https://www.qqradios.com/tag/go" title="查看更多关于go的文章" target="_blank">go</a>/src/test/abc.txt"
        file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)
        HandleError(err, "OpenFile")
        defer file.Close()
    
        w := bufio.NewWriter(file)
        _, err = w.WriteString(str)
        HandleError(err, "WriteString")
        _, err = w.WriteString("\r\n")
        HandleError(err, "Write err")
        w.Flush()
    }
    
    // func main(){
    //     //1、爬邮箱
    //     // GetEmail()
    //     //2、爬邮箱方法二
    //     // GetEmail2("https://tieba.baidu.com/p/6051076813?red_tag=1573533731")
    //     //3、爬链接
    //     // GetLink("https://www.baidu.com/s?wd=qqhd")
    //     //4、爬手机号
    //     // GetPhone("https://www.qqradios.com/")
    //     //5.爬图片美女
    //     GetImg("https://www.qqradios.com/meizitu/")
    // }
    

    demo2.go代码如下:

    package main
    
    import (
        "fmt"
        "io/ioutil"
        "net/http"
        "regexp"
        "strconv"
        "strings"
        "sync"
        "time"
    )
    
    func myTest() {
        //pageStr:=GetPageStr("https://www.qqradios.com/page/2")
        //fmt.Println(pageStr)
        //获取链接
        GetImg("https://www.qqradios.com/page/2")
    }
    
    //下载图片
    func DownloadFile(url string, filename string) (ok bool) {
        resp, err := http.Get(url)
        HandleError(err, "Http.get.url")
        defer resp.Body.Close()
    
        bytes, err := ioutil.ReadAll(resp.Body)
        HandleError(err, "resp.body")
        filename = "./pa/img/" + filename
    
        //写出数据
        err = ioutil.WriteFile(filename, bytes, 0666)
        if err != nil {
            return false
        } else {
            return true
        }
    }
    
    var (
        //存放图片链接的数据管道
        chanImageUrls chan string
        waitGroup     sync.WaitGroup
        //用于监控携程
        chanTask chan string
    )
    
    func main() {
        //myTest()
        //DownloadFile("https://www.qqradios.com/uploads/allimg/201904/1555256296278615.jpg","1.jpg")
    
        //1、初始化管道
        chanImageUrls = make(chan string, 1000000)
        chanTask = make(chan string, 26)
        //2、爬虫携程
        for i := 1; i < 27; i++ {
            waitGroup.Add(1)
            <a href="https://www.qqradios.com/tag/go" title="查看更多关于go的文章" target="_blank">go</a> getImgUrls("https://www.qqradios.com/page/" + strconv.Itoa(i))
        }
        //3、任务统计协程,统计26个任务是否都完成,完成了就关闭管道
        waitGroup.Add(1)
        <a href="https://www.qqradios.com/tag/go" title="查看更多关于go的文章" target="_blank">go</a> CheckOK()
        //4、下载协程,从管道中读取链接并下载
        for i := 0; i < 5; i++ {
            waitGroup.Add(1)
            <a href="https://www.qqradios.com/tag/go" title="查看更多关于go的文章" target="_blank">go</a> DownloadImg()
        }
        waitGroup.Wait()
    }
    
    //下载图片
    func DownloadImg() {
        for url := range chanImageUrls {
            filename := GetFilenameFromUrl(url)
            ok := DownloadFile(url, filename)
            if ok {
                fmt.Printf("%s下载成功\n", filename)
            } else {
                fmt.Printf("%s下载失败\n", filename)
            }
        }
        waitGroup.Done()
    }
    
    //截取url名字
    func GetFilenameFromUrl(url string) (filename string) {
        //返回最后一个/的位置
        lastIndex := strings.LastIndex(url, "/")
        //切出来
        filename = url[lastIndex+1:]
        //时间戳解决重名
        timePrefix := strconv.Itoa(int(time.Now().UnixNano()))
        filename = timePrefix + "_" + filename
        return
    }
    
    //任务统计协程
    func CheckOK() {
        var count int
        for {
            url := <-chanTask
            fmt.Printf("%s完成了爬娶任务\n", url)
            count++
            if count == 26 {
                close(chanImageUrls)
                break
            }
        }
        waitGroup.Done()
    }
    
    //爬图片链接到管道
    func getImgUrls(url string) {
        urls := getImgs(url)
        //遍历切片里所有链接,存入数据管道
        for _, url := range urls {
            chanImageUrls <- url
        }
        //标知当前协程完成,每完成一个任务,写一条数据,用于监控协程知道已经完成了几个任务
        chanTask <- url
        waitGroup.Done()
    }
    
    //获取当前页图片链接
    func getImgs(url string) (urls []string) {
        pageStr := GetPageStr(url)
        re := regexp.MustCompile(reImg)
        results := re.FindAllStringSubmatch(pageStr, -1)
        fmt.Printf("共找到%d条结果\n", len(results))
    
        for _, result := range results {
            url := result[0]
            urls = append(urls, url)
        }
        return
    }
    

    Golang爬虫代码攻略运行效果如下
    WX20200119-130434.png
    原文:https://www.qqradios.com/2020/1250.html