Go语言爬虫实战(线程池)

Go语言爬虫实战

目标

  • 利用go语言爬取指定网站的图片。
  • 实现爬取网站任意页面所有所需的图片。
  • 实现使用go语言线程池开启多个线程爬取图片内容。
  • 最后实现创建多个文件夹存储图片。

爬取网站图片

步骤

  • 对指定URL发去GET请求,获取对应的响应。

    • resp, err := http.Get(url)
  • 通过返回的响应获取网站的Html文本内容

    • BodyData, err := io.ReadAll(resp.Body)
  • 通过观察Html文本中图片的地址,并写出对应的正则表达式,匹配所有符合的图片信息。

    • 细节:通过浏览器的开发者模式,可以更快找到图片的地址

    • reImg := `https?://[^"]+?(\.((jpg)|(png)|(jpeg)|(gif)|(bmp)))`
      
  • 保存正则表达式的匹配结果,并对其发起GET请求获取图片资源信息。

    • //创建正则表达式的对象
      compile, err := regexp.Compile(reImg)
      //根据网站得Html内容匹配符合条件的结果,-1的意思是匹配所有结果。正数则表示匹配对应数字的结果
      allResult := compile.FindAllString(string(BodyData), -1)
      //获取图片资源
      for i, resultUrl := range allResult {...}
      
  • 保存图片到指定的文件夹

    • //获取图片信息
      data, err := io.ReadAll(get.Body)
      //创建指定文件夹
      mkdirPath := "./img/" + "img_" + strconv.Itoa(num) + "/"
      os.MkdirAll(mkdirPath, os.ModePerm)
      //创建文件保存图片信息
      file, err := os.OpenFile(mkdirPath+"cutImg_"+name, os.O_CREATE|os.O_RDWR, os.ModePerm)
      //将图片信息写入文件
      _, err = file.Write(data)
      

实现爬取网站任意页面

思路

  • 可以通过对网站的观察我们可以发现网站各个页面之间微小的变化,然后将需要爬取的网页存储在一个切片当中,之后重复第一步即可。

  • 例如:https://desk.3gbizhi.com/deskFJ/该网站的网页信息,通过点击翻页可以发现一些规律

    • https://desk.3gbizhi.com/deskFJ/index_1.html 第一页
    • https://desk.3gbizhi.com/deskFJ/index_2.html 第二页
    • https://desk.3gbizhi.com/deskFJ/index_3.html 第三页
    • 所以这里我们只需改变后面的数字即可获取对应页数的网页信息,并开始爬取图片信息。
  • 代码

    var start int
    var end int
    fmt.Printf("请输入爬取的开始页数:")
    fmt.Scanf("%d\n", &start)
    fmt.Printf("请输入爬取的结束页数:")
    fmt.Scanf("%d\n", &end)
    reImg := `https?://[^"]+?(\.((jpg)|(png)|(jpeg)|(gif)|(bmp)))`
    for i := 0; i < end-start+1; i++ {...urls[i].Url = "https://desk.3gbizhi.com/deskFJ/index_" + strconv.Itoa(urls[i].Id) + ".html"...
    }
    

线程池开启多个线程

  • 可以查看往期文章
    • https://editor.csdn.net/md/?articleId=137082930

创建多个文件夹存储图片

  • 创建文件夹

    • os.MkdirAll(mkdirPath, os.ModePerm)
  • 在存储图片的时候,获取图片的后缀以及获取图片原名称来命名图片

    • //截取名字和后缀
      index := strings.LastIndex(resultUrl, "/")
      name := resultUrl[index+1:]

项目结构图片

在这里插入图片描述


项目代码

