我经营一家网上商店,经营收藏品,其市场价格根据消费者需求不断变化。
我最近开始记录我的竞争对手'价格通过每日运行一个ruby脚本(一个rake任务),通过一个~30k的URL列表,抓取一些相关的数据,并将它们填充到Elasticsearch索引中。我依靠Nokogiri和PhantomJS来实现这一目标,因为并非所有站点都能正确呈现我需要的数据而无需运行JavaScript。
我的程序在运行时目前占用大约4GB内存,而PhantomJS占据了大部分消耗(~2.5GB)。脚本也需要花费很多时间才能运行 - 我不确定多长时间,但我认为它超过10个小时。
我非常愿意接受有关如何减少内存消耗和提高我的速度的建议。我希望我的竞争对手能为我提供一个不错的JSON API,但不幸的是我们没有这种关系。
答案 0 :(得分:2)
最明显的工作是确定哪些网站需要完整的浏览器处理,哪些网站可以直接翻录而不需要任何网站。
第二件事是检查正在运行的JavaScript应用程序,看看是否有任何方法可以直接从它正在使用的API获取所需的数据。在客户端应用程序(例如Angular,React,Ember)中通常会出现与服务器通信的某种JSON API。如果您可以直接与该API接口,它实际上大大简化了您的数据收集过程:您甚至可能根本不需要解析任何HTML!
Ruby在处理事物方面通常都很不错,但它并不总是最有效的。需要考虑的是,如果使用JRuby并且线程可能会提高性能,通常它是一个替代品,运行速度提高约40%,但代价是更高的初始内存占用。
您可能还想探索使用Node.js执行大量获取/执行JavaScript的肮脏工作的可行性,因为与Ruby的许多JavaScript运行时相比,它的重量非常轻。它甚至可以作为一个非常好的预取器,然后可以将内容移交给Ruby后端以进行更多处理。
使用数据库,Redis或RabbitMQ中间层作为队列或持久性机制,构建这样的混合系统非常容易。
答案 1 :(得分:1)
在不影响吞吐量的情况下,您可以做一些事情来提高抓取速度并保持较低的内存消耗。
为了减少内存消耗,您可以将URL保存在平面文件或数据库中,而不是通过数据结构将其保存在内存中。
在几次迭代后也清空任何数据的数据结构。
我假设您按顺序提出请求,因为每次抓取网址所花费的平均时间大于1.2秒(10 * 60 * 60/30000 = 1.2)。您可以一次对一堆请求进行异步调用,因为您的代码将等待一个请求完成,直到它成为下一个请求。
您可以参考“Building blocks of a scalable web crawler”,其中涵盖了可扩展抓取的大部分方面。
由于我没有关于您的代码的任何信息,因此我可以给出一些建议。
答案 2 :(得分:0)
我认为你应该节省时间并使用SaaS服务。
我相信有时间和地点推出自己的功能。例如,如果您想出于估价原因将其构建为您自己的IP,或者您认为这可以抓住您组织的核心竞争力(即,这是一种竞争优势)。但是,考虑到你需要它能够很好地工作而不是在爬行,这是站在别人肩膀上的好时机。
答案 3 :(得分:-2)
我假设你在单线程上运行你的刮板(因为需要时间来完成)。您应该考虑在多个线程上运行脚本。 https://www.tutorialspoint.com/ruby/ruby_multithreading.htm