欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

php并发抓图怎么知道有没抓完呢

程序员文章站 2022-06-01 09:44:32
...
我有个程序,将图片抓回来;然后打包成zip。
当前用的是单线程,由于实在太慢。所以想用多线程并发抓。
但这样做的话,我不知道什么时候可以打包zip。
大侠们给点建议吧


回复讨论(解决方案)

抓回来了才会写盘
你在程序中维护一个目标列表,当列表中的文件都存在了,就可以打包了

多线程同步问题,信号量同步。

怎么抓图的,能否分享

多线程同步问题,信号量同步。

这位仁兄,可否解释更清楚一点呢。

抓回来了才会写盘
你在程序中维护一个目标列表,当列表中的文件都存在了,就可以打包了

版主 这个方法我想过。觉得挺麻烦的。因为我这边有几百个专题进行循环,一个专题内容有七八张图片。
每次通过正则获取内容中的图片地址,抓取到服务器;再压图大小。

如果需要记录,那应该是一次循环并发多个进程。然后执行完了再进入下个循环。

怎么抓图的,能否分享

抓图不难
最简单的就是file_get_contents

你难道不记录哪个图片是哪个专题的吗?

你难道不记录哪个图片是哪个专题的吗?

没有关联图片记录表
因为内容可能经常要更新,目前增加无太大的意义。

为每一个专题建立一个文件夹,每次用正则匹配的时候,就统计一下有几张图片,然后把这个数据写入到文件夹下的一个专用文件中,如.number等!

另写一个打包程序,不停的扫描这些文件夹下的文件,并与特殊文件中的文件个数进行比较,如果文件个数相等就直接打包,并删除文件夹!

PV操作。。你要维持一个信号量。简单的说是一个变量。如果程序运行之前你就知道要抓取多少文件,那么这个值在一开始就是确定的,比如说你知道要抓取5张图片,那么这个变量的值就是5,每个子进程完成一张图片抓取动作这个变量就减一,最终为0时表示全抓完了。

如果一开始不知道要抓多少图片,那么这个信号量需要动态维护了,且要加入其他信号量来控制进程间的同步。比如有可能该信号量为0,但实际上还有进程在分析是否还有图片要进行抓取,而因为该信号量为0,程序直接退出。这样的情况也要考虑。

另外,你怎么用的多线程?PHP不支持多线程的。

apache有多线程组件
也可是用iframe实现吧

另外,你怎么用的多线程?PHP不支持多线程的。

php 5.+ 之后的curl是支持多线程的,你是每下载一个就要打包一次?

为每一个专题建立一个文件夹,每次用正则匹配的时候,就统计一下有几张图片,然后把这个数据写入到文件夹下的一个专用文件中,如.number等!

另写一个打包程序,不停的扫描这些文件夹下的文件,并与特殊文件中的文件个数进行比较,如果文件个数相等就直接打包,并删除文件夹!

这个方法挺好的。不过可能用表会更好点,因为可以记更多东西。比如已触发抓取的图片,抓取的状态;完成的时间等。

我简单描述下这边的情况
由于软件那边的一个专题app,有这样一个功能。
用户需要可以下载离线包浏览专题。

和软件那边约定好的格式为zip

zip内结构为
文件夹(专题id)对应多个专题图片 一个专题首页
而多个专题就会生成多个文件夹,文件夹名为专题id。

我现在的工作是要将这些专题生成文件夹数据,然后再打包为zip。提供给软件那边下载。
专题图片是由专题内容中正则匹配图片地址,再抓回来的。
现在出现的问题,由于几百个专题。一个专题内容有八九张图片;
造成抓取速度狠慢。

或者我需要一个表,记录每次循环正则匹配的图片数;每次抓取成功或失败都去减少这个量。
然后在程序中while查询这个数量,直到为零的时候就进入下一个专题。

另外,你怎么用的多线程?PHP不支持多线程的。

有办法的 可以用fsockopen触发抓图程序的链接。 不需等待该链接返回,程序会继续跑。

抓取宜使用 curl,技术简单且效率高
curl 可直接将抓取的数据写入文件
curl_multi 可同时挂载多个 curl
curl_getinfo 可获取相关的工作信息(如果需要的话)

判定 curl_multi 各成员结束,就判定了抓取结束
这也符合你不打算保存进度信息的初衷

抓取宜使用 curl,技术简单且效率高
curl 可直接将抓取的数据写入文件
curl_multi 可同时挂载多个 curl
curl_getinfo 可获取相关的工作信息(如果需要的话)

