обрабатывать все ссылки, кроме внешних (ruby + mechanize)

Я хочу обрабатывать все ссылки, кроме внешних со всего веб-сайта. Есть ли простой способ определить, что ссылка является внешней, и пропустить ее?

Мой код пока выглядит так (URL-адрес сайта передается через аргумент командной строки)

Я использую mechanize (0.9.3) и ruby 1.8.6 (уровень обновления 287 от 11 августа 2008 г.) [i386-mswin32]

Обратите внимание, что веб-сайт может использовать относительный путь, поэтому нет хоста/домена, и это немного усложняет его.

require 'mechanize'

def process_page(page) 
  puts
  puts page.title
  STDIN.gets
  page.links.each do |link|
process_page($agent.get(link.href))
  end
end

$agent = WWW::Mechanize.new 
$agent.user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4'
process_page($agent.get(ARGV[0]))

person Radek    schedule 27.04.2010    source источник


Ответы (2)


У URI есть несколько методов, позволяющих довольно легко увидеть, просматриваете ли вы локальный URL-адрес или URL-адрес другого сайта.

Это небольшая модификация примера документации URI .route_to():

require 'uri'

URI.parse('/main.rbx?page=1').host # => nil
URI.parse('main.rbx?page=1').host  # => nil

У внутренних URL-адресов нет хоста, поэтому я бы проанализировал рассматриваемые URL-адреса и посмотрел, есть ли у них хост. Если нет, то это внутренняя часть сайта.

URL-адрес, указывающий на внешний сайт, вернет значение для хоста, но так же будет и полный URL-адрес рассматриваемого сайта, поэтому вам придется сделать еще немного массажа.

uri = URI.parse('http://my.example.com')

uri.route_to('http://my.example.com/main.rbx?page=1').host  # => nil
uri.route_to('http://another.com/main.rbx?page=1').host # => "another.com"

Если у него есть хост, посмотрите, соответствует ли этот хост хосту вашего начального URL. Вы можете сделать это с помощью поиска подстроки или совпадения регулярных выражений, но оба они могут возвращать ложные срабатывания, если происходит совпадение подстроки.

Вместо этого я бы использовал методы URI, чтобы избежать ложных срабатываний; Используйте route_to(), чтобы попытаться создать относительный путь к URL-адресу. Если результат имеет значение .host, то он является внешним.

person the Tin Man    schedule 27.04.2010
comment
Спасибо. Это происходит из-за того, что я много раз врезался в стену, делая это способами, которые, как я думал, сработают, но не сработали. Нет никакой гарантии, что это покроет все ситуации, но использование URI помогает отсеять множество непредвиденных проблем. :-) - person the Tin Man; 27.04.2010

Используйте метод uri ссылки:

  page.links.each do |link|
     next unless link.uri.host.match(/(www\.)?thissite\.com/)
     process_page($agent.get(link.href))
  end
person CodeJoust    schedule 27.04.2010
comment
@COdeJoust: выглядит хорошо, но in process_page': неопределенный метод url' for #<WWW::Mechanize::Page::Link "" "Statement.html"> (NoMethodError) - person Radek; 27.04.2010
comment
хорошо, похоже, что метод на самом деле .uri, но иногда у вас может быть относительный путь на веб-сервере, и тогда я получаю undefined method 'match' for nil:NilClass (NoMethodError), потому что хоста нет - person Radek; 27.04.2010