//pool.go
package workerimport ("log""math""sync"
)// Args 参数结构体
type Args struct {Url   stringReImg stringId    int
}// Task 定义任务函数类型
type Task func(num int, url string, reImg string) interface{}//type Task func() interface{}type Pool struct {worker  inttasks   *Queueevents  chan struct{}results chan interface{}wg      sync.WaitGroup
}// NewPool 创建pool
func NewPool(worker int) *Pool {return &Pool{worker:  worker,tasks:   NewQueue(-1),events:  make(chan struct{}, math.MaxInt),results: make(chan interface{}, worker*2),wg:      sync.WaitGroup{},}
}// AddTasks 任务添加
func (p *Pool) AddTasks(task Task) {err := p.tasks.Push(task)if err != nil {log.Println(err)return}p.events <- struct{}{}
}// Start 启动工作池
func (p *Pool) Start(urls []Args) chan interface{} {var index = -1var IndexLock sync.Mutexfor i := 0; i < p.worker; i++ {p.wg.Add(1)go func() {for range p.events {task, err := p.tasks.Pop()if err != nil {log.Println(err)continue}IndexLock.Lock()index++IndexLock.Unlock()if task, ok := task.(Task); ok {p.results <- task(urls[index].Id, urls[index].Url, urls[index].ReImg)}}p.wg.Done()}()}return p.results
}// Wait 关闭池子
func (p *Pool) Wait() {close(p.events)p.wg.Wait()close(p.results)
}//queue.go
package workerimport ("fmt""sync"
)type Queue struct {elements []interface{}lock     sync.Mutexlimit    int
}// NewQueue 创建队列
func NewQueue(limit int) *Queue {return &Queue{elements: make([]interface{}, 0, 1024),lock:     sync.Mutex{},limit:    limit,}
}// Push 入队
func (q *Queue) Push(task interface{}) error {if q.limit != -1 && len(q.elements) >= q.limit {return fmt.Errorf("队列已满,请等待")}q.lock.Lock()defer q.lock.Unlock()q.elements = append(q.elements, task)return nil
}// Pop 出队
func (q *Queue) Pop() (interface{}, error) {if len(q.elements) == 0 {return nil, fmt.Errorf("队列以空,等带任务入队")}task := q.elements[0]q.elements = q.elements[1:]return task, nil
}//main.go
package mainimport ("fmt""io""log""net/http""os""regexp""src/worker""strconv""strings""time"
)// 爬虫流程
// 1.对网站发送Get请求
// 2.读取网站信息
// 3.提取图片路径
// 4.下载图片,保存起来func main() {var start intvar end intfmt.Printf("请输入爬取的开始页数:")fmt.Scanf("%d\n", &start)fmt.Printf("请输入爬取的结束页数:")fmt.Scanf("%d\n", &end)pool := worker.NewPool(5)reImg := `https?://[^"]+?(\.((jpg)|(png)|(jpeg)|(gif)|(bmp)))`urls := make([]worker.Args, end-start+1)for i := 0; i < end-start+1; i++ {urls[i].ReImg = reImgurls[i].Id = start + iurls[i].Url = "https://desk.3gbizhi.com/deskFJ/index_" + strconv.Itoa(urls[i].Id) + ".html"pool.AddTasks(GetUrlImage)}pool.Start(urls)pool.Wait()fmt.Printf("爬取结束!")
}func GetUrlImage(num int, url string, reImg string) interface{} {resp, err := http.Get(url)HandleError(err)//读取BodyData, err := io.ReadAll(resp.Body)HandleError(err)//解析数据compile, err := regexp.Compile(reImg)HandleError(err)allResult := compile.FindAllString(string(BodyData), -1)if allResult == nil {fmt.Printf("%d号线程找不到对应数据\n", num)return nil}fmt.Printf("%d号线程已经获取到%d个图片路径,准备下载\n", num, len(allResult))for i, resultUrl := range allResult {//截取名字index := strings.LastIndex(resultUrl, "/")name := resultUrl[index+1:]get, err := http.Get(resultUrl)HandleError(err)//下载图片now := time.Now()data, err := io.ReadAll(get.Body)HandleError(err)fmt.Println("图片耗时:", time.Now().Sub(now))mkdirPath := "./img/" + "img_" + strconv.Itoa(num) + "/"os.MkdirAll(mkdirPath, os.ModePerm)file, err := os.OpenFile(mkdirPath+"cutImg_"+name, os.O_CREATE|os.O_RDWR, os.ModePerm)HandleError(err)_, err = file.Write(data)HandleError(err)fmt.Printf("成功下载图片%d\n", i)}return nil
}// HandleError 错误
func HandleError(err error) {if err != nil {log.Println(err)return}
}