判定 curl_multi 各成员结束,就判定了抓取结束
这也符合你不打算保存进度信息的初衷

版主 我可以加多个表记录状态,不过这个表应该怎样设计好呢。
一个包关联多个专题,多个包可以并发进行生成zip操作。
我想过这样的表结构

proc的结构
id 图片地址 包id 执行状态(1为已抓取) 专题id

一开始清空 proc 当前生成 包id的记录数
循环专题的时候
匹配了图片地址 一张为一条记录插入这张表。
抓取成功或失败则更新执行的状态
最后有个循环
直到查询这张表的某个包,某个专题的图片执行状态为1的记录数等于正则匹配的图片数则进入下一个专题循环。

我不确定有没描述清楚,这个生成过程还有其它的一些操作;刚开始我只抽了关键的一些来描述。

版主 我proc表的设计合理不。

版主大哥 我在等你回复呢

我已经按这个想法写好程序 下午测试

你测试了,发现不足就改进
发现不能解决的问题就提问

修正了一下午 用fsockopen 来触发一个抓取图片的脚本。如果不fgets就触发不了。本地试是可以的。搞不清楚什么原因。

后来网上搜了个

**  * curl 多线程  *   * @param array $array 并行网址  * @param int $timeout 超时时间 * @return array  */  function curl_http($array,$timeout){ 	$res = array(); 	$mh = curl_multi_init();							  //创建多个curl语柄	$startime = getmicrotime(); 	foreach($array as $k=>$url){ 		$conn[$k]=curl_init($url);        curl_setopt($conn[$k], CURLOPT_TIMEOUT, $timeout); //设置超时时间        curl_setopt($conn[$k], CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');        curl_setopt($conn[$k], CURLOPT_MAXREDIRS, 7);	   //HTTp定向级别        curl_setopt($conn[$k], CURLOPT_HEADER, 0);		   //这里不要header,加块效率        curl_setopt($conn[$k], CURLOPT_FOLLOWLOCATION, 1); // 302 redirect        curl_setopt($conn[$k],CURLOPT_RETURNTRANSFER,1);        curl_multi_add_handle ($mh,$conn[$k]); 	}	do {		$mrc = curl_multi_exec($mh,$active);		//当无数据,active=true	} 	while ($mrc == CURLM_CALL_MULTI_PERFORM);		//当正在接受数据时	while ($active and $mrc == CURLM_OK) {		//当无数据时或请求暂停时,active=true		if (curl_multi_select($mh) != -1) {			do {				$mrc = curl_multi_exec($mh, $active);			} while ($mrc == CURLM_CALL_MULTI_PERFORM);		}	} 	foreach ($array as $k => $url) {	  curl_error($conn[$k]);	  //$res[$k]=curl_multi_getcontent($conn[$k]);//获得返回信息	  $header[$k] = curl_getinfo($conn[$k]);//返回头信息	  curl_close($conn[$k]);//关闭语柄	  curl_multi_remove_handle($mh, $conn[$k]);   //释放资源		  	}	curl_multi_close($mh);	$endtime = getmicrotime();	$diff_time = $endtime - $startime;		return array(		'diff_time'=>$diff_time,		'return'=>$res,		'header'=>$header				); 	 } //计算当前时间 function getmicrotime() {	    list($usec, $sec) = explode(" ",microtime());	    return ((float)$usec + (float)$sec);}


测试过还行。不过不知道为啥本地测试的话,file_get_contents比这个更快。

while ($active and $mrc == CURLM_OK) {        //当无数据时或请求暂停时,active=true        if (curl_multi_select($mh) != -1) {            do {                $mrc = curl_multi_exec($mh, $active);            } while ($mrc == CURLM_CALL_MULTI_PERFORM);        }    }


另外 不大理解这句的作用。 上面已经触发了链接。
这段是用来检测什么时候完成的吗 ?

            do {                $mrc = curl_multi_exec($mh, $active);            } while ($mrc == CURLM_CALL_MULTI_PERFORM);


这段和上面的重复

你用了 curl_multi_select 函数,却又不知道他是干什么的,....

手册说
curl_multi_select -- Get all the sockets associated with the cURL extension, which can then be "selected"
google说
curl_multi_select - 获取所有相关的插座与卷曲的扩展名,这样就可以“选择”

今天研究一下,用这个方式的话。应该就不用表老记录图片数量啦。

表来记录图片数量啦

搞明白啦 谢谢大家。结贴 !