gpt4 book ai didi

ruby-on-rails - 我的抓取 "stack"应该如何处理 404 错误?

转载 作者:数据小太阳 更新时间:2023-10-29 06:35:34 25 4
gpt4 key购买 nike

我有一个 rake 任务,负责对数百万个 URL 进行批处理。因为这个过程需要很长时间,我有时会发现我尝试处理的 URL 不再有效——404、站点已关闭等等。

当我最初写这篇文章时,基本上只有一个站点在处理过程中会不断崩溃,所以我的解决方案是使用 open-uri,挽救产生的任何异常,稍等片刻,然后重试.

这在数据集较小时效果很好,但现在时间过去了很多,我发现 URL 不再存在并产生 404。

使用 404 的情况,当这种情况发生时,我的脚本会停在那里并无限循环——显然很糟糕。

我应该如何处理页面未成功加载的情况,更重要的是,这如何适应我构建的“堆栈”?

我对这个和 Rails 很陌生,所以欢迎就我在这个设计中可能出错的地方提出任何意见!

这是一些匿名代码,显示了我所拥有的:

调用 MyHelperModule 的 rake 任务:

# lib/tasks/my_app_tasks.rake
namespace :my_app do
desc "Batch processes some stuff @ a later time."
task :process_the_batch => :environment do
# The dataset being processed
# is millions of rows so this is a big job
# and should be done in batches!
MyModel.where(some_thing: nil).find_in_batches do |my_models|
MyHelperModule.do_the_process my_models: my_models
end
end
end
end

MyHelperModule 接受 my_models 并使用 ActiveRecord 做更多的事情。它调用 SomeClass:

# lib/my_helper_module.rb
module MyHelperModule
def self.do_the_process(args = {})
my_models = args[:my_models]

# Parallel.each(my_models, :in_processes => 5) do |my_model|
my_models.each do |my_model|
# Reconnect to prevent errors with Postgres
ActiveRecord::Base.connection.reconnect!
# Do some active record stuff

some_var = SomeClass.new(my_model.id)

# Do something super interesting,
# fun,
# AND sexy with my_model
end
end
end

SomeClass 将通过 WebpageHelper 访问网络并处理页面:

# lib/some_class.rb
require_relative 'webpage_helper'
class SomeClass
attr_accessor :some_data

def initialize(arg)
doc = WebpageHelper.get_doc("http://somesite.com/#{arg}")
# do more stuff
end
end

WebpageHelper是在404的情况下捕获异常并开始无限循环的地方:

# lib/webpage_helper.rb
require 'nokogiri'
require 'open-uri'

class WebpageHelper
def self.get_doc(url)
begin
page_content = open(url).read
# do more stuff
rescue Exception => ex
puts "Failed at #{Time.now}"
puts "Error: #{ex}"
puts "URL: " + url
puts "Retrying... Attempt #: #{attempts.to_s}"
attempts = attempts + 1
sleep(10)
retry
end
end
end

最佳答案

长话短说

使用带外错误处理和不同的概念抓取模型来加速操作。

异常不适用于常见情况

还有许多其他答案可以解决如何为您的用例处理异常。我采取了不同的方法,说处理异常在这里从根本上来说是错误的方法,原因有很多。

  1. 在他的Exceptional Ruby一书中,Avdi Grimm 提供了一些基准测试,显示异常的性能比使用提前返回等替代编码技术慢 156%。

    <
  2. The Pragmatic Programmer: From Journeyman to Master 中,作者声明“[E]xceptions 应该为意外事件保留。”在您的情况下,404 错误是不可取的,但一点也不意外——事实上,处理 404 错误是一个核心考虑因素!

简而言之,您需要一种不同的方法。替代方法最好提供带外错误处理,并防止您的进程在重试时阻塞。

另一种选择:更快、更原子化的过程

这里有很多选项,但我要推荐的选项是将 404 状态代码作为正常结果处理。这允许您“快速失败”,但也允许您稍后重试页面或从队列中删除 URL。

考虑这个示例模式:

ActiveRecord::Schema.define(:version => 20120718124422) do
create_table "webcrawls", :force => true do |t|
t.text "raw_html"
t.integer "retries"
t.integer "status_code"
t.text "parsed_data"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end

这里的想法是,您可以简单地将整个 抓取视为一个原子过程。例如:

  • 你收到页面了吗?

    很好,存储原始页面和成功状态代码。您甚至可以稍后解析原始 HTML,以便尽快完成您的抓取。

  • 你收到 404 了吗?

    好吧,存储错误页面和状态码。快速前进!

当您的流程完成对 URL 的抓取后,您可以使用 ActiveRecord 查找来查找最近返回 404 状态的所有 URL,以便您可以采取适当的措施。也许您想重试该页面、记录一条消息,或者只是从要抓取的 URL 列表中删除该 URL——“适当的操作”由您决定。

通过跟踪重试次数,您甚至可以区分暂时性错误和更永久性错误。这允许您根据给定 URL 的抓取失败频率为不同的操作设置阈值。

这种方法还有一个额外的好处,那就是利用数据库来管理并发写入并在进程之间共享结果。这将允许您在多个系统或进程之间分配工作(可能使用消息队列或分块数据文件)。

最后的想法:向上和向外扩展

在初始抓取期间花更少的时间在重试或错误处理上应该会显着加快您的过程。然而,有些任务对于单机或单进程方法来说太大了。如果您的进程加速仍然不足以满足您的需求,您可能需要考虑使用以下一种或多种方法来降低线性度:

  • fork 后台进程。
  • 使用dRuby在多个进程或机器之间拆分工作。
  • 通过使用 GNU parallel 生成多个外部进程来最大化核心使用率.
  • 不是整体式顺序过程的其他东西。

优化应用程序逻辑应该足以应对常见情况,但如果不能,请扩展到更多进程或扩展到更多服务器。向外扩展肯定会增加工作量,但也会扩展您可用的处理选项。

关于ruby-on-rails - 我的抓取 "stack"应该如何处理 404 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11388783/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com