为了账号安全,请及时绑定邮箱和手机立即绑定

爬虫性能分析及优化

标签:
Go

前两天我们写了单任务版爬虫爬取了珍爱网用户信息,那么它的性能如何呢?

我们可以通过网络利用率看一下,我们用任务管理器中的性能分析窗口可以看到下载速率大概是保持在了200kbps左右,这可以说是相当慢了。

image

我们针对来通过分析单任务版爬虫的设计来看下:

image

从上图我们可以看出,engine将request从任务队列取出来,送到Fetcher取获取资源,等待数据返回,然后将返回的数据送到Parser去解析,等待其返回,把返回的request再加到任务队列里,同时把item打印出来。

慢就慢在了没有充分利用网络资源,其实我们可以同时发送多个Fetcher和Pareser,等待其返回的同时,可以去做其他的处理。这一点利用go的并发语法糖很容易实现。

image

上图中,Worker是Fetcher和Parser的合并,Scheduler将很多Request分发到不同的Worker,Worker将Request和Items返回到Engine,Items打印出来,再把Request放到调度器里。

基于此用代码实现:

Engine:

package engine

import (
 "log"
)

type ConcurrentEngine struct {
 Scheduler Scheduler
 WokerCount int
}

type Scheduler interface {
 Submit(Request)
 ConfigureMasterWorkerChan(chan Request)
}

func (e *ConcurrentEngine) Run(seeds ...Request) {

 in := make(chan Request)
 out := make(chan ParserResult)

 e.Scheduler.ConfigureMasterWorkerChan(in)

 //创建Worker
 for i := 0; i < e.WokerCount; i   {
   createWorker(in, out)
 }


 //任务分发给Worker
 for _, r := range seeds {
   e.Scheduler.Submit(r)
 }


 for  {

   //打印out的items
   result := <- out
   for _, item := range result.Items {
     log.Printf("Get Items: %v\n", item)
   }

   //将out里的Request送给Scheduler
   for _, r := range result.Requests {
     e.Scheduler.Submit(r)
   }

 }
}

//workerConut goroutine to exec worker for Loop
func createWorker(in chan Request, out chan ParserResult) {
 go func() {
   for {
     request := <-in

     parserResult, err := worker(request)

     //发生了错误继续下一个
     if err != nil {
       continue
     }

     //将parserResult送出
     out <- parserResult
   }
 }()
}

Scheduler:

package scheduler

import "crawler/engine"

//SimpleScheduler one workChan to multi worker
type SimpleScheduler struct {
 workChan chan engine.Request
}

func (s *SimpleScheduler) ConfigureMasterWorkerChan(r chan engine.Request) {
 s.workChan = r
}

func (s *SimpleScheduler) Submit(r engine.Request) {
 go func() { s.workChan <- r }()
}

Worker:

func worker(r Request) (ParserResult, error) {

 log.Printf("fetching url:%s\n", r.Url)
 //爬取数据
 body, err := fetcher.Fetch(r.Url)

 if err != nil {
   log.Printf("fetch url: %s; err: %v\n", r.Url, err)
   //发生错误继续爬取下一个url
   return ParserResult{}, err
 }

 //解析爬取到的结果
 return r.ParserFunc(body), nil
}

main函数:

package main

import (
 "crawler/engine"
 "crawler/zhenai/parser"
 "crawler/scheduler"
)

func main() {

 e := &engine.ConcurrentEngine{
   Scheduler: &scheduler.SimpleScheduler{},
   WokerCount :100,
 }

 e.Run(
   engine.Request{
     Url:        "http://www.zhenai.com/zhenghun",
     ParserFunc: parser.ParseCityList,
   })

}

这里开启100个Worker,运行后再次查看网络利用率,变为3M以上。

image

由于代码篇幅较长,需要的同学可以关注公众号回复:go爬虫 获取。



本公众号免费**提供csdn下载服务,海量IT学习资源,**如果你准备入IT坑,励志成为优秀的程序猿,那么这些资源很适合你,包括但不限于java、go、python、springcloud、elk、嵌入式 、大数据、面试资料、前端 等资源。同时我们组建了一个技术交流群,里面有很多大佬,会不定时分享技术文章,如果你想来一起学习提高,可以公众号后台回复【2】,免费邀请加技术交流群互相学习提高,会不定期分享编程IT相关资源。


扫码关注,精彩内容第一时间推给你

image

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
5
获赞与收藏
23

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消