0

複数のページ タイトルを解析するスクリプトを作成しています。スタック内の別の質問のおかげで、この作業ビットができました

curl = %x(curl http://odin.1.ai)
simian = curl.match(/<title>(.*)<\/title>/)[1]
puts simian

ただし、たとえばページにタイトルがない場合に同じことを試してみると

 curl = %x(curl http://zales.1.ai)

タイトルがないため、nillクラスの未定義のメソッドで終了します....この場合はそうではないため、curlがnilであるかどうかを確認できません(別の行が含まれています)

タイトルが存在しない場合でもこれを機能させ、次のページに移動して確認する解決策はありますか? nokogiri と uri (Nokogiri::HTML(open("http:/.....")) を使用して他のソリューションを試したので、このコードに固執していただければ幸いですが、これは byname_meee.1 のようなサブドメインとしても機能しません。 .ai はデフォルトの open-uri では機能しないため、curl を使用するこのコードに固執できることを感謝します。

アップデート

明確にすべきいくつかの特定のケースをおそらく省略していたことに気づきました。これは、300 ~ 400 ページを解析するためのものです。最初の実行で、nokogiri、hpricot が機能しないケースが少なくとも 2 つあることに気付きましたが、より基本的な open-uri でさえ機能しません。

1) open-uri は、 http://levant_alejandro.1.aiのような _ を持つ単純なドメインで単純に失敗します。これは有効なドメインであり、curl では機能しますが、open_uri または open_uri を使用する nokogiri では機能しません。

2) http://zales.1.aiのようにページにタイトルがない場合の 2 番目のケース

3) 3 つ目は、 http: //voldemortas.1.ai/のような有効な HTML がなく、画像が含まれるページです。

4 番目のケースは、内部サーバー エラーまたはパッセンジャー/ラック エラーしかないページです。

最初の 3 つのケースは、このソリューションでソートできます (#ruby IRC チャネルの Havenwood に感謝)。

curl = %x(curl http://voldemortas.1.ai/)
begin
   simian = curl.match(/<title>(.*)<\/title>/)[1]
rescue NoMethodError
   simian = "" # curl was nil?    
rescue ArguementError
   simian = "" # not html?
end
puts simian

今、これはエレガントでも最適でもないことを認識しています。

言い換えられた質問

nokogiri またはこれらのケースを含む別の gem (タイトルがない、有効な HTML ページがない、または 404 ページさえない) で同じことを達成するためのより良い方法はありますか? 解析しているページのタイトル構造がかなり単純な場合、上記の解決策は適切ですか? 知識のために、nokogiri のような解析用の追加の gem を使用する方が良いオプションである理由を知っておくと便利です (注: gem の依存関係をできるだけ頻繁に、時間の経過とともに破損する傾向があるようにしています)。

4

3 に答える 3

2

あなたは自分自身にそれを非常に難しくしています。

Nokogiri は、HTML をどこから取得するかは気にしません。ドキュメントの本文が必要なだけです。Curb、Open-URI、生の Net::HTTP 接続を使用でき、返されたコンテンツを解析します。

縁石を試す:

require 'curb'
require 'nokogiri'

doc = Nokogiri::HTML(Curl.get('http://http://odin.1.ai').body_str)
doc.at('title').text
=> "Welcome to Dotgeek.org * 1.ai"

タグがあるかどうかわからない場合は<title>、一度にすべてを実行しようとしないでください。

title = doc.at('title')
next if (!title)
puts title.text

より多くのアイデアについては、「Ruby の curl と同等ですか? 」を参照してください。

于 2012-09-07T23:38:57.300 に答える
1

アクセスする前に一致を確認する必要があります。curl.matchの場合nil、グループ化にアクセスできません:

curl = %x(curl http://odin.1.ai)
simian = curl.match(/<title>(.*)<\/title>/)
simian &&= simian[1] # only access the matched group if available
puts simian

ブリキ男の忠告に従い、のこぎりを使ってください。あなたの正規表現は、実際には脆弱なソリューションにのみ適しています-title要素が複数の行にまたがると失敗します。

アップデート

HTML パーサーを本当に使用したくない場合、およびこれが簡単なスクリプト用であると約束する場合は、標準ライブラリで OpenURI (net/http のラッパー) を使用できます。curl出力を解析するよりも少なくとも少しはきれいです。

require 'open-uri'

def extract_title_content(line)
  title = line.match(%r{<title>(.*)</title>})
  title &&= title[1]
end

def extract_title_from(uri)
  title = nil

  open(uri) do |page|
    page.lines.each do |line|
      return title if title = extract_title_content(line)
    end
  end
rescue OpenURI::HTTPError => e
  STDERR.puts "ERROR: Could not download #{uri} (#{e})"
end

puts extract_title_from 'http://odin.1.ai'
于 2012-09-08T00:45:47.557 に答える
0

あなたが本当に探しているのは、HTML 以外の応答をスキップする方法のようです。ブリキ男が提案したように、縁石のようなカールラッパーを使用すると、シェルにドロップしてそこでカールを使用するよりもはるかに簡単です。

1.9.3p125 :001 > require 'curb'
 => true 
1.9.3p125 :002 > response = Curl.get('http://odin.1.ai')
 => #<Curl::Easy http://odin.1.ai?> 
1.9.3p125 :003 > response.content_type
 => "text/html" 
1.9.3p125 :004 > response = Curl.get('http://voldemortas.1.ai')
 => #<Curl::Easy http://voldemortas.1.ai?> 
1.9.3p125 :005 > response.content_type
 => "image/png" 
1.9.3p125 :006 > 

したがって、コードは次のようになります。

response = Curl.get(url)
if response.content_type == "text/html" # or more fuzzy: =~ /text/
  match = response.body_str.match(/<title>(.*)<\/title>/)
  title = match && match[1] 
  # or use Nokogiri for heavier lifting
end

もう例外はありません

于 2012-09-08T06:47:33.923 に答える