【问题标题】:Data scraping with Nokogiri使用 Nokogiri 进行数据抓取
【发布时间】:2012-09-04 06:38:06
【问题描述】:

我可以使用 Nokogiri 抓取http://www.example.com/view-books/0/new-releases,但是如何抓取所有页面?这本有五页,但不知道最后一页我该怎么办?

这是我写的程序:

require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'csv'

urls=Array['http://www.example.com/view-books/0/new-releases?layout=grid&_pop=flyout',
           'http://www.example.com/view-books/1/bestsellers',
           'http://www.example.com/books/pre-order?query=book&cid=1&layout=list&ref=4b116001-01a6-4f53-8da7-945b74fdb253'
      ]

@titles=Array.new
@prices=Array.new
@descriptions=Array.new
@page=Array.new

urls.each do |url|
  doc=Nokogiri::HTML(open(url))
  puts doc.at_css("title").text

  doc.css('.fk-inf-scroll-item').each do |item|
   @prices << item.at_css(".final-price").text
   @titles << item.at_css(".fk-srch-title-text").text
   @descriptions << item.at_css(".fk-item-specs-section").text
   @page << item.at_css(".fk-inf-pageno").text rescue nil
  end

  (0..@prices.length - 1).each do |index|
    puts "title: #{@titles[index]}"
    puts "price: #{@prices[index]}"
    puts "description: #{@descriptions[index]}"
  #  puts "pageno. : #{@page[index]}"
    puts ""
  end
end

CSV.open("result.csv", "wb") do |row|
  row << ["title", "price", "description","pageno"]
  (0..@prices.length - 1).each do |index|
    row << [@titles[index], @prices[index], @descriptions[index],@page[index]]
  end
end

如您所见,我已对 URL 进行了硬编码。你如何建议我刮掉整个书籍类别?我正在尝试海葵,但无法让它发挥作用。

【问题讨论】:

  • 由于页面没有完全加载到html源上,而是在用户浏览页面时被一些js加载。您需要一些东西来模拟用户操作或执行js。这与nokogiri无关。也许“watir”宝石可以提供帮助。
  • 好的,我试试...
  • 显示您编写的代码总是有帮助的,因此我们可以帮助您修改它,而不是期望我们对您可能编写或未编写的代码做出疯狂的猜测。跨度>
  • 动态 HTML 页面的问题在于 JavaScript。通常我们必须深入研究源代码,分析他们在做什么,然后在我们的 Ruby 代码中模仿它来执行请求。有时您可以在 HTML 或 JavaScript 中找到提示,告诉您预期有多少页,并且可以从脚本或文本节点中提取值。其他时候,就像这次一样,你必须循环直到没有结果,或者你得到一个错误。
  • 抱歉缺少代码...我已经编辑了我的问题..感谢您的帮助

标签: ruby nokogiri


【解决方案1】:

如果您检查加载更多结果时究竟发生了什么,您会发现它们实际上是在使用 JSON 来读取带有偏移量的信息。

所以,你可以像这样得到五个页面:

http://www.flipkart.com/view-books/0/new-releases?response-type=json&inf-start=0
http://www.flipkart.com/view-books/0/new-releases?response-type=json&inf-start=20
http://www.flipkart.com/view-books/0/new-releases?response-type=json&inf-start=40
http://www.flipkart.com/view-books/0/new-releases?response-type=json&inf-start=60
http://www.flipkart.com/view-books/0/new-releases?response-type=json&inf-start=80

基本上,您不断增加inf-start 并获得结果,直到您获得的result-set 小于20,这应该是您的最后一页。

【讨论】:

  • 哇,他们使用 JSON 来传递 HTML sn-ps——这有点荒谬。
  • 如果您使用response-type=html,他们会以 HTML 格式返回结果。
【解决方案2】:

这是一个未经测试的代码示例,可以做你的事情,只是写得更简洁一点:

require 'nokogiri'
require 'open-uri'
require 'csv'

urls = %w[
  http://www.flipkart.com/view-books/0/new-releases?layout=grid&_pop=flyout
  http://www.flipkart.com/view-books/1/bestsellers
  http://www.flipkart.com/books/pre-order?query=book&cid=1&layout=list&ref=4b116001-01a6-4f53-8da7-945b74fdb253
]

CSV.open('result.csv', 'wb') do |row|

  row << ['title', 'price', 'description', 'pageno']

  urls.each do |url|

    doc = Nokogiri::HTML(open(url))
    puts doc.at_css('title').text

    doc.css('.fk-inf-scroll-item').each do |item|

      page = {
        titles:       item.at_css('.fk-srch-title-text').text,
        prices:       item.at_css('.final-price').text,
        descriptions: item.at_css('.fk-item-specs-section').text,
        pageno:       item.at_css('.fk-inf-pageno').text rescue nil,
      }

      page.each do |k, v|
        puts '%s: %s' % [k.to_s, v]
      end

      row << page.values
    end
  end
end

您可以使用一些有用的数据来帮助您确定需要检索多少条记录:

var config = {container: "#search_results", page_size: 20, counterSelector: ".fk-item-count", totalResults: 88, "startParamName" : "inf-start", "startFrom": 20};

要访问这些值,请使用以下内容:

doc.at('script[type="text/javascript+fk-onload"]').text =~ /page_size: (\d+).+totalResults: (\d+).+"startFrom": (\d+)/
page_size, total_results, start_from = $1, $2, $3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 1970-01-01
    • 2020-06-10
    相关资源
    最近更新 更多