全球主机交流论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

IP归属甄别会员请立即修改密码
查看: 603|回复: 2
打印 上一主题 下一主题

Golang协程并发爬取图片源码,仅供学习

[复制链接]
跳转到指定楼层
1#
发表于 2022-7-10 16:25:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. package main

  2. import (
  3.         "fmt"
  4.         "io/ioutil"
  5.         "net/http"
  6.         "os"
  7.         "regexp"
  8.         "strconv"
  9.         "strings"
  10.         "sync"
  11.         "time"
  12. )

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

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

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

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

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

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

  35.         waitGroup.Add(1)
  36.         go checkOk()

  37.         waitGroup.Wait()

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

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

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

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

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

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

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

  56.         taskChan <- url

  57.         waitGroup.Done()
  58. }

  59. // 处理图片方法
  60. func handleImg() {
  61.         for url := range imgChan {
  62.                 fileName := GetFilenameFromUrl(url)
  63.                 result := DownloadFile(url, fileName)
  64.                 if result {
  65.                         fmt.Printf("已下载完毕 %v \n", url)
  66.                 } else {
  67.                         fmt.Printf("下载失败 %v \n", url)
  68.                 }
  69.         }
  70.         waitGroup.Done()
  71. }

  72. // 检查管道任务是否完成
  73. func checkOk() {
  74.         count := 0
  75.         for {
  76.                 url := <-taskChan
  77.                 fmt.Printf("完成爬取:%v \n", url)
  78.                 count++
  79.                 if count == pageSize {
  80.                         close(imgChan)
  81.                         close(taskChan)
  82.                         break
  83.                 }
  84.         }

  85.         waitGroup.Done()
  86. }

  87. // 截取url名字
  88. func GetFilenameFromUrl(url string) (filename string) {
  89.         // 返回最后一个/的位置
  90.         lastIndex := strings.LastIndex(url, "/")
  91.         // 切出来
  92.         filename = url[lastIndex+1:]
  93.         // 时间戳解决重名
  94.         timePrefix := strconv.Itoa(int(time.Now().UnixNano()))
  95.         filename = timePrefix + "_" + filename
  96.         return
  97. }

  98. // 下载文件方法
  99. func DownloadFile(url string, filename string) bool {
  100.         var err error
  101.         resp, err := http.Get(url)
  102.         if err != nil {
  103.                 fmt.Println(err)
  104.         }
  105.         defer resp.Body.Close()
  106.         bytes, err := ioutil.ReadAll(resp.Body)
  107.         if err != nil {
  108.                 fmt.Println(err)
  109.         }

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

  117.         filename = DownLoadPath + filename
  118.         err = ioutil.WriteFile(filename, bytes, 0666)
  119.         if err != nil {
  120.                 return false
  121.         }
  122.         return true
  123. }
复制代码
2#
发表于 2022-7-10 16:29:42 | 只看该作者
人生苦短,我用PYTHON
3#
发表于 2022-7-10 16:32:48 | 只看该作者
支持看到了if err 舒服了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|全球主机交流论坛

GMT+8, 2025-12-13 22:49 , Processed in 0.057795 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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