使用Ruby获取网页的所有链接

Fáb*_*rez 11 ruby regex string nokogiri

我正在尝试使用Ruby检索网页的每个外部链接.我正在使用String.scan这个正则表达式:

/href="https?:[^"]*|href='https?:[^']*/i
Run Code Online (Sandbox Code Playgroud)

然后,我可以使用gsub删除href部分:

str.gsub(/href=['"]/)
Run Code Online (Sandbox Code Playgroud)

这很好用,但我不确定它在性能方面是否有效.这可以使用,或者我应该使用更具体的解析器(例如nokogiri)?哪种方式更好?

谢谢!

tok*_*and 16

使用正则表达式适用于快速而脏的脚本,但Nokogiri使用起来非常简单:

require 'nokogiri'
require 'open-uri'

fail("Usage: extract_links URL [URL ...]") if ARGV.empty?

ARGV.each do |url|
  doc = Nokogiri::HTML(open(url))
  hrefs = doc.css("a").map do |link|
    if (href = link.attr("href")) && !href.empty?
      URI::join(url, href)
    end
  end.compact.uniq
  STDOUT.puts(hrefs.join("\n"))
end
Run Code Online (Sandbox Code Playgroud)

如果你只想要这个方法,可以根据你的需要重构一下:

def get_links(url)
  Nokogiri::HTML(open(url).read).css("a").map do |link|
    if (href = link.attr("href")) && href.match(/^https?:/)
      href
    end
  end.compact
end
Run Code Online (Sandbox Code Playgroud)


Mar*_*mas 6

Mechanize使用了Nokogiri,但内置了解析HTML的细节,包括链接:

require 'mechanize'

agent = Mechanize.new
page = agent.get('http://example.com/')

page.links_with(:href => /^https?/).each do |link|
  puts link.href
end
Run Code Online (Sandbox Code Playgroud)

使用解析器通常总是比使用正则表达式解析HTML更好.这是Stack Overflow上经常被问到的问题,是最着名的答案.为什么会这样?因为构建一个可以处理HTML的真实变体的健壮的正则表达式,其中一些不是有效的,非常困难,并且最终比简单的解析解决方案更复杂,该解决方案几乎适用于将在浏览器中呈现的所有页面.


the*_*Man 6

我是Nokogiri的忠实粉丝,但为什么要重新发明轮子呢?

Ruby的URI模块已经有了extract这样做的方法:

URI::extract(str[, schemes][,&blk])
Run Code Online (Sandbox Code Playgroud)

来自文档:

从字符串中提取URI.如果给定块,则遍历所有匹配的URI.如果给定块或具有匹配的数组,则返回nil.

require "uri"

URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.")
# => ["http://foo.example.com/bla", "mailto:test@example.com"]
Run Code Online (Sandbox Code Playgroud)

您可以使用Nokogiri来遍历DOM并拉出所有包含URL的标记,或者让它只检索文本并将其传递给URI.extract,或者只是让URI.extract它们全部完成.

而且,为什么要使用像Nokogiri这样的解析器而不是正则表达式?因为HTML和XML可以通过许多不同的方式进行格式化,并且仍然可以在页面上正确呈现或有效地传输数据.在接受糟糕的标记时,浏览器非常宽容.另一方面,正则表达式模式在"可接受性"的非常有限的范围内工作,其中该范围由您预测标记变化的程度来定义,或者相反,您预测模式出错的方式有多好出现意想不到的模式.

解析器不像正则表达式那样工作.它构建了文档的内部表示,然后逐步完成.它并不关心文件/标记的布局方式,而是关注DOM的内部表示.Nokogiri放松了它的解析来处理HTML,因为HTML因写得不好而臭名昭着.这有助于我们,因为大多数非验证HTML Nokogiri可以解决它.偶尔我会遇到一些写得很糟糕的东西,Nokogiri无法正确修复它,所以我必须通过调整HTML来给它一点轻推,然后再把它传递给Nokogiri; 我仍然会使用解析器,而不是尝试使用模式.


gor*_*tde 4

为什么你不在你的模式中使用组?例如

/http[s]?:\/\/(.+)/i
Run Code Online (Sandbox Code Playgroud)

所以第一组已经是您搜索的链接。