我在一个房地产网站上工作,我们将获得一个外部提要的大约100万份清单。假设每个清单都有10张与其相关的照片,大约有1000万张照片,我们需要将每一张照片下载到我们的服务器上,以避免“热链接”到它们。
我完全不知道如何有效地做这件事。我玩了一些数字,我得出结论,根据每幅图像下载速度为0.5秒,这可能需要58天以上的时间(从外部服务器下载10m张图像)。这显然是不可接受的。
每张照片的大小似乎都在50 be左右,但随着一些照片更大,更大,还有一些照片更小,照片的大小也会有所不同。
我一直在测试,只需使用:
copy(http://www.external-site.com/image1.jpg, /path/to/folder/image1.jpg)
我也尝试过cURL、wget和其他。
我知道其他网站也会这么做,而且规模要大得多,但我一点也不知道他们是如何管理这类事情的,而不需要几个月的时间。
基于我们要接收的XML提要的Sudo代码。我们使用PHP解析XML:
<listing>
<listing_id>12345</listing_id>
<listing_photos>
<photo>http://example.com/photo1.jpg</photo>
<photo>http://example.com/photo2.jpg</photo>
<photo>http://example.com/photo3.jpg</photo>
<photo>http://example.com/photo4.jpg</photo>
<photo>http://example.com/photo5.jpg</photo>
<photo>http://example.com/photo6.jpg</photo>
<photo>http://example.com/photo7.jpg</photo>
<photo>http://example.com/photo8.jpg</photo>
<photo>http://example.com/photo9.jpg</photo>
<photo>http://example.com/photo10.jpg</photo>
</listing_photos>
</listing>
因此,我的脚本将遍历每一张照片以获得特定的列表,并将照片下载到我们的服务器,并将照片名插入到我们的照片数据库中(插入部分已经完成,没有问题)。
有什么想法吗?
发布于 2015-01-16 21:25:30
我很惊讶供应商不允许你热链接。事实是,你不会每个月服务每一张图片,所以为什么下载每一张图片呢?让你热连接是一个更好的利用每个人的带宽。
我管理一个包含数以百万计的项目的目录,其中的数据是本地的,但是图像大多是热链接的。有时,我们需要隐藏图像的来源,或者供应商要求我们缓存图像。为了实现这两个目标,我们使用一个代理。我们编写了自己的代理,但您可能会找到一些可以满足您需求的开源工具。
代理的工作方式是对加密的URL字符串进行加密和URL编码。于是http://yourvendor.com/img1.jpg变成了xtX957z。在我们的标记中,img标记类似于http://ourproxy.com/getImage.ashx?image=xtX957z。
当我们的代理接收到图像请求时,它会解密图像URL。代理首先在磁盘上查找映像。我们从URL中派生出图像名,因此它正在查找类似于youvendorcom.img1.jpg的内容。如果代理无法在磁盘上找到映像,则使用解密的URL从供应商获取图像。然后,它将映像写入磁盘并将其服务于客户端。这种方法的优点是在没有浪费带宽的情况下按需运行。我只得到了我需要的图像,我只得到了一次。
发布于 2015-01-16 19:45:19
在你做这个之前
比如@BrokenBinar在评论中说。考虑到主机每秒可以提供多少请求。你不想在他们不知情的情况下向他们发出大量的请求。然后使用像睡眠这样的东西来限制您的请求,不管它们能提供多少。
卷曲多层
不管怎么说,用卷。答案有点重复,但还是抄袭了:
$nodes = array($url1, $url2, $url3);
$node_count = count($nodes);
$curl_arr = array();
$master = curl_multi_init();
for($i = 0; $i < $node_count; $i++)
{
$url =$nodes[$i];
$curl_arr[$i] = curl_init($url);
curl_setopt($curl_arr[$i], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($master, $curl_arr[$i]);
}
do {
curl_multi_exec($master,$running);
} while($running > 0);
for($i = 0; $i < $node_count; $i++)
{
$results[] = curl_multi_getcontent ( $curl_arr[$i] );
}
print_r($results);
来自:PHP并行卷曲请求
另一种解决办法是:
丝线
<?php
class WebRequest extends Stackable {
public $request_url;
public $response_body;
public function __construct($request_url) {
$this->request_url = $request_url;
}
public function run(){
$this->response_body = file_get_contents(
$this->request_url);
}
}
class WebWorker extends Worker {
public function run(){}
}
$list = array(
new WebRequest("http://google.com"),
new WebRequest("http://www.php.net")
);
$max = 8;
$threads = array();
$start = microtime(true);
/* start some workers */
while (@$thread++<$max) {
$threads[$thread] = new WebWorker();
$threads[$thread]->start();
}
/* stack the jobs onto workers */
foreach ($list as $job) {
$threads[array_rand($threads)]->stack(
$job);
}
/* wait for completion */
foreach ($threads as $thread) {
$thread->shutdown();
}
$time = microtime(true) - $start;
/* tell you all about it */
printf("Fetched %d responses in %.3f seconds\n", count($list), $time);
$length = 0;
foreach ($list as $listed) {
$length += strlen($listed["response_body"]);
}
printf("Total of %d bytes\n", $length);
?>
你真的应该使用搜索功能,你知道:)
发布于 2015-01-16 19:45:42
您可以将所有链接保存到某个数据库表中(它将是您的“作业队列”),然后您可以创建一个脚本,该脚本在循环中获取作业并执行它(获取单个链接的图像并标记作业记录为已完成)--您可以多次执行该脚本。使用监督。因此,作业队列将并行处理。如果要放慢速度,您可以只执行另一个工作脚本(如果带宽没有使您慢下来)
如果任何脚本因为某种原因挂起,您可以轻松地再次运行它,只获得尚未下载的图像。顺便说一下,如果每个脚本失败,可以配置为自动重新启动每个脚本。
另一个优点是,您可以在任何时候通过supervisorctl检查这些脚本的输出。要检查还有多少图像在等待,您可以轻松地查询“作业队列”表。
https://stackoverflow.com/questions/27990937
复制相似问题