You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby爬虫动态分页迭代问题:each遍历无法新增循环次数

解决Ruby爬虫动态分页遍历的问题

你遇到的这个问题其实很常见——当用each遍历数组时,Ruby会先把数组的元素快照下来,所以在循环里往数组加新元素,并不会让each去遍历这些新增的项。要处理这种动态加载的分页,我们得换一种遍历方式,让程序能持续处理新发现的页面,直到没有新页面可爬为止。

下面给你两种实用的解决方案:

方案1:用数组配合while循环+shift

这种方式最简单,不需要额外引入类库。核心思路是:用一个数组存待处理的页面,每次从数组头部取出一个页面处理,处理完后把新发现的未处理页面加到数组尾部,直到数组为空。

require 'nokogiri'
require 'open-uri'
require 'set'

# 初始化待处理页面数组,初始是你拿到的第一波页面
cleanpages = ['page1_url', 'page2_url']
# 用Set记录已处理的页面,避免重复爬取
processed_pages = Set.new

while !cleanpages.empty?
  current_page_url = cleanpages.shift # 取出第一个待处理页面
  
  # 跳过已经处理过的页面
  next if processed_pages.include?(current_page_url)
  processed_pages.add(current_page_url)

  # 这里写你的页面处理逻辑:打开页面、抓取数据
  puts "正在处理页面: #{current_page_url}"
  doc = Nokogiri::HTML(URI.open(current_page_url))
  # ... 抓取二手车数据的代码 ...

  # 获取当前页面显示的所有分页链接
  new_pages = doc.css('.pagination a').map { |a| a['href'] }.uniq
  # 过滤掉已经处理过和已经在待处理数组里的页面
  new_pages.reject! { |url| processed_pages.include?(url) || cleanpages.include?(url) }
  # 把新页面加到待处理数组尾部
  cleanpages.concat(new_pages)
end

方案2:用Queue类(线程安全)

如果你的爬虫后续可能改成多线程,用Queue会更合适,它本身就是线程安全的,处理动态添加的元素非常方便:

require 'nokogiri'
require 'open-uri'
require 'thread'
require 'set'

# 初始化队列
page_queue = Queue.new
# 把初始页面加入队列
['page1_url', 'page2_url'].each { |url| page_queue << url }
processed_pages = Set.new

until page_queue.empty?
  current_page_url = page_queue.pop(true) rescue nil # 非阻塞弹出,避免空队列报错
  next if current_page_url.nil? || processed_pages.include?(current_page_url)
  
  processed_pages.add(current_page_url)
  puts "正在处理页面: #{current_page_url}"
  doc = Nokogiri::HTML(URI.open(current_page_url))
  # ... 抓取数据 ...

  # 获取新分页链接
  new_pages = doc.css('.pagination a').map { |a| a['href'] }.uniq
  new_pages.each do |url|
    unless processed_pages.include?(url) || page_queue.include?(url)
      page_queue << url
    end
  end
end

关键要点解释

  1. 为什么each不行?
    Ruby的Array#each会在循环开始前就把数组的元素复制一份到迭代器里,所以你在循环中给数组加新元素,迭代器不会感知到,自然不会去遍历这些新增项。

  2. 去重很重要
    一定要用Set或者其他方式记录已处理的页面,不然很容易陷入死循环——比如页面A显示了页面B的链接,页面B又显示了页面A的链接,来回重复爬取。

  3. 动态分页的处理逻辑
    每次处理一个页面时,都要重新抓取当前页面的所有分页链接,因为网站可能在你爬了几页后才加载出更多页码。这样就能确保不会漏掉任何新出现的页面。

内容的提问来源于stack exchange,提问作者bottbott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:33:53