[ruby]使用多线程和多进程来写爬虫

为了提高处理和运算速度,或者充分利用 cpu 的计算和处理能力,需要使用多线程编程。

我们要把 ruby-china.org 上每篇贴子的标题和回复的数量,用爬虫爬下来。

1. 用 ruby 代码来实现。

require 'open-uri'
require 'nokogiri'

(1..50).each do |page|
  begin
    puts "page - #{page}"
    doc = Nokogiri::HTML(open("https://ruby-china.org/topics?page=#{page}"))
    doc.css("div.topic").each do |node|
      puts "#{node.css('> div.infos > div.title > a').text} #{node.css("> div.count > a").text}"
    end
    puts ""
  rescue : e
    puts "problem on page #{page}"
    puts e.inspect
  end
end

运行时间:

real    0m30.906s
user    0m2.212s
sys     0m0.279s

2. 用多线程实现

上面的代码效果太低效,我们改用多性程来编写。

我们访问的是 50 页,那就开 50 个线程,每页一个线程。

require 'open-uri'
require 'nokogiri'
require 'thread'

threads = (1..50).map do |page|
  Thread.new(page) do |page|
    begin
      puts "page - #{page}"
      doc = Nokogiri::HTML(URI.open("https://ruby-china.org/topics?page=#{page}"))
      doc.css("div.topic").each do |node|
        puts "#{node.css('> div.infos > div.title > a').first['title']} https://ruby-china.org#{node.css("> div.infos > div.title > a").first['href']}"
      end
      puts ""
    rescue : e
      puts "problem on page #{page}"
      puts e.inspect
    end
  end
end
threads.each {|t| t.join}

时间输出:

real    0m4.610s
user    0m1.480s
sys     0m0.279s

3. 使用线程安全的数据结构保证同步

用 ruby 中唯一的线程安全的数据结构 Queue 来保证线程同步。

require 'open-uri'
require 'nokogiri'
require 'thread'

work_q = Queue.new

(1..50).each{|page| work_q << page}

workers = (0...10).map do
  Thread.new do
    begin
      while page = work_q.pop(true)      
        begin
          puts "page - #{page}"
          doc = Nokogiri::HTML(open("https://ruby-china.org/topics?page=#{page}"))
          doc.css("div.topic").each do |node|
            puts "#{node.css('> div.infos > div.title > a').text} #{node.css("> div.count > a").text}"
          end
        rescue : e
          puts "problem on page #{page}"
          puts e.inspect
        end
      end # while
      puts ""
    rescue ThreadError
    end
  end
end
workers.map(&:join)
real    0m5.983s
user    0m1.753s
sys     0m0.357s

使用的时间 (6s) 比不用线程的情况 (30s) 缩短了几倍。

4. 使用多进程来实现

parallel这个库可以轻易地开多个进程。

require 'parallel'
require 'open-uri'
require 'nokogiri'

Parallel.map(1..50, in_processes: 10) do |page|
  begin
    puts "page - #{page}"
    doc = Nokogiri::HTML(open("https://ruby-china.org/topics?page=#{page}"))
    doc.css("div.topic").each do |node|
      puts "#{node.css('> div.infos > div.title > a').text} #{node.css("> div.count > a").text}"
    end
    puts ""
  rescue : e
    puts "problem on page #{page}"
    puts e.inspect
  end
end

时间输出:

real    0m4.767s
user    0m1.856s
sys     0m0.360s
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值