Ruby 脚本实现数据爬取

本贴最后更新于 3192 天前,其中的信息可能已经时移世异

工作上使用Redis,为了测试其性能,需要大量的测试数据,所以利用周末的时间用ruby写了个脚本,跑了一天,从搜搜问问百度知道爬了大量的数据下来,分成问题和答案,总共有50万条数据,大小也就50M左右;周一去上班,写了一个ruby脚本连接Redis数据库,再循环分别导入问题和答案数据,这样测试数据就有了,由于测试机器内存的限制,导入的测试数据总共100万条,占内存1G。

下面想说说ruby脚本的结构,很简单,还有需要改进的地方,但是脚本就是一次性的工具,如没有通用性可能,有没有必要再改进另当其说。

建立http连接功能使用了内部包含的gem包open-uri,解析获取到的页面对象,并抓取特定的document元素,使用的gem是nokogiri,脚本分几个功能部分,各负其责,分别介绍如下:

  • 递归抓取页面所有超级链接(spider_url.rb)
#!/usr/bin/ruby -w

require 'rubygems'
require 'nokogiri'
require 'open-uri'

load 'spider_document.rb'

class URL
attr_accessor :available_url, :pre_url, :visited_url, :error_url

def initialize @available_url = {} @visited_url = {} @error_url = {} @pre_url = "http://wenwen.soso.com" end # 抓取页面上的所有超链接,形如 'href...' def crawl_url (target_url) puts '获取超级链接页面地址 -> ' + target_url temp_available_url = {} begin open(target_url) do |uri| doc_content = uri.read doc_content.scan(/href=["|'](.+?)["|']/) do |href_item| url = href_item[0] # TODO pattern is not exactely url.match(/.z./) do |m| # build hash {url=>real url} if !@visited_url.has_key?(url) temp_available_url["#{url}"] = url @visited_url["#{url}"] = url end # puts '新增访问url:' + url end # url=@target_url.match(/(http:\/\/([^\/]+))\//)[1] << url if url =~ /^\// end end rescue puts $! @error_url["#{target_url}"] = target_url puts 'error' end temp_available_url end def crawl_content (target_url) doc = Document.new doc.crawl_content(target_url) end

end

url_spider = URL.new
puts 'url spider begining ...'

url_spider.available_url = url_spider.crawl_url("http://wenwen.soso.com")
while(!url_spider.available_url.empty?)
url_spider.available_url.each do |key,value|
url_spider.crawl_content(url_spider.pre_url + value)
url_spider.available_url = url_spider.available_url.merge url_spider.crawl_url(url_spider.pre_url + value)
url_spider.available_url.delete(key)
puts 'current available_url size : ' + url_spider.available_url.size.to_s
end
end

puts 'Total available_url size : ' + url_spider.available_url.size.to_s
puts 'Total visited_url size : ' + url_spider.visited_url.size.to_s
puts 'Total error_url size : ' + url_spider.error_url.size.to_s

  • 解析页面文档(spider_document.rb)
#!/usr/bin/ruby -w

require 'rubygems'
require 'nokogiri'
require 'open-uri'

class Document
@@quesion_count = 0
@@answer_count = 0

def get_question (page) questionArray = page.css('div.qa_title') questionArray.each do |question| #puts question.text File.open("question.txt",'a') { |f| f.puts question.text.strip.delete "快速回答".strip } end @@quesion_count = @@quesion_count + questionArray.size puts "current question count is : [" + @@quesion_count.to_s + "]" end def get_answer (page) answerArray = page.css('div.answer_con') answerArray.each do |answer| #puts answer.text File.open("answer.txt",'a') { |f| f.puts answer.text.strip.delete "快速回答".strip } end @@answer_count = @@answer_count + answerArray.size puts "current answer count is : [" + @@answer_count.to_s + "]" end def crawl_content (target_url) puts '抓取页面内容地址 -> ' + target_url begin page = Nokogiri::HTML(open(target_url)) get_question (page) get_answer (page) rescue Exception => e puts $! end end

end

  • 批量导入Redis(spider_persistence.rb)
#!/usr/bin/ruby -w

require 'rubygems'
require 'nest'
require 'redis'

class Persistence

