• 爬虫性能分析及优化


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

    我们可以通过网络利用率看一下,我们用任务管理器中的性能分析窗口可以看到下载速率大概是保持在了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
    ", 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
    ", r.Url)
     //爬取数据
     body, err := fetcher.Fetch(r.Url)
    
     if err != nil {
       log.Printf("fetch url: %s; err: %v
    ", 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

  • 相关阅读:
    OGG_GoldenGate数据控制进程Manager(案例)
    OGG_GoldenGate安装和环境搭建(案例)
    OGG_Oracle GoldenGate简介(概念)
    DBA_Oracle Erp R12系统文件结构(概念)
    PLSQL_统计信息系列10_统计信息过旧导致程序出现性能问题
    PLSQL_统计信息系列09_统计信息在不同数据库中迁移
    Hadoop2源码分析-准备篇
    高可用Hadoop平台-答疑篇
    高可用Hadoop平台-实战尾声篇
    高可用Hadoop平台-实战
  • 原文地址:https://www.cnblogs.com/liabio/p/11696045.html
Copyright © 2020-2023  润新知