2

Ruby On Rails を使い始めたばかりで、次のような単純な Web サイト クローラーを作成したいと考えています。

  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もうメンテナンスされていません。代わりにノコギリを使ってみませんか?

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

これは、テーブルの 4 番目の列にあるクラス名を持つ 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

これが最終的な答えです

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 に答える
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 に答える