• Ruby:多线程队列(Queue)下载博客文章到本地


    Ruby:多线程下载博客文章到本地的完整代码

    #encoding:utf-8
    require 'net/http'
    require 'thread'
    require 'open-uri'
    require 'nokogiri'
    require 'date'
    
    $queue = Queue.new
    #文章列表页数
    page_nums = 8
    page_nums.times do |num|
      $queue.push("http://www.cnblogs.com/hongfei/default.html?page="+num.to_s)
    end
    
    threads = []
    #获取网页源码
    def get_html(url)
      html = ""
      open(url) do |f|
        html = f.read
      end
      return html
    end
    
    def fetch_links(html)
      doc = Nokogiri::HTML(html)
      #提取文章链接
      doc.xpath('//div[@class="postTitle"]/a').each do |link|
        href = link['href'].to_s
        if href.include?"html"
          #add work to the  queue
          $queue.push(link['href'])
        end
      end
    end
    
    def save_to(save_to,content)
      f = File.new("./"+save_to+".html","w+")
      f.write(content)
      f.close()
    end
    
    #程序开始的时间
    $total_time_begin = Time.now.to_i
    
    #开辟的线程数
    threadNums = 10
    threadNums.times do
      threads<<Thread.new do
        until $queue.empty?
          url = $queue.pop(true) rescue nil
          html = get_html(url)
          fetch_links(html)
          if !url.include?"?page"
            title = Nokogiri::HTML(html).css('title').text
            puts "["+ Time.now.strftime("%H:%M:%S") + "]「" + title + "" + url
            save_to("pages/" + title.gsub(///,""),html) if url.include?".html"
          end
        end
      end
    end
    threads.each{|t| t.join}
    
    #程序结束的时间
    $total_time_end = Time.now.to_i
    puts "线程数:" + threadNums.to_s
    puts "执行时间:" + ($total_time_end - $total_time_begin).to_s + ""

    多线程部分讲解

    $queue = Queue.new
    #文章列表页数
    page_nums = 8
    page_nums.times do |num|
      $queue.push("http://www.cnblogs.com/hongfei/default.html?page="+num.to_s)
    end

    首先声明一个Queue队列,然后往队列中添加文章列表页,以便后面可以从这些列表页中提取文章链接,另外queue声明成全局变量($),以便在函数中也可以访问到
    我的曾是土木人博客文章列表总共有8页,所以需要实现给page_nums赋值为8

    #开辟的线程数
    threadNums = 10
    threadNums.times do
      threads<<Thread.new do
        until $queue.empty?
          url = $queue.pop(true) rescue nil
          html = get_html(url)
          fetch_links(html)
          if !url.include?"?page"
            title = Nokogiri::HTML(html).css('title').text
            puts "["+ Time.now.strftime("%H:%M:%S") + "]「" + title + "" + url
            save_to("pages/" + title.gsub(///,""),html) if url.include?".html"
          end
        end
      end
    end
    threads.each{|t| t.join}

    通过Thread.new来创建线程
    创建线程后,会进入until $queue.empty?循环,直到任务队列为空(即:没有要采集的网址了)
    开辟的线程,每次都会从任务队列(queue)取到一个url,并通过get_html函数获取网页源码
    由于任务队列中的url有分页url和文章url两种,所以要进行区分。
    如果是分页url(url中含有“?page”),就直接提取文章链接。
    如果是文章url,就保存到本地(save_to(),文件名为文章title)
    在循环体外,创建线程完毕后,需要将创建的线程执行Thread#join方法,以便让主线程等待,
    直到所有的线程执行完毕才结束主线程

     代码执行时间统计

    #程序开始的时间
    $total_time_begin = Time.now.to_i
    #执行过程
    
    #程序结束的时间
    $total_time_end = Time.now.to_i
    puts "执行时间:" + ($total_time_end - $total_time_begin).to_s + ""

    TIme模块的#now方法可以获取当前时间,然后使用to_i,可以将当前时间转换成从1970年1月1日00:00:00 UTC开始所经过的秒数。

    获取网页源码

    #获取网页源码
    def get_html(url)
      html = ""
      open(url) do |f|
        html = f.read
      end
      return html
    end

    ruby中,获取网页的方法用Net::HTTP模块和OpenURI模块。OpenURI模块最简单,可以直径将指定网页当成普通文件一样进行操作。

    执行结果:使用多线程采集130多篇文章,耗时15秒(单线程:47s左右)

    推荐阅读:


    Thread and Queue

    Ruby线程学习:并行发起http请求

    Ruby线程:关于线程同步的问题

    Thread#join的作用

    线程同步:MonitorMixin

    3种方式实现线程同步

    [Ruby]线程和进程

    Ruby的OpenURI模块

    Ruby: Net::Http and open-uri


    作       者:曾是土木人http://www.cnblogs.com/hongfei

    原文地址:http://www.cnblogs.com/hongfei/p/3696392.html

  • 相关阅读:
    [k8s] minikube的使用与应用部署
    [docker]docker 安装及构建流程
    [npm] error Cannot read properties of null (reading 'pickAlgorithm')
    SpringWebflux中WebClient怎么打印日志
    ERROR: cannot verify xxx certificate, issued by ‘/C=US/O=Let’s Encrypt/CN=R3’:use `nocheckcertif`
    如何解压 rpm 文件
    error while loading shared libraries: libmpfr.so.6: cannot open shared object file
    安装`gmp`遇到 configure:error:no usable m4 in$path or /user/5bin解决方案
    gcc升级
    264. 丑数 II (JAVA)
  • 原文地址:https://www.cnblogs.com/hongfei/p/3696392.html
Copyright © 2020-2023  润新知