2017-02-10 81 views
0

我正在构建一个包含大约140个URL的数据库的PHP应用程序。使用PHP curl下载许多网页

目标是下载这些网页内容的副本。

我已经编写了从我的数据库中读取URL的代码,然后使用curl来获取页面的副本。然后它获取<body> </body>之间的所有内容,并将其写入文件。它还考虑到重定向,例如如果我转到一个URL并且响应代码是302,它将遵循适当的链接。到现在为止还挺好。

这一切都适用于一些网址(也许20左右),但然后我的脚本超时由于max_execution_time设置为30秒。我不想重写或增加这个,因为我觉得这是一个糟糕的解决方案。

我想到了2个解决方法,但想知道这些是好还是坏的方法,或者如果有更好的方法。

第一种方法是在数据库查询上使用LIMIT,以便一次将任务分成20行(即如果有140行,则分别运行脚本7次)。我从这个方法中明白,它仍然需要调用script,download.php,7个不同的时间,所以需要通过限制数字。

第二种方法是在脚本中传入我想要的URL(例如download.php?id=2)的每个数据库记录的ID,然后对它们执行多个Ajax请求(download.php?id=2, download.php?id=3, download.php?id=4等)。基于$_GET['id']它可以做一个查询来查找数据库中的URL等。理论上我会做140个单独的请求,因为它是每个URL设置1个请求。

我读过一些其他指出排队系统的帖子,但这些都超出了我的理解。如果这是最好的方法,那么是否有一个值得一看的特定系统?

任何帮助,将不胜感激。

编辑:目前有140个网址,而且这个网址可能会随着时间推移而增加。所以我正在寻找一种解决方案,可以在没有超时限制的情况下进行扩展。

+0

更改max_execution_time可能是最好的解决方案,因为您确实不知道要花费多长时间才能抓取140页,或者服务器是否会滞后,并使某些请求比其他请求花费更长的时间。 – Brogan

+0

延长超时并不是一个糟糕的解决方案。使用['set_time_limit(30)'](http://php.net/manual/en/function.set-time-limit.php)循环的每个步骤(或任何对于单个页面合理的)。这是一个合理的说法,“我将允许每CURL呼叫X秒”。 – apokryfos

+1

我会用ajax调用方法。所以你可以抓住数据库中的所有记录,迭代它发送ajax调用,然后在完成时报告。接收到调用(并进行工作)的脚本可能会报告并说出如下内容:“X中的X已完成,Y中有错误” – LordNeo

回答

2

我不同意你的逻辑,如果脚本运行良好,需要更多时间完成,只是给它更多的时间,这不是一个糟糕的解决方案。你的建议使事情变得更加复杂,并且不能很好地扩展如果你的网址增加。

我会建议你的脚本移动到没有时间限制的命令行,而不是使用浏览器来执行它。

+0

完全相反,当列表变大时,增加超时将不会升级。你不能无限增加超时。 ajax调用将分离每个进程并将其隔离为一个单独的线程,以便他可以获得多个结果(成功/失败),而无需从头开始重新运行所有内容。 – LordNeo

+1

这不是我所建议的,我说移动到没有时间限制的命令行。 set_time_limit(0)的equivelant; –

+0

无法让命令行无限期地打开,您不知道列表是否会像10.000一样大或保持不变。 – LordNeo

1

当你有一个未知的列表,这将需要一个未知的时间异步调用的路要走。

将你的脚本分成单页下载(就像你建议的,download.php?id=X)。

从“主”脚本中获取数据库中的列表,遍历它并向每个脚本发送一个ajax调用。由于所有的电话都会立即被触发,请检查您的带宽和CPU时间。您可以使用成功回调将其分解为“X活动任务”。

您可以设置download.php文件返回成功数据或将其保存到数据库中,并使用网站的ID和调用结果。我推荐以后的版本,因为您可以稍后离开主脚本并获取结果。

你不能无限期地增加时间限制,不能等待无限期的时间来完成请求,所以你需要一个“消失和忘记”,这就是异步调用最好的。

@apokryfos指出,根据这种“备份”的时机,你可以将它安装到任务调度器(如chron)中。如果你把它叫做“on demand”,把它放在一个gui中,如果你把它称为“每x次”,把一个指向主脚本的时间任务放在它上面,它也会这样做。

+1

上的差异。比如适合任务调度器而不是客户端UI的东西。 CLI可能是一种更好的方法。 – apokryfos

0

您所描述的内容听起来像是控制台的工作。浏览器供用户看,但你的任务是程序员将运行的东西,所以使用控制台。或者安排文件以cron-job或类似的方式由开发人员处理。

0

使用stream_socket_client()同时执行所有请求。将所有套接字ID保存在一个数组中

然后使用stream_select()循环访问ID数组以读取响应。

这几乎就像PHP中的多任务处理一样。