在前两个问题的帮助下,我现在有了一个可以将产品信息输入数据库的 HTML 抓取工具。我现在要做的是通过让我的刮刀使用pcntl_fork
.
如果我将我的 php5-cli 脚本分成 10 个单独的块,我会大大提高总运行时间,所以我知道我不受 i/o 或 cpu 限制,而只是受到我的抓取函数的线性性质的限制。
使用我从多个来源拼凑的代码,我有这个工作测试:
<?php
libxml_use_internal_errors(true);
ini_set('max_execution_time', 0);
ini_set('max_input_time', 0);
set_time_limit(0);
$hrefArray = array("http://slashdot.org", "http://slashdot.org", "http://slashdot.org", "http://slashdot.org");
function doDomStuff($singleHref,$childPid) {
$html = new DOMDocument();
$html->loadHtmlFile($singleHref);
$xPath = new DOMXPath($html);
$domQuery = '//div[@id="slogan"]/h2';
$domReturn = $xPath->query($domQuery);
foreach($domReturn as $return) {
$slogan = $return->nodeValue;
echo "Child PID #" . $childPid . " says: " . $slogan . "\n";
}
}
$pids = array();
foreach ($hrefArray as $singleHref) {
$pid = pcntl_fork();
if ($pid == -1) {
die("Couldn't fork, error!");
} elseif ($pid > 0) {
// We are the parent
$pids[] = $pid;
} else {
// We are the child
$childPid = posix_getpid();
doDomStuff($singleHref,$childPid);
exit(0);
}
}
foreach ($pids as $pid) {
pcntl_waitpid($pid, $status);
}
// Clear the libxml buffer so it doesn't fill up
libxml_clear_errors();
这提出了以下问题:
1) 鉴于我的 hrefArray 包含 4 个 url - 如果该数组包含 1,000 个产品 url,则此代码会产生 1,000 个子进程?如果是这样,将进程数量限制为 10 个的最佳方法是什么,再以 1,000 个 url 为例,将子工作负载拆分为每个孩子 100 个产品 (10 x 100)。
2)我了解到 pcntl_fork 创建了流程和所有变量、类等的副本。我想做的是用 DOMDocument 查询替换我的 hrefArray 变量,该查询构建要抓取的产品列表,然后提供它们让子进程进行处理 - 因此将负载分散到 10 个童工身上。
我的大脑告诉我需要执行以下操作(显然这不起作用,所以不要运行它):
<?php
libxml_use_internal_errors(true);
ini_set('max_execution_time', 0);
ini_set('max_input_time', 0);
set_time_limit(0);
$maxChildWorkers = 10;
$html = new DOMDocument();
$html->loadHtmlFile('http://xxxx');
$xPath = new DOMXPath($html);
$domQuery = '//div[@id=productDetail]/a';
$domReturn = $xPath->query($domQuery);
$hrefsArray[] = $domReturn->getAttribute('href');
function doDomStuff($singleHref) {
// Do stuff here with each product
}
// To figure out: Split href array into $maxChilderWorks # of workArray1, workArray2 ... workArray10.
$pids = array();
foreach ($workArray(1,2,3 ... 10) as $singleHref) {
$pid = pcntl_fork();
if ($pid == -1) {
die("Couldn't fork, error!");
} elseif ($pid > 0) {
// We are the parent
$pids[] = $pid;
} else {
// We are the child
$childPid = posix_getpid();
doDomStuff($singleHref);
exit(0);
}
}
foreach ($pids as $pid) {
pcntl_waitpid($pid, $status);
}
// Clear the libxml buffer so it doesn't fill up
libxml_clear_errors();
但是我不知道如何仅在主/父进程中构建我的 hrefsArray[] 并将其提供给子进程。目前我尝试过的一切都会导致子进程中的循环。即我的 hrefsArray 在主进程和每个后续子进程中构建。
我敢肯定,这一切都完全错误,因此非常感谢您朝着正确的方向进行总体推动。