世界上最伟大的投资就是投资自己的教育

首页Ruby
随风 · 练气

使用多线程和多进程来写爬虫

随风发布于3726 次阅读

1. 爬虫

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

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

我们用 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(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
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

完结。

更新:

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}

本站文章均为原创内容,如需转载请注明出处,谢谢。

1 条回复
  • wangfeng1992 · 凡人

    https 的网站 open 不能直接打开

    <:ssl::sslerror: ssl_connect returned="1" errno="0" state="error:" certificate verify failed>

喜欢
统计信息
    学员: 29811
    视频数量: 1987
    文章数量: 526

© 汕尾市求知科技有限公司 | Rails365 Gitlab | 知乎 | b 站 | csdn

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top