(mkdirPath, os.ModePerm)
file, err := os.OpenFile(mkdirPath+“cutImg_”+name, os.O_CREATE|os.O_RDWR, os.ModePerm)
HandleError(err)
_, err = file.Write(data)
HandleError(err)
fmt.Printf(“成功下载图片%d\n”, i)
}
return nil
}

// HandleError 错误
func HandleError(err error) {
if err != nil {
log.Println(err)
return
}
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2905757.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

SQL Server 实验二:数据库视图的创建和使用

目录 第一关 相关知识 什么是表 操作数据表 创建数据表 插入数据 修改表结构 删除数据表 编程要求 第一关实验代码&#xff1a; 第二关 相关知识 视图是什么 视图的优缺点 视图的优点 视图的缺点 操作视图 创建视图 通过视图向基本表中插入数据 通过视图修改基本表的…

【Unity】TextMeshPro富文本

启用富文本 在Unity里&#xff0c;如果需要使用富文本&#xff0c;首先需要开启Rich Text 如果不开启Rich Text&#xff0c;就会在UI上显示富文本代码 1.粗体 <b>Game</b> Over2.斜体 <i>Game</i> Over3.下划线 <u>Game</u> Over4…

【Linux】网络编程套接字二

网络编程套接字二 1.TCP网络编程1.1TCP Server服务端1.2 TCP Client客户端 2.Server 多进程版本2.1普通版2.2 信号版 3.Server 多线程版4.Server 线程池版5.日志函数重新设计6.守护进程7.TCP协议通讯流程8.TCP和UDP 对比 喜欢的点赞&#xff0c;收藏&#xff0c;关注一下把&…

人工智能|推荐系统——搜索引擎广告

原文题目 Dark sides of artificial intelligence: The dangers of automated decision-making in search engine advertising(JASIST,2023) 人工智能的阴暗面:搜索引擎广告自动决策的危险 摘要 随着人工智能应用的日益广泛,搜索引擎供应商越来越多地要求广告商使用基于机…

6.RGB转YCbcr

1.方法 RGB转灰度有很多种方式   1.将RGB中任意分量拿出来当做灰度值。   2.取RGB三通道的均值来当灰度值。   3.将RGB转YUV(YCbCr)然后取Y分量作为灰度值。   其余的几种实现方式较为简单&#xff0c;这里不做介绍。重点实现RGB转YCbCr。 1.1 YUV(YCbCr)格式 Y表示亮…

深度学习中的模型蒸馏技术:实现流程、作用及实践案例

在深度学习领域&#xff0c;模型压缩与部署是一项重要的研究课题&#xff0c;而模型蒸馏便是其中一种有效的方法。 模型蒸馏&#xff08;Model Distillation&#xff09;最初由Hinton等人在2015年提出&#xff0c;其核心思想是通过知识迁移的方式&#xff0c;将一个复杂的大模型…

HTTP——Cookie

HTTP——Cookie 什么是Cookie通过Cookie访问网站 我们之前了解了HTTP协议&#xff0c;如果还有小伙伴还不清楚HTTP协议&#xff0c;可以点击这里&#xff1a; https://blog.csdn.net/qq_67693066/article/details/136895597 我们今天来稍微了解一下HTTP里面一个很小的部分&…

解决“Pycharm中Matplotlib图像不弹出独立的显示窗口”问题

matplotlib的绘图的结果默认显示在SciView窗口中, 而不是弹出独立的窗口, 这样看起来就不是很舒服&#xff0c;不习惯。 通过修改设置&#xff0c;改成独立弹出的窗口。 File—>Settings—>Tools—>Python Scientific—>Show plots in toolwindow 将√去掉即可

Github多账号共存

在开发阶段&#xff0c;如果同时拥有多个开源代码托管平台的账户&#xff0c;在代码的管理上非常麻烦。那么&#xff0c;如果同一台机器上需要配置多个账户&#xff0c;怎样才能确保不冲突&#xff0c;不同账户独立下载独立提交呢&#xff1f; 我们以两个github账号进行演示 …

密码学基础-对称密码/公钥密码/混合密码系统 详解

密码学基础-对称密码/公钥密码 加解密说明1.加密解密必要因素加密安全性说明 什么是对称密码图示说明对称密码详解什么是DES?举例说明 什么是3DES什么是AES? 公钥密码什么是RSA? 对称密钥和公钥密码优缺点对比对称密码对称密码算法总结对称密码存在的问题? 公钥密码公钥密码…

工业镜头常用参数之实效F(Fno.)和像圈

Fno. 工业镜头中常用到的参数F&#xff0c;有时候用F/#&#xff0c;Fno.来表示&#xff0c;指的是镜头通光能力的参数。它可用镜头焦距及入瞳直径来表示&#xff0c;也可通过镜头数值孔径&#xff08;NA&#xff09;和光学放大倍率&#xff08;β&#xff09;来计算。有效Fno.…

linux系统装载nginx的笔记

作为一个前端开发&#xff0c;自己部署一个前端项目是不是很正常的事情&#xff0c;所以我在这里记录一下自己在linux环境中通过nginx部署前端项目的步骤&#xff0c;方便后面查看。 步骤如下&#xff1a; 1、使用管理员身份进入命令窗口&#xff0c;如果进入时提示&#xff0…

使用苹果应用商店上架工具实现应用快速审核与发布

摘要 移动应用app上架是开发者关注的重要环节&#xff0c;但常常会面临审核不通过等问题。为帮助开发者顺利完成上架工作&#xff0c;各种辅助工具应运而生。本文探讨移动应用app上架原理、常见辅助工具功能及其作用&#xff0c;最终指出合理使用工具的重要性。 引言 移动应…

阳光倒灌高准直汽车抬头显示器HUD太阳光模拟器

阳光倒灌高准直汽车抬头显示器HUD太阳光模拟器是一种高级别的模拟设备&#xff0c;用于模拟太阳光的光谱、强度及照射角度&#xff0c;应用于太阳能电池板、光伏系统等领域的研究和测试。其参数包括光谱范围、光强度、光源、照射角度、均匀性和稳定性&#xff0c;可根据需求调整…

2024最新彩虹知识付费模板MangoA全开源包含秒杀/抽奖/社群/推送等功能

二次开发增加以下功能每日秒杀每日签到官方社群多级分销在线抽奖项目投稿 每日秒杀 每日签到 官方社群 多级分销 在线抽奖 项目投稿 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88963704 更多资源下载&#xff1a;关注我。

应急响应靶机训练-Linux1题解

前言 接上文&#xff0c;应急响应靶机训练Linux1 靶机地址&#xff1a; 应急响应靶机-Linux(1) 最近感冒了&#xff0c;就没录视频版。 题解 目标&#xff1a;3个flag以及黑客的ip地址 登陆虚拟机 密码defend flag1: su history flag{thisismybaby} flag2&#xff1a;…

【学习】软件企业何时会选择第三方软件测试机构

近年来&#xff0c;随着软件行业的迅猛发展&#xff0c;软件企业对软件测试的需求也越来越大。为了保证软件的质量和稳定性&#xff0c;许多企业选择寻找第三方软件测试机构来进行软件测试。第三方软件测试机构是独立于软开发企业的专业机构&#xff0c;主要从事软件测试和质量…

OpenGL 实现“人像背景虚化“效果

手机上的人像模式,也被人们称作“背景虚化”或 ”双摄虚化“ 模式,也称为 Bokeh 模式,能够在保持画面中指定的人或物体清晰的同时,将其他的背景模糊掉。突出画面的主体部分,主观上美感更强烈。 人像模式的一般实现原理是,利用双摄系统获取景深信息,并通过深度传感器和图…

Vivado Lab Edition

Vivado Lab Edition 是完整版 Vivado Design Suite 的独立安装版本 &#xff0c; 包含在生成比特流后对赛灵思 FPGA 进行编程和 调试所需的所有功能。通常适用于在如下实验室环境内进行编程和调试&#xff1a; 实验室环境中的机器所含磁盘空间、内存和连 接资源较少。Vivad…