从Web抓取URL

时间:2011-06-24 16:49:51

标签: ruby regex url web-scraping hpricot

<a href="http://www.utoronto.ca/gdrs/" title="Rehabilitation Science"> Rehabilitation Science</a>

对于上面的示例,我想同时获得部门名称“康复科学”及其主页网址“http://www.utoronto.ca/gdrs/”。

有人可以建议一些能为我做这个工作的智能正则表达式吗?

5 个答案:

答案 0 :(得分:4)

没有理由使用正则表达式来完成此操作。这是使用Nokogiri的解决方案,这是通常的Ruby HTML / XML解析器:

html = <<EOT
<p><a href="http://www.example.com/foo">foo</a></p>
<p><a href='http://www.example.com/foo1'>foo1</p></a>
<p><a href=http://www.example.com/foo2>foo2</a></p>
<p><a href = http://www.example.com/bar>bar</p>
<p><a 
  href="http://www.example.com/foobar"
  >foobar</a></p>
  <p><a 
    href="http://www.example.com/foobar2"
    >foobar2</p>
EOT

require 'nokogiri'

doc = Nokogiri::HTML(html)

links = Hash[
  *doc.search('a').map { |a| 
      [
        a['href'],
        a.content
      ]
    }.flatten
  ]

require 'pp'
pp links
# >> {"http://www.example.com/foo"=>"foo",
# >>  "http://www.example.com/foo1"=>"foo1",
# >>  "http://www.example.com/foo2"=>"foo2",
# >>  "http://www.example.com/bar"=>"bar",
# >>  "http://www.example.com/foobar"=>"foobar",
# >>  "http://www.example.com/foobar2"=>"foobar2"}

这会将URL的哈希值作为键返回,并将<a>标记的相关内容作为值。这意味着您只会捕获唯一的URL,从而丢失重复的内容。如果您希望所有网址都使用:

links = doc.search('a').map { |a| 
    [
      a['href'],
      a.content
    ]
  }

导致:

# >> [["http://www.example.com/foo", "foo"],
# >>  ["http://www.example.com/foo1", "foo1"],
# >>  ["http://www.example.com/foo2", "foo2"],
# >>  ["http://www.example.com/bar", "bar"],
# >>  ["http://www.example.com/foobar", "foobar"],
# >>  ["http://www.example.com/foobar2", "foobar2"]]

我使用CSS访问器'a'来定位标签。如果我只想抓住链接,忽略锚点,我可以使用'a[href]'

在处理HTML和XML时,正则表达式非常脆弱,因为标记格式过于自由;它们的格式可以保持有效,特别是HTML,它的“正确性”可能会有很大差异。如果您不拥有正在解析的文件的生成,那么您的代码将受到使用正则表达式时生成它的人的摆布;文件中的简单更改可能会严重破坏模式,从而导致持续的维护问题。

解析器,因为它实际上了解文件的内部结构,可以承受这些更改。请注意,我故意创建了一些格式错误的HTML,但代码并不关心。比较解析器版本与正则表达式解决方案的简单性,并考虑长期可维护性。

答案 1 :(得分:1)

我建议使用像@mrk建议的HTML解析器。然后取得结果你回来并通过正则表达式搜索者。我喜欢用Rubular。这将向您显示正则表达式捕获的内容,您可以避免获得不需要的结果。我发现使用正则表达式/ http [^“] + / work会在这样的情况下工作,因为即使没有”www。“它也会抓取整个url并且你避免捕获引号。

答案 2 :(得分:1)

如果你正在建造蜘蛛,那么Ruby's Mechanize是一个很好的选择。要获取页面并提取链接:

require 'rubygems'
require 'mechanize'

agent = Mechanize.new
page = agent.get "http://google.com/"

page.links.each do |link|
  puts link.href
  puts link.text
end

文档和指南(我链接到的)列出了很多你可能想要做的事情。使用正则表达式来解析HTML(或XML)是非常棘手且容易出错的。使用完整的解析器(正如其他人建议的那样)将节省您的工作量并使您的代码更加健壮。

答案 3 :(得分:0)

试图不要过于复杂:

#<a .*?href="([^"]*)".*>([^<]+)</a>#i

答案 4 :(得分:0)

这是我的Ruby方法:

require 'open-uri'

class HTMLScraper
    def initialize(page)
      @src = page
      open(@src) do |x|
          @html = x.read
      end
    end
    def parseLinks
      links = @html.scan(/<a\s+href\s*=\s*"([^"]+)"[^>]*>\s*([^<]+)\s*<\/a>/ui)
      puts "Link(s) Found:"
      i = 0
      while i < links.length
        puts "\t#{links[i]}"
        i += 1
      end
    end
  end

url = "http://stackoverflow.com/questions"
test = HTMLScraper.new(url)
test.parseLinks

这将为您提供一个数组数组,其中每个(内部)数组的第一项是url,第二项是标题。希望这有助于并注意正则表达式上的u开关,这是为了避免编码问题。