吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2518|回复: 3
收起左侧

[其他原创] Golang协程并发爬取图片源码,仅供学习

[复制链接]
18978429109 发表于 2022-3-20 00:57
本帖最后由 18978429109 于 2022-3-20 01:05 编辑

效果图

1647708749(1).jpg

image.png

-----------------------------------------------------------------------------------------------------------------------------------------------------------------
上代码
[Golang] 纯文本查看 复制代码
package main

import (
        "fmt"
        "io/ioutil"
        "net/http"
        "os"
        "regexp"
        "strconv"
        "strings"
        "sync"
        "time"
)

var (
        reImg        = `https?://[^"]+?(\.((jpg)|(png)|(jpeg)|(gif)|(bmp)))`
        taskChan     chan string                                                      // 记录任务完成的通道
        imgChan      chan string                                                      // 图片通道
        waitGroup    sync.WaitGroup                                                   // 协程会涉及到并发,这个的作用具体的可百度
        pageStart    int            = 1                                               // 从第几页开始
        pageSize     int            = 30                                              // 扫描页数
        DownLoadPath string         = "D:/HBuilderX/project/GolangProject/爬虫小案例/img/" // 此处是图片下载的地址,需要修改为你们自己的地址
)

func main() {
        fmt.Println("从第几页开始")
        fmt.Scanln(&pageStart)

        fmt.Println("扫描页数")
        fmt.Scanln(&pageSize)

        taskChan = make(chan string, pageSize) // 给管道缓冲值
        imgChan = make(chan string, 100000)    // 给管道缓冲值

        for i := pageStart; i < pageStart+pageSize; i++ {
                waitGroup.Add(1)
                go getWebBody(i) // 获取地址的body
        }

        waitGroup.Add(1)
        go handleImg() // 处理img

        waitGroup.Add(1)
        go checkOk()

        waitGroup.Wait()

        fmt.Println("执行完毕,回车退出")
        var input string
        fmt.Scanln(&input)
}

func getWebBody(i int) {
        url := "https://www.bizhizu.cn/shouji/tag-%E5%8F%AF%E7%88%B1/" + strconv.Itoa(i) + ".html"
        resp, err := http.Get(url)
        if err != nil {
                fmt.Println(err)
        }
        defer resp.Body.Close() // 此处不可少,否则会造成内存泄露或者溢出问题

        body, _ := ioutil.ReadAll(resp.Body)

        re := regexp.MustCompile(reImg) // 正则匹配图片地址

        result := re.FindAllStringSubmatch(string(body), -1)

        println("第" + strconv.Itoa(i) + "页找到数据" + strconv.Itoa(len(result)) + "条")

        for _, v := range result {
                imgChan <- v[0] // 把得到的数据写到 管道 里
        }

        taskChan <- url

        waitGroup.Done()
}

// 处理图片方法
func handleImg() {
        for url := range imgChan {
                fileName := GetFilenameFromUrl(url)
                result := DownloadFile(url, fileName)
                if result {
                        fmt.Printf("已下载完毕 %v \n", url)
                } else {
                        fmt.Printf("下载失败 %v \n", url)
                }
        }
        waitGroup.Done()
}

// 检查管道任务是否完成
func checkOk() {
        count := 0
        for {
                url := <-taskChan
                fmt.Printf("完成爬取:%v \n", url)
                count++
                if count == pageSize {
                        close(imgChan)
                        close(taskChan)
                        break
                }
        }

        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 DownloadFile(url string, filename string) bool {
        var err error
        resp, err := http.Get(url)
        if err != nil {
                fmt.Println(err)
        }
        defer resp.Body.Close()
        bytes, err := ioutil.ReadAll(resp.Body)
        if err != nil {
                fmt.Println(err)
        }

        if _, err := os.Stat(DownLoadPath); os.IsNotExist(err) {
                // 必须分成两步
                // 先创建文件夹
                os.Mkdir(DownLoadPath, 0777)
                // 再修改权限
                os.Chmod(DownLoadPath, 0666)
        }

        filename = DownLoadPath + filename
        err = ioutil.WriteFile(filename, bytes, 0666)
        if err != nil {
                return false
        }
        return true
}






发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

mokleolee 发表于 2022-3-20 08:57
好东西啊。。。
15504582159 发表于 2022-3-20 09:17
wws741 发表于 2022-4-25 23:18
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 07:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表