我有个程序,将图片抓回来;然后打包成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=trueif (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 - 获取所有相关的插座与卷曲的扩展名,这样就可以“选择”
今天研究一下,用这个方式的话。应该就不用表老记录图片数量啦。
表来记录图片数量啦
搞明白啦 谢谢大家。结贴 !
本文原创发布php中文网,转载请注明出处,感谢您的尊重!