2

我刚开始使用 Ruby On Rails,并想创建一个简单的网站爬虫,它:

  1. 浏览所有 Sherdog 战士的个人资料。
  2. 获取裁判的姓名。
  3. 将名称与旧名称进行比较(在站点解析期间和文件中)。
  4. 打印所有唯一名称并将其保存到文件中。

示例 URL 为:http ://www.sherdog.com/fighter/Fedor-Emelianenko-1500

我正在搜索标签条目<span class="sub_line">Dan Miragliotta</span>,不幸的是,除了我需要的正确裁判名称之外,相同类型的类用于:

  1. 日期。
  2. 当裁判员姓名未知时,“N/A”。

我需要用“N/A”字符串以及任何包含数字的字符串丢弃所有结果。我设法做了第一部分,但不知道如何做第二部分。我尝试搜索、思考和试验,但是,在试验和重写之后,设法破坏了整个程序并且不知道如何(正确)修复它:

require 'rubygems'
require 'hpricot'
require 'simplecrawler'

# Set up a new crawler
sc = SimpleCrawler::Crawler.new("http://www.sherdog.com/fighter/Fedor-Emelianenko-1500")
sc.maxcount = 1
sc.include_patterns = [".*/fighter/.*$", ".*/events/.*$", ".*/organizations/.*$", ".*/stats/fightfinder\?association/.*$"]

# The crawler yields a Document object for each visited page.
sc.crawl { |document|
# Parse page title with Hpricot and print it
hdoc = Hpricot(document.data)

(hdoc/"td/span[@class='sub_line']").each do |span|
  if span.inner_html == 'N/A' || Regexp.new(".*/\d\.*$").match(span.inner_html)
    # puts "Test"
  else
    puts span.inner_html
    #File.open("File_name.txt", 'a') {|f| f.puts(hdoc.span.inner_html) } 
  end
end
}

我还将感谢有关程序其余部分的想法的帮助:如果程序运行多次,如何正确读取文件中的当前名称,以及如何比较唯一名称?


编辑:

经过一些建议的改进后,我得到了:

require 'rubygems'
require 'simplecrawler'
require 'nokogiri'
#require 'open-uri'

sc = SimpleCrawler::Crawler.new("http://www.sherdog.com/fighter/Fedor-Emelianenko-1500")
sc.maxcount = 1

sc.crawl { |document|
doc = Nokogiri::HTML(document.data)
names = doc.css('td:nth-child(4) .sub-line').map(&:content).uniq.reject { |c| c == 'N/A' }
puts names
}

不幸的是,代码仍然不起作用 - 它返回一个空白。

如果不是doc = Nokogiri::HTML(document.data),我写doc = Nokogiri::HTML(open(document.data)),那么它给了我整个页面,但是,解析仍然不起作用。

4

4 回答 4

2

hpricot不再维护。用nokogiri代替怎么样?

names = document.css('td:nth-child(4) .sub-line').map(&:content).uniq.reject { |c| c == 'N/A' }
=> ["Yuji Shimada", "Herb Dean", "Dan Miragliotta", "John McCarthy"]

不同部分的细分:

document.css('td:nth-child(4) .sub-line')

这将返回一个带有类名的 html 元素数组,这些元素sub-line位于第四个表列中。

.map(&:content)

对于前一个数组中的每个元素,返回element.content(内部 html)。这相当于map({ |element| element.content })

.uniq

从数组中删除重复值。

.reject { |c| c == 'N/A' }

删除值为“N/A”的元素

于 2012-10-11T02:40:42.297 回答
0

您将使用数组数学 (-) 来比较它们:

从当前页面获取裁判

current_referees = doc.search('td[4] .sub_line').map(&:inner_text).uniq - ['N/A']

从文件中读取旧裁判

old_referees = File.read('old_referees.txt').split("\n")

使用 Array#- 比较它们

new_referees = current_referees - old_referees

写新文件

File.open('new_referees.txt','w'){|f| f << new_referees * "\n"}
于 2012-10-11T04:05:18.007 回答
0

这将返回所有名称,忽略日期和“N/A”:

puts doc.css('td span.sub_line').map(&:content).reject{ |s| s['/'] }.uniq

结果是:

Yuji Shimada
Herb Dean
Dan Miragliotta
John McCarthy

将这些添加到文件中并删除重复项留给您作为练习,但我会使用 , 的一些神奇组合File.readlinessort然后再编写一些结果uniqFile.open

于 2012-10-11T04:08:40.113 回答
0

这是最终答案

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

# Mute log messages
module SimpleCrawler
   class Crawler
      def log(message)
      end
   end
end

n = 0  #  Counters how many pages/profiles processed
sc = SimpleCrawler::Crawler.new("http://www.sherdog.com/fighter/Fedor-Emelianenko-1500")
sc.maxcount = 150000
sc.include_patterns = [".*/fighter/.*$", ".*/events/.*$", ".*/organizations/.*$", ".*/stats/fightfinder\?association/.*$"]

old_referees = File.read('referees.txt').split("\n")

sc.crawl { |document|
doc = Nokogiri::HTML(document.data)

current_referees = doc.search('td[4] .sub_line').map(&:text).uniq - ['N/A']
new_referees = current_referees - old_referees

n +=1
# If new referees found, print statistics
if !new_referees.empty? then
    puts n.to_s + ". " + new_referees.length.to_s + " new : " + new_referees.to_s + "\n"
end

new_referees = new_referees + old_referees
old_referees = new_referees.uniq
old_referees.reject!(&:empty?)

# Performance optimization. Saves only every 10th profile.
if n%10 == 0 then 
    File.open('referees.txt','w'){|f| f << old_referees * "\n" }
end
}
File.open('referees.txt','w'){|f| f << old_referees * "\n" }
于 2012-10-11T05:43:23.477 回答