Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 使用多个XPath选择器定义单个链接的页面的变通方法?_Ruby_Xpath_Nokogiri - Fatal编程技术网

Ruby 使用多个XPath选择器定义单个链接的页面的变通方法?

Ruby 使用多个XPath选择器定义单个链接的页面的变通方法?,ruby,xpath,nokogiri,Ruby,Xpath,Nokogiri,下面的代码可以工作,但不会迭代到下一页。我发现这个网站使用了两个不同的XPath选择器来定义下一个页面链接,我不确定如何在代码中实现它 作为对评论的回应,以下是有关第一页选择器的来源: <table class="pager" cellspacing="0"> <tr> <td> Items 1 to 72 of 1146 total </td>

下面的代码可以工作,但不会迭代到下一页。我发现这个网站使用了两个不同的XPath选择器来定义下一个页面链接,我不确定如何在代码中实现它

作为对评论的回应,以下是有关第一页选择器的来源:

<table class="pager" cellspacing="0">
    <tr>
        <td>
                    Items 1 to 72 of 1146 total                </td>
                <td class="pages">
            <strong>Page:</strong>
            <ol>
                                                            <li><span class="on">1</span></li>
                                                                <li><a href="http://www.example.com/clothing-accessories?dir=asc&amp;limit=72&amp;order=position&amp;p=2">2</a></li>
                                                                <li><a href="http://www.example.com/clothing-accessories?dir=asc&amp;limit=72&amp;order=position&amp;p=3">3</a></li>
                                                                <li><a href="http://www.example.com/clothing-accessories?dir=asc&amp;limit=72&amp;order=position&amp;p=4">4</a></li>
                                                                <li><a href="http://www.example.com/clothing-accessories?dir=asc&amp;limit=72&amp;order=position&amp;p=5">5</a></li>
                                                        <li><a href="http://www.example.com/clothing-accessories?dir=asc&amp;limit=72&amp;order=position&amp;p=2"><img src="http://www.example.com/skin/frontend/default-mongo/a033/images/pager_arrow_right.gif" alt="Next Page"/></a></li>
                        </ol>
        </td>

        <td class="a-right">
            Show <select onchange="setLocation(this.value)">
                            <option value="http://www.example.com/clothing-accessories?dir=asc&amp;limit=12&amp;order=position">
                    12                </option>
                            <option value="http://www.example.com/clothing-accessories?dir=asc&amp;limit=24&amp;order=position">
                    24                </option>
                            <option value="http://www.example.com/clothing-accessories?dir=asc&amp;limit=48&amp;order=position">
                    48                </option>
                            <option value="http://www.example.com/clothing-accessories?dir=asc&amp;limit=72&amp;order=position" selected="selected">
                    72                </option>
                        </select> per page        </td>

    </tr>
</table>
在所有后续页面上,下一页链接由以下内容定义:

//*[@id="bodyblock"]/div/div[2]/div[2]/div[3]/table[3]/tbody/tr/td[2]/ol/li[7]/‌​a
我将更改代码的哪一部分,以及如何确保程序迭代到结果的下一页,而不管如何定义
next\u page\u link

require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'fileutils'

DATA_DIR = "data-hold/clothing-accessories"
Dir.mkdir(DATA_DIR) unless File.exists?(DATA_DIR)
BASE_TOM_URL = "http://www.example.com"

list_url = "#{ BASE_TOM_URL }/clothing-accessories?dir=asc&limit=72&order=position"

loop do

  page = Nokogiri::HTML(open(list_url))
  rows = page.xpath('//*[@id="product-list-table"]/li')

  unless rows.empty?

    rows[1..-2].each do |row|

      hrefs = row.xpath('//*[@id="product-list-table"]/li/div/a').map{ |a| a['href'] }.uniq

      hrefs.each do |href|

        remote_url = href
        local_fname = "#{ DATA_DIR }/#{ File.basename(href) }"

        unless File.exists?(local_fname)

          puts "Fetching #{ remote_url }..."

          begin
            tom_content = open(remote_url).read
            File.write(local_fname, tom_content)
            puts "\t...Success, saved to #{ local_fname }"
            sleep 1.0 + rand
          rescue Exception => e
            puts "Error: #{ e }"
            sleep 5
          end  

        end 

      end 

    end

  end


  next_results_link = page.at('//*[@id="bodyblock"]/div/div[2]/div[2]/div[3]/table[3]/tbody/tr/td[2]/ol/li[7]/a')

  if next_results_link
    list_url = next_results_link['href']
    puts "\t...Getting next page of results: #{list_url}"
  else
    break
  end

end

你为什么不这样做:

