Go最新Go分布式爬虫笔记(二十二)_extensions randomua,2024年最新Golang架构组件Room功能详解

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

return errors.New("Max depth limit reached")

}
return nil
}

func (s *Schedule) CreateWork() {
for {
r := <-s.workerCh
if err := r.Check(); err != nil {
s.Logger.Error(“check failed”,
zap.Error(err),
)
continue
}

}
}


## 避免请求重复


目的:


* 避免死循环
* 无效爬取


考虑点:


* 用什么数据结构来存储数据才能保证快速地查找到请求的记录?  
哈希表
* 如何保证并发查找与写入时,不出现并发冲突问题?  
 锁, sync.Map
* 在什么条件下,我们才能确认请求是重复的,从而停止爬取?  
 任务进行前检查


在解决上面的三个问题之前,我们先优化一下代码。我们之前的 Request 结构体会在每一次请求时发生变化,但是我们希望有一个字段能够表示一整个网站的爬取任务,因此我们需要抽离出一个新的结构 **Task ​**作为一个**爬虫任务**,而 Request 则作为单独的请求存在。有些参数是整个任务共有的,例如 Task 中的 Cookie、MaxDepth(最大深度)、WaitTime(默认等待时间)和 RootReq(任务中的第一个请求)。



type Task struct {
Url string
Cookie string
WaitTime time.Duration
MaxDepth int
RootReq *Request
Fetcher Fetcher
}

// 单个请求
type Request struct {
Task *Task
Url string
Depth int
ParseFunc func([]byte, *Request) ParseResult
}


由于抽象出了 Task,代码需要做对应的修改,例如我们需要把初始的 Seed 种子任务替换为 Task 结构。



for i := 0; i <= 0; i += 25 {
str := fmt.Sprintf(“https://www.douban.com/group/szsh/discussion?start=%d”, i)
seeds = append(seeds, &collect.Task{

Url: str,
RootReq: &collect.Request{
ParseFunc: doubangroup.ParseURL,
},
})
}


同时,在深度检查时,每一个请求的最大深度需要从 Task 字段中获取。



func (r *Request) Check() error {
if r.Depth > r.Task.MaxDepth {
return errors.New(“Max depth limit reached”)
}
return nil
}


接下来,我们继续用一个哈希表结构来存储历史请求。  
 由于我们希望随时访问哈希表中的历史请求,所以把它放在 Request、Task 中都不合适。 放在调度引擎中也不合适,因为调度引擎从功能上讲,应该只负责调度才对。所以,我们还需要完成一轮抽象,**将调度引擎抽离出来作为一个接口,让它只做调度的工作,不用负责存储全局变量等任务。**



type Crawler struct {
out chan collect.ParseResult //负责处理爬取后的数据,完成下一步的存储操作。schedule 函数会创建调度程序,负责的是调度的核心逻辑。
Visited map[string]bool //存储请求访问信息
VisitedLock sync.Mutex
options
}

type Scheduler interface {
Schedule() //启动调度器
Push(…*collect.Request) //将请求放入到调度器中
Pull() *collect.Request //从调度器中获取请求
}

type Schedule struct {
requestCh chan *collect.Request //负责接收请求
workerCh chan *collect.Request //负责分配任务给 worker
reqQueue []*collect.Request
Logger *zap.Logger
}


Visited 中的 Key 是请求的唯一标识,我们现在先将唯一标识设置为 URL + method 方法,并使用 MD5 生成唯一键。后面我们还会为唯一标识加上当前请求的规则条件。



// 请求的唯一识别码
func (r *Request) Unique() string {
block := md5.Sum([]byte(r.Url + r.Method))
return hex.EncodeToString(block[:])
}


接着,编写 HasVisited 方法,判断当前请求是否已经被访问过。StoreVisited 方法用于将请求存储到 Visited 哈希表中。



func (e *Crawler) HasVisited(r *collect.Request) bool {
e.VisitedLock.Lock()
defer e.VisitedLock.Unlock()
unique := r.Unique()
return e.Visited[unique]
}

func (e *Crawler) StoreVisited(reqs …*collect.Request) {
e.VisitedLock.Lock()
defer e.VisitedLock.Unlock()

for _, r := range reqs {
unique := r.Unique()
e.Visited[unique] = true
}
}


最后在 Worker 中,在执行 request 前,判断当前请求是否已被访问。如果请求没有被访问过,将 request 放入 Visited 哈希表中。



func (s *Crawler) CreateWork() {
for {
r := s.scheduler.Pull()
if err := r.Check(); err != nil {
s.Logger.Error(“check failed”,
zap.Error(err),
)
continue
}
// 判断当前请求是否已被访问
if s.HasVisited® {
s.Logger.Debug(“request has visited”,
zap.String(“url:”, r.Url),
)
continue
}
// 设置当前请求已被访问
s.StoreVisited®

}
}


## 设置优先队列


爬虫任务的优先级有时并不是相同的,一些任务需要优先处理。因此,接下来我们就来设置一个任务的优先队列。优先队列还可以分成多个等级,在这里将它简单地分为了两个等级,即优先队列和普通队列。优先级更高的请求会存储到 priReqQueue 优先队列中。



type Schedule struct {
requestCh chan *collect.Request
workerCh chan *collect.Request
priReqQueue []*collect.Request
reqQueue []*collect.Request
Logger *zap.Logger
}



## 设置随机User-Agent



![img](https://img-blog.csdnimg.cn/img_convert/63d979e705b1a26fbe50368a3e8b59b2.png)
![img](https://img-blog.csdnimg.cn/img_convert/b848e30ae193fd9f17814e06b0062be5.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值