ROR/Hpricot:解析网站并使用正则表达式搜索/比较字符串



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

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

一个示例URL是:http://www.sherdog.com/fighter/Fedor-Emelianenko-1500

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

  1. 日期
  2. "不适用",当裁判姓名未知时

我需要丢弃所有带有"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(open(document.data))而不是doc = Nokogiri::HTML(document.data),那么它会给我整个页面,但是解析仍然不起作用。

不再维护

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')

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

.map(&:content)

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

.uniq

从数组中删除重复的值。

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

删除值为"N/A"的元素

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

从当前页面获取推荐人

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

从文件中读取旧的推荐人

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

使用数组#-来比较它们

new_referees = current_referees - old_referees

写入新文件

File.open('new_referees.txt','w'){|f| f << new_referees * "n"}

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

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

结果是:

Yuji Shimada
Herb Dean
Dan Miragliotta
John McCarthy

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

这是的最终答案

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" }

相关内容

  • 没有找到相关文章

最新更新