attr_accessor :redis, :question_count, :answer_count def initialize @redis = Redis.new # @redis = Redis.new(:host=>"192.168.1.67",:port=>6379) @question_count = 0 @answer_count = 0 end # 批量生产账号 def batch_account account_namespace = Nest.new("account",@redis) File.open("account_email_local.txt") do |f| f.each_line do |line| pre_str = line.chomp.split('@')[0] account_namespace[line.chomp].hset("nickName",pre_str) account_namespace[line.chomp].hset("email",pre_str) account_namespace[line.chomp].hset("passWordHash","49") # 密码为1 account_namespace[line.chomp].hset("answerCount","0") account_namespace[line.chomp].hset("selfDescription","非理性人类一枚") account_namespace[line.chomp].hset("followCount","0") account_namespace[line.chomp].hset("followerCount","0") account_namespace[line.chomp].hset("questionCount","0") puts line.chomp + " is builded." end end end # 批量生成问题集合 def batch_question account_namespace = Nest.new("account",@redis) question_namespace = Nest.new("question",@redis) pre_email = "rayootech" # 默认的账号 rayootech@163.com begin File.open("question.txt","r") do |file| file.each_line do |line| # 生成随机的20位问题id id = random_id(20) if (!line.strip.empty? && line.strip.length>3) puts "#{file.lineno} : #{line}" question_namespace[id].hset("id",id) question_namespace[id].hset("content",line) question_namespace[id].hset("author",pre_email+"@163.com") question_namespace[id].hset("createTime","2014-01-14") question_namespace[id].hset("followerCount","0") question_namespace[id].hset("browseCount","1") # 用户和提出的问题关系集合 account:[id]:question account_namespace["#{pre_email}@163.com"]["questions"].zadd(1401141645,id) @question_count = @question_count + 1 File.open("question_id_local.txt", "a") { |f| f.puts id } end # 生成随机email地址前缀,并保存,后期生成account账号导入redis,一个email账户提500个问题 if (@question_count%500==0) pre_email = random_id(10) File.open("account_email_local.txt","a"){|file|file.puts "#{pre_email}@163.com"} end end end rescue Exception => e puts $! end end # 批量生成回答集合 def batch_answer account_namespace = Nest.new("account",@redis) qa_relation_ns = Nest.new("question",@redis) answer_namespace = Nest.new("answer",@redis) question_id = "lzj4ggcgfpmj5uxnhtgx" # 【提问时间】 默认问题id begin File.open("answer.txt","r") do |file| file.each_line do |line| # 生成随机的20位回答id id = random_id(20) author = random_account_email if (!line.strip.empty?) puts "#{file.lineno} : #{line}" answer_namespace[id].hset("id",id) answer_namespace[id].hset("content",line) answer_namespace[id].hset("author",author) answer_namespace[id].hset("createTime","2014-01-15") answer_namespace[id].hset("approveCount","0") answer_namespace[id].hset("qId",question_id) # 问题和回答关系数据 qa_relation_ns[question_id]["answers"].zadd(1401152040,id) # 问题的所有回答者关系数据 qa_relation_ns[question_id]["respondents"].sadd(author) # 用户所有的回答数据 account_namespace[author]["answers"].zadd(1401159088,id) @answer_count = @answer_count + 1 File.open("answer_id_local.txt", "a") { |f| f.puts id } end # 每个问题下有平均100个回答 if (@answer_count%100==0) question_id = random_question_id end end end rescue Exception => e puts $! end end # 批量生成问题浏览者集合 def batch_question_browser end # 随机返回一个问题id def random_question_id question_id_arr = [] index = 0 File.open("question_id.txt") do |f| f.each_line do |line| question_id_arr[index]=line index = index + 1 end end question_id_arr[rand(question_id_arr.size-1)].chomp end # 随机返回一个回答id def random_answer_id end # 随机返回一个email def random_account_email account_email_arr = [] index = 0 File.open("account_email.txt") do |f| f.each_line do |line| account_email_arr[index]=line index = index + 1 end end account_email_arr[rand(account_email_arr.size-1)].chomp end # 生成随机数 def random_id(len) chars = ("a".."z").to_a + ("a".."z").to_a + ("0".."9").to_a random_id = "" 1.upto(len) { |i| random_id << chars[rand(chars.size-1)] } return random_id end

end

persistence = Persistence.new

1.times

puts "persistence question count : " + persistence.question_count.to_s

persistence.batch_account

1.times {|i| persistence.batch_answer }
puts "persistence answer count : " + persistence.answer_count.to_s

  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 249 关注
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • OpenCV
    15 引用 • 36 回帖 • 8 关注
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 614 关注
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    170 引用 • 1529 回帖
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 279 关注
  • 叶归
    7 引用 • 31 回帖 • 17 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    495 引用 • 931 回帖
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    325 引用 • 1395 回帖 • 1 关注
  • 链书

    链书(Chainbook)是 B3log 开源社区提供的区块链纸质书交易平台,通过 B3T 实现共享激励与价值链。可将你的闲置书籍上架到链书,我们共同构建这个全新的交易平台,让闲置书籍继续发挥它的价值。

    链书社

    链书目前已经下线,也许以后还有计划重制上线。

    14 引用 • 257 回帖
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    9733 引用 • 44280 回帖 • 89 关注
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    6 引用 • 26 回帖 • 544 关注
  • Visio
    1 引用 • 2 回帖 • 1 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 4 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 193 关注
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    10 引用 • 77 回帖
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 628 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    29 引用 • 202 回帖 • 30 关注
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 22 关注
  • flomo

    flomo 是新一代 「卡片笔记」 ,专注在碎片化时代,促进你的记录,帮你积累更多知识资产。

    6 引用 • 143 回帖 • 2 关注
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用 • 1 关注
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 67 回帖 • 451 关注
  • 浅吟主题

    Jeffrey Chen 制作的思源笔记主题,项目仓库:https://github.com/TCOTC/Whisper

    1 引用 • 28 回帖
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    32 引用 • 99 回帖
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 529 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    168 引用 • 597 回帖
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    36 引用 • 37 回帖 • 546 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3200 引用 • 8216 回帖 • 1 关注
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 47 关注