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
关键要点解释
为什么
each不行?
Ruby的Array#each会在循环开始前就把数组的元素复制一份到迭代器里,所以你在循环中给数组加新元素,迭代器不会感知到,自然不会去遍历这些新增项。去重很重要
一定要用Set或者其他方式记录已处理的页面,不然很容易陷入死循环——比如页面A显示了页面B的链接,页面B又显示了页面A的链接,来回重复爬取。动态分页的处理逻辑
每次处理一个页面时,都要重新抓取当前页面的所有分页链接,因为网站可能在你爬了几页后才加载出更多页码。这样就能确保不会漏掉任何新出现的页面。
内容的提问来源于stack exchange,提问作者bottbott
相关产品推荐
相关产品推荐