rows[1..-2].each_with_index do |row, i|

  ...

  xpath_index = if i == 1
    '6'
  else
    '7'
  end

  next_results_link = page.at(%Q!//*[@id="bodyblock"]/div/div[2]/div[2]/div[3]/table[3]/tbody/tr/td[2]/ol/li[#{ xpath_index }]/a!)
  ...

end
这会让你了解它在做什么:

xpath_index = 6
%Q!//*[@id="bodyblock"]/div/div[2]/div[2]/div[3]/table[3]/tbody/tr/td[2]/ol/li[#{ xpath_index }]/a!
# => "//*[@id=\"bodyblock\"]/div/div[2]/div[2]/div[3]/table[3]/tbody/tr/td[2]/ol/li[6]/a"

xpath_index = 7
%Q!//*[@id="bodyblock"]/div/div[2]/div[2]/div[3]/table[3]/tbody/tr/td[2]/ol/li[#{ xpath_index }]/a!
# => "//*[@id=\"bodyblock\"]/div/div[2]/div[2]/div[3]/table[3]/tbody/tr/td[2]/ol/li[7]/a"
另外,正如您所知,您正在处理XPath中的非ASCII字符。我不知道它是如何到达那里的,但是后面的
/a
无效。目前是:

'/‌​a'.codepoints.to_a # => [47, 8204, 8203, 97]
应该是:

'/a'.codepoints.to_a # => [47, 97]

“page.at(%Q!)选择器语法对我来说是新的,我在任何阅读资料中都没有看到它被引用过

Nokogiri相当于
搜索(一些节点选择器,一些名称空间)。首先
。它都记录在中。换句话说,它只查找第一个节点并返回它,而查找所有匹配的节点并将其作为节点集返回

同样地接受CSS或XPath选择器。CSS特定的版本是,XPath特定的版本是。我倾向于使用,除非我使用的选择器不明确,这会欺骗Nokogiri做错误的事情

类似地,接受CSS和XPath,和分别是CSS和XPath的变体

%Q!…
是定义解释/双引号字符串的另一种方法。除了
%Q
之外,还有
%Q
%
,对于正则表达式还有
%r
%x
在子shell中执行命令行应用程序,以及Ruby v.2.0中的
%i

以下是一组示例:

foo = 'bar'

%Q[a b]        # => "a b"
%Q^a #{ foo }^ # => "a bar"

%[a b]        # => "a b"
%/a #{ foo }/ # => "a bar"

%q#a b#        # => "a b"
%q[a #{ foo }] # => "a \#{ foo }"

%w$a b$ # => ["a", "b"]
%W~a b~ # => ["a", "b"]

%W[a foo]      # => ["a", "foo"]
%W[a #{ foo }] # => ["a", "bar"]

%r.^foo. # => /^foo/
%r!^foo! # => /^foo/
%r/^foo/ # => /^foo/
%x(date) # => "Mon Dec  2 21:13:37 MST 2013\n"

%s[a]   # => :a
%s[a b] # => :"a b"
%i[a b] # => [:a, :b]
请注意,分隔符可以是书尾,如
()
[]
,也可以是相同的字符,如
#
。这在处理包含单引号和双引号的字符串时提供了很大的灵活性,并且可以清除“倾斜牙签综合症”行:


请注意,最后一个在视觉上更清晰,更易于输入。这些只是嵌入单引号和双引号的简单示例。请通读以获取更多示例和信息。

在此链接中,包含一个包含可选文本“下一页”的图像。请充分利用这一点:

//td[contains(@class,'pages')]/ol/li/a[img/@alt='Next Page']
如果您喜欢完整的路径,可以轻松地将此XPath表达式的选择器应用于上面获取的路径的开头。我甚至可以进一步使用
//td[contains(@class,'pages')]//a[img/@alt='Next Page']
将代码与XML结构进一步解耦


匹配类属性时,你也应该考虑使用一个更正确的版本,但是它会使表达式稍微复杂一点。看看这个。

不确定额外的ASCII字符(我可能只是在提交时做了一个打印错误)。。对于您建议的更改应该放在程序中的确切位置,我有点困惑。我了解每个_的“发生了什么”,并将变量分配给索引,但我不确定所有这些都应该嵌套在哪里。还有这个“页面(%Q)!”选择器语法对我来说是新的,我在任何阅读资料中都没有看到它的引用;我想多读一些逻辑,但IDK where除外。非常感谢您的耐心和分享专业知识。您应该提供一些关于下一个链接或URI的示例输入,这样我们就可以确定匹配的模式。顺便说一句,不要使用任何域示例以外的名称。{com、net、org、edu}用于提供示例域。它们是专门为此目的定义的,所有其他域都可能属于其他域,并使读者感到困惑。感谢Jens的输入,我添加了一些相关的源数据。Tin Man能够使用每个带索引的_提供一个备选方案,但我能够将其正确嵌套在我的循环中。我还尝试使用e next_results_link=page.at(“LIA img”)的css选择器,但这引发了一个错误“无法将nil转换为字符串”。提前感谢您的帮助。感谢您发布更多详细信息,这是一个现在发布的非常好的问题。XPath谓词比您似乎知道的功能强大得多(直到现在):很容易匹配该链接中包含的图像。再次运行顺利。非常感谢Jens。
'/a'.codepoints.to_a # => [47, 97]
foo = 'bar'

%Q[a b]        # => "a b"
%Q^a #{ foo }^ # => "a bar"

%[a b]        # => "a b"
%/a #{ foo }/ # => "a bar"

%q#a b#        # => "a b"
%q[a #{ foo }] # => "a \#{ foo }"

%w$a b$ # => ["a", "b"]
%W~a b~ # => ["a", "b"]

%W[a foo]      # => ["a", "foo"]
%W[a #{ foo }] # => ["a", "bar"]

%r.^foo. # => /^foo/
%r!^foo! # => /^foo/
%r/^foo/ # => /^foo/
%x(date) # => "Mon Dec  2 21:13:37 MST 2013\n"

%s[a]   # => :a
%s[a b] # => :"a b"
%i[a b] # => [:a, :b]
"He's quoting Shakesphere's \"The Taming of the Shrew\"" # => "He's quoting Shakesphere's \"The Taming of the Shrew\""
'He\'s quoting Shakesphere\'s "The Taming of the Shrew"' # => "He's quoting Shakesphere's \"The Taming of the Shrew\""
%Q[He's quoting Shakesphere's "The Taming of the Shrew"] # => "He's quoting Shakesphere's \"The Taming of the Shrew\""