2014-08-27 230 views
0

我已经建立了一个使用open-uri和nokogiri的网页爬虫ruby脚本,我很新,但它都适用于我需要从中提取数据的几个网站除了使用相对URL之外,其源代码中包含完整的网址。红宝石 - 从相对开放的绝对网址

脚本的功能是打开页面,构建一个打开的页面数组,然后从css(而不是xpath)中提取数据。

如何强制脚本使用完整的URL在他们相对的,它的被窃听我一会儿实例,我似乎无法让它运行

在我的情况,我想我需要在推送网址的时候添加一些内容,有谁能请我指出正确的方向吗?这将非常感激!谢谢!

require 'open-uri' 
require 'nokogiri' 

PAGE_URL = "http://www.OMMITED.co.uk" 

page = Nokogiri::HTML(open(PAGE_URL, "User-Agent" => “OMMITED“)) 

links = page.css("a") 

links_array = Array.new 

links.each{|link| 
     url = link['href'].nil? ? 'empty' : link['href'] 
     if url.include? 'category' and !url.include? '/all' 
       links_array.push url 
     end 
} 
+0

你可以使用正则表达式来检查完全合格的URL,类似于/^[\ w] *:\/\ // - 如果它匹配,那么前插根URL。在相对URL表示,它开始在服务器后的根路径,而不是开始没有斜线相对链接,匹配当前页的目录当中开始记住的“/”的精妙之处。我会写一个答案,但我需要更多关于可用变量的知识。 (主要是当前完全限定的URL和当前页面路径。) – 2014-08-27 11:17:38

+0

编辑添加变量! – James 2014-08-27 13:58:42

回答

0

tl; dr:底部简短回答。

OK,假设你有一个类变量叫做@url包含当前页面的完全合格的URL:

require 'uri' 

def full_url(rel, url) 
    return rel if rel.match /^[\w]*:\/\// 
    uri = URI(url) 
    if rel[0] == '/' 
    "#{uri.scheme}://#{uri.host}#{rel}" 
    else 
    path = uri.path.split('/')[0..-2].select{|m| !m.empty?}.join('/') 
    "#{uri.scheme}://#{uri.host}/#{path}/#{rel}" 
    end 
end 

然后,您可以拨打:

links_array.push full_url(url, @url) 

你可以把方法的相同的类或某处的助手类。它使用Ruby URI库来查找完全限定URL的相关部分,然后从相对路径构造一个新的URL。

如果相对路径以'/'开始,它应该直接在主机之后。

如果它不以'/'开始,那么它需要与当前页面位于相同的虚拟目录中。因此,如果当前页面是:

http://www.host.com/aaa/bbb/ccc 

和相对路径是:

ddd 

则输出应该是:

http://www.host.com/aaa/bbb/ddd 

然而,如果相对路径是:

/ddd 

那么输出应该是:

http://www.host.com/ddd 

的代码:

uri.path.split('/')[0..-2].select{|m| !m.empty?}.join('/') 

需要完整的URL的路径,将其分解在 '/' 给出的阵列(['aaa','bbb', 'ccc']),然后删除最后一个元素。 (['aaa','bbb'])。选择删除所有空白元素,然后再次将连接缝合起来。("aaa/bbb"

OR

你能做到这一点的枯燥方式:

require 'uri' 

URI.join("http://www.host.com/aaa/bbb/ccc", "/ddd").to_s 
# => "http://www.host.com/ddd" 

URI.join("http://www.host.com/aaa/bbb/ccc", "ddd").to_s 
# => "http://www.host.com/aaa/bbb/ddd" 

给出代码:

links.each{|link| 
    url = link['href'].nil? ? 'empty' : link['href'] 
    if url.include? 'category' and !url.include? '/all' 
      links_array.push url 
    end 
} 

我会为重新写:

links.each do |link| 
    url = link['href'].nil? ? 'empty' : link['href'] 
    if url.include? 'category' && !url.include? '/all' 
    full_url = URI.join(PAGE_URL, url).to_s 
    puts full_url 
    links_array << url 
    puts links_array.inspect 
    end 
end 

注意:S在多态方面,多行块应该使用do/end而不是{}。缩进应该是两个空格。圆括号内不应有空格。运营商比推送更受青睐。始终使用& &在条件语句而不是and,它具有低得多的优先级,并可能导致的问题。见GitHub的风格指南:

https://github.com/styleguide/ruby

puts是根据您的意见还有,希望帮助你弄清楚为什么你的阵列是不是行为。它应该是,根据你放在那里的代码。我宁愿使用调试器宝石。 (或者,如果你对Ruby的2.X byebug)

+0

感谢您的回复,我已经加你的代码并添加这导致停止没有这样的文件或目录的错误,我想指出,它是把两个值加在一起的@url变量,但它似乎并没有被打开我需要查看的URL数组,我会尝试修复并回来确认您的解决方案正常工作!谢谢! – James 2014-08-27 13:52:20

+0

检查答案的编辑结束,它显示了一个更简单,更干净的解决方案。 – 2014-08-27 13:58:10

+0

你最后的评论的鼓舞下,我来到了这个 'code' @full_url = URI.join(PAGE_URL,URL).to_s 提出@full_url links_array.push @full_url 结束 } '代码' 它加入正确(卖出期权是打印完整的URL),但它并不像它传递到阵列中。你能在这里看到任何可以解释的错误吗? – James 2014-08-27 15:28:47