【发布时间】:2013-08-31 14:13:29
【问题描述】:
我目前有这个课程,用于使用 Nokogiri 从单个零售商网站上抓取产品。 XPath、CSS 路径详细信息存储在 MySQL 中。
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
...
)
class Site < ActiveRecord::Base
has_many :site_details
def create_product_links
# http://www.example.com
p = Nokogiri::HTML(open(url))
p.xpath(total_products_path).each {|lnk| SiteDetail.find_or_create_by(url: url + "/" + lnk['href'], site_id: self.id)}
end
end
class SiteDetail < ActiveRecord::Base
belongs_to :site
def get_product_data
# http://www.example.com
p = Nokogiri::HTML(open(url))
title = p.css(site.title_path).text
price = p.css(site.price_path).text
description = p.css(site.description_path).text
update_attributes!(title: title, price: price, description: description)
end
end
# Execution
@s = Site.first
@s.site_details.get_product_data
我将来会添加更多网站(大约 700 个)。每个站点都有不同的页面结构。所以get_product_data 方法不能按原样使用。我可能不得不使用case or if statement 跳转并执行相关代码。很快这个类就变得又粗又丑(700 个零售商)。
什么是适合这种情况的最佳设计方法?
【问题讨论】:
-
在这种情况下,用户会选择一家零售商,而您必须从中获取数据,还是要运行 700 家零售商才能显示数据?
-
@JamesWoodward:没有。涉及的用户没有互动。我手动将零售商 xpath 插入到数据库中。我将全部运行以显示数据。
-
我不会保证这是最好的答案,但我可能会为每个实现 get_product_data 并以通用格式返回的零售商创建一个类。然后使用工厂模式来检索您要使用的零售商的实现。它可能最终会在工厂中有一个 case/if 语句,但它会被包含并保持这个特定的类干净整洁。如果您用更多的东西来描述总体计划,这可能会有所帮助。例如。每次显示页面时是否会遍历所有 700 个,或者在某些情况下可能会遍历 300 个?
-
每天都会在特定时间迭代全部 700 个。
-
从来没有最好的通用方法。有更快,最好的可维护性,很可能你永远不需要针对特定点的最好的。但是有很多可能性。您必须研究每种可能性的权衡。