我写了一个PhantomJS应用程序来抓取我构建的网站并检查要包含的JavaScript文件。 JavaScript类似于Google,其中一些内联代码加载到另一个JS文件中。该应用程序查找其他JS文件,这就是我使用Phantom的原因。
预期结果是什么?
控制台输出应该读取大量的URL,然后判断脚本是否已加载。
发生了什么事?
控制台输出将按预期读取大约50个请求,然后才开始吐出此错误:
2013-02-21T10:01:23 [FATAL] QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe
QEventDispatcherUNIXPrivate(): Unable to create thread pipe: Too many open files
这是打开页面并搜索脚本的代码块:
page.open(url, function (status) {
console.log(YELLOW, url, status, CLEAR);
var found = page.evaluate(function () {
if (document.querySelectorAll("script[src='***']").length) {
return true;
} else { return false; }
});
if (found) {
console.log(GREEN, 'JavaScript found on', url, CLEAR);
} else {
console.log(RED, 'JavaScript not found on', url, CLEAR);
}
self.crawledURLs[url] = true;
self.crawlURLs(self.getAllLinks(page), depth-1);
});
crawledURLs对象只是我已经抓取过的网址对象。 crawlURLs函数只是通过getAllLinks函数的链接,并在具有爬虫开始的域的基本域的所有链接上调用open函数。
修改
我修改了代码的最后一个块如下,但仍然有同样的问题。我已将page.close()添加到文件中。
if (!found) {
console.log(RED, 'JavaScript not found on', url, CLEAR);
}
self.crawledURLs[url] = true;
var links = self.getAllLinks(page);
page.close();
self.crawlURLs(links, depth-1);
答案 0 :(得分:7)
来自文档:
由于某些技术限制,网页对象可能不会完全被垃圾收集。当反复使用同一个对象时经常会遇到这种情况。
解决方案是在合适的时间显式调用网页对象的close()
(例如,在许多情况下为page
)。
一些包含的示例(例如follow.js)演示了具有显式关闭的多个页面对象。
答案 1 :(得分:4)
即使正确关闭文件,您仍可能遇到此错误。
在搜索互联网之后,我发现您需要增加允许单个进程打开的文件数量限制。就我而言,我正在生成包含数百到数千页的PDF。
根据您运行的系统有不同的方法来调整此设置,但这是在 Ubuntu 服务器上对我有用的:
将以下内容添加到 /etc/security/limits.conf
:
# Sets the open file maximum here.
# Generating large PDFs hits the default ceiling (1024) quickly.
* hard nofile 65535
* soft nofile 65535
root hard nofile 65535 # Need these two lines because the wildcards (above)
root soft nofile 65535 # are not applied to the root user as well.
可以找到ulimit
命令的良好参考here。
我希望这会让一些人走上正轨。
答案 2 :(得分:0)
我在ruby程序中运行多个线程时出现此错误。 我和Capybara-poltergeist一起运行phantomjs,每个线程都在访问一个页面,打开同一个CSV文件并写入它。
我可以使用Mutex
类修复它。
lock = Mutex.new
lock.synchronize do
CSV.open("reservations.csv", "w") do |file|
file << ["Status","Name","Res-Code","LS-Num","Check-in","Check-out","Talk-URL"]
$status.length.times do |i|
file << [$status[i],$guest_name[i],$reservation_code[i],$listing_number[i],$check_in[i],$check_out[i], $talk_url[i]]
end
end
puts "#{user.email} PAGE NUMBER ##{p+1} WRITTEN TO CSV"
end
end