curl多线程采集----评论

文章《curl多线程采集》的讨论如下


  1. william2016 年 3 月 20 日下午 3:21 说道:

    我想抓取http://china.nba.com/playerindex/上面的所有球员的信息保存到数据库中,代码应该怎么写?

  2. 你好,我用的是DEMO4,程序结构和演示的是一样的,只是改成我的数据
    在函数demo4_cb1 的$curl->status();这个语句后加了一条
    phpQuery::unloadDocuments();

    但是程序运行到 78万条时
    不动了
    提示 :Allowed memory size of 8388608 bytes exhausted (tried to allocate 1298358 bytes)…… 错误 PHPQUERY LINE 56

    请问是怎么回事呢?谢谢

  3. 请问为什么每次一到2414个任务的时候就提示 ETA 1sKilled,一共有6W个任务的。
    96.98% 2341/2414(0) 167/s 1.97MB/s 27.55MB ETA 1sKilled
    弄了好久一直都是这样,请问这是什么原因呢?

  4. phpxiebin2015 年 5 月 21 日下午 4:55 说道:

    建议博主该功能curl调用的时候每次按一个顺序来调用,目前是随机链接顺序调用

    • phpxiebin2015 年 5 月 21 日下午 5:01 说道:

      打乱是有优点,但是根据场景吧,我是curl远程获取账户数据,每次顺序都不同,我想直接生成个HTML表格页面,总不能每次都顺序不一样,建议加个属性,比如什么1是随机,2是按顺序什么的,我自己本地改造过了

      • 不需要改造。
        输入一批url,输出对应的结果,哪个url先完成就先处理哪个,按循序的话你直接改成单线程即可,或者手动处理返回的那一批结果。
        库本身是面向对象的组件化编程产物,不会针对某类需求做特殊处理。

  5. 极天2015 年 3 月 30 日下午 12:22 说道:

    求发个最新版的635842671@qq.com 不知道为什么下载不来 那几个网站都打不开 翻过墙了谢谢大牛了

  6. 写的不错,感谢博主的耐心,发我一份 ,超级 感谢

  7. 匿名2014 年 12 月 23 日上午 9:42 说道:

    频繁采集导致数据返回空,对方做了限制,如何解决

  8. 匿名2014 年 11 月 4 日下午 11:08 说道:

    我自己写的采集程序,偶尔下载大文件的时候,会出现morformed 错误,是为何呢?

  9. 楼主, 这个 CurlMulti.php 是加密的? 汗, 还准备拜读一下

  10. centos lnmp环境。
    网页直接访问demo1.php或我修改的php均出现以下错误:
    Warning: curl_setopt_array() [function.curl-setopt-array]: CURLOPT_FOLLOWLOCATION cannot be activated when safe_mode is enabled or an open_basedir is set in /home/wwwroot/vip/caiji/CURL.php on line 422

    Fatal error: Call to undefined function debug_print() in /home/wwwroot/vip/caiji/CURL.php on line 178

    命令行访问只出现这个错误:
    Fatal error: Call to undefined function debug_print() in /home/wwwroot/vip/caiji/CURL.php on line 178

    亲,什么原因呢?

    • 亲,找了一整天,发现貌似是open_basedir的问题。
      把open_basedir关了,还是无法运行demo1.php或我写的采集程序。

      还是有这个错误提示:
      Fatal error: Call to undefined function debug_print() in /home/wwwroot/vip/caiji/CURL.php on line 178

      windows能正常运行啊,这个错误提示在网上也没有找到相关说明。
      哪里错误了呢

      • CURL.php178行是function read($url) 功能的代码。
        小白猜测是不是读取网页都有问题了?
        果然demo1.php只保留curl读取,还出现了这个错误提示。
        就算目标网页很简单,还是无法读取到内容。

        如果是读取baidu,就很正常,有点奇怪。

        亲,是不是centos 上面的curl模块需要升级了?

        • debug_print()是自定义函数替换为user_error()即可。
          我可以肯定类的稳定性,采集了n亿的页面也没出问题。
          类升级了n次,接口等变化很大,具体什么问题自己修改类代码调试。

  11. padtong2014 年 3 月 4 日下午 3:46 说道:

    在实际使用中发现 有个站点加了header才能抓取
    这个类应该完善下

    • 为所有任务设置header
      $curl->opt[CURLOPT_HTTPHEADER]=’xxx’;
      单独为某一个任务设置header
      $curl->add(array(‘url’=>’xxx’,’opt’=>array(CURLOPT_HTTPHEADER=>’xxx’)));

      本类功能和性能已经完美。

  12. 道哥2014 年 1 月 15 日下午 5:42 说道:

    博主,又来请教了。如果主机有多IP的话,如何在多线程运行过程中自动切换网关来实现IP轮转?

    • 你说的主机应该是运行curl的机器,你说的多IP应该是多网卡多IP
      curl本质就是一个浏览器,主机多网卡访问外网只能有一个起作用,这是由路由规则决定的,浏览器无法选择网卡,所以curl也不行。

      可能的方案:
      如果主机是windows环境可以使用route命令修改路由,这个我亲身实践过,如果要实现ip轮转只能用php调用route命令动态修改路由实现,估计轮询性能好不到哪去。

      如果是linux主机,不知道有没有类似windows的route命令来修改路由,但是可以通过iptables的NAT模块实现,这个亲身实践过,不过这个够你喝一壶的,具体知识可以参考这里http://blog.phpdr.net/iptables%E5%88%9D%E6%8E%A2.html

      通过切换网关还不如把其他IP做成代理更简便快捷,理论上是可以实现的,privoxy或者php自己实现都可以,windows和linux都可以实现,具体细节不讨论,比较麻烦。

  13. 有些需要登录才能采集的,如何加入获取的cookie?

  14. windows命令行中文可能乱码导致非常奇怪的错误(尤其是demo5),所有代码在linux下测试完全正确。
    这个转一下码就可以了,
    $filename=iconv(‘utf-8′,’gbk’,$name).’.’.$ext;
    demo5里面我这样就可以保存成中文的名字了。还在研究博主的类,还没看懂,不过试了下pthreads,确实不错,博主试一下,会爱上它的,博主的示例代码 没有unloadducoment,导致内存可以占到2、3g去,而且那时运行速度非常慢。
    不过还是非常感谢强大的博主,提供这么好的东东。

  15. 匿名2013 年 12 月 23 日下午 4:34 说道:

    这个和多进程采集是一样的吗

  16. wiskeyjohn2013 年 12 月 15 日上午 1:59 说道:

    我是用你的多线程的curl采集类,发现有个问题,就是我采用了链式采集,思路是这样:

    主要是担心第一个回调函数使用了sleep来防止被封IP地址,假如我其中一个子进程正在执行插入数据库,但是突然某个进程调用回调函数的时候刚刚判断到要进行sleep(5),这插入数据库的进程是中断已经正在插入的来休息1秒钟

    或者是某个子进程还在下载的时候,还没下载完,突然间另外一个子进程遇到了sleep(5);程序会怎么处理那个正在加载的子进程,休息了一秒钟之后,之前那个下载进程是重新开始下载还是,继续下载还未下载完的文件,假如被采集的网站不支持续传,会怎么样呢?

    求大神指导一下!调试了一个星期了,终于弄明白您的多线程类大致原理,但是我看了您的博客,没有提及这个sleep(5)对其他进程影响。

    • 运行原理你搞错了!
      PHP没有多进程,PHP只能运行一个进程,php有个扩展pthreads可以实现多线程,没有测试,应该能利用多核CPU。
      curl扩展自己内部维护一个多线程操作,但是和PHP没有关系,PHP始终是以顺序结构运行程序!
      链式采集原理:
      curl类做的工作很单纯,记录任务(每个任务包含url,回调函数,curl配置等相关信息),并发数不够就从任务缓冲区取任务开始执行,只要有任务完成就调用对应的回调函数,回调函数是阻塞的!回调完成之后curl类继续轮询运行中的任务(轮询容易理解,实际上也是一个阻塞操作,不会进行空轮询,这是本类非常重要的一个特性,保证了cpu占用基本为零),有完成的任务继续上述操作,直到所有任务完成,第一个curl->go()才会结束。
      任务缓冲池是一个堆栈数据结构,后添加的任务先得到执行,保证链子中总是最后面的节点先执行。
      curl类本质还是顺序执行,有点类似while循环。

      结论:回调函数是阻塞的,如果sleep(5)会导致所有PHP代码都sleep,但是php的curl扩展可能还在后台做一些事情。本类用的多线程是curl扩展的多线程,php本身还是顺序执行。php的多线程目前只有pthreads扩展可以实现。

  17. 请教下楼主,我在测试addtask时发现总会有部分任务跑不完。最后的报错为Fatal error: Call to a member function fetchAll() on a non-object in XX.PHP on line XX。
    我观察了程序运行的过程,首先会读取所有的数据出来放入taskpool当中,但是当运行了一段时间后taskpool中的任务为29也就是小于30的时候,程序会再调用addtask函数并添加到taskpool中。这个过程是OK的,但是问题出在最后的一个队列上,也就是当taskpool中的任务为29时,程序会去获取调用addtask函数,并且由于SQL返回的结果为空导致报错退出,所以最终active并且在running的29个任务+taskpool中的29个任务就始终都不会被执行到了。
    请问该如何处理这种问题呢?尽管对于全局来说少采几十个无所谓,但看到error始终不舒服。。。

  18. 艾哈2013 年 11 月 20 日下午 4:53 说道:

    请问采集GBK编码的网页乱码怎么处理?谢谢了

  19. tor的速度是个大问题。
    尝试多端口同时去采集同一网址,一旦某个线程完成抓取就直接返回结果,其他线程直接舍弃。想以此选择N端口中最快的一条线路进行抓取。
    结果发现这种情况,速度反而变得更慢了。
    后直接不用tor,对比并发采集10条相同url跟单线程采集。发现总时间上,并发占了点优势。但是响应时间上完全没优势。
    瓶颈?

    • 没有任何瓶颈。
      tor如果不慢就不正常了,请先了解tor的原理。
      并发占了点优势跟多线程和单线程没关系,和网络稳定性、网速、对方服务器速度、缓存等一系列因素有关系。

  20. 楼主,我问个问题,假如添加了200个任务,$curl->go();之后,是把这200个一波同时发出去。
    假定每个线程平均需要5秒执行完。在第3秒时,有些线程快早1秒已经执行完了,这里运行中的线程假设只有100个了(因为另100个已经执行完)。这时$curl不会自动添加新的任务时来,需必须等这200个全部执行完才添加下一批。是这样吗?

    如果是这样,假如我有10万个任务需要执行,每波200个,过程中的流量是不平滑的,带宽不能充分利用,有什么办法能更平滑的执行?

  21. boring2013 年 10 月 29 日下午 2:27 说道:

    请教博主。这个类中如果我每条url要设置不同的header(比如用不同的代理)。要在哪里传递进去?

    • 3.curl配置分为三个级别,优先级由低到高如下,优先级高的会覆盖优先级低的配置。
      默认:如私有方法init()中所示。
      类级别:保存在 $opt这个公有属性中,此CURL对象的所有操作中都会起作用。
      任务级别:多线程任务中添加任务时指定,只在当前任务中起作用。

      $curl->add(array(‘url’=>’http://xxx.com’,’opt’=>array(CURLOPT_PROXYPORT=>’127.0.0.1:8118′)));

  22. benryyang2013 年 10 月 29 日下午 1:14 说道:

    您好,博主,curl能做定时任务吗?感觉一次采集太多了,IP被封了,可以坐定时采集吗

  23. php cURL入门教程
    http://3aj.cn/php/96.html

  24. xiaomi2013 年 9 月 30 日下午 4:00 说道:

    类中的download方法有一个错误,fclose($fp),之前设置参数时没有引用此资源,是直接打开的,所以关闭的时候没有引用的符号,用$fp是错的,要在前面加上一句$fp=fopen($file,’w’);然后把参数中的换成$fp

  25. 飞来飞去2013 年 8 月 28 日下午 3:11 说道:

    只要每个URL支持一个代理,支持一个COOKIE文件,就可以了,可以实现不

  26. 匿名2013 年 8 月 22 日上午 11:24 说道:

    First argument is expected to be a valid callback???

  27. tao_6272013 年 8 月 4 日下午 8:01 说道:

    博主,您好,我发现大家很少用task,task_param这种方式的多任务调用方法,我觉得大家应该多用,因为这种方法是等添加的任务快执行完,再添加,占资源比较少。

    但是,楼主的addTask函数中存在笔误:
    if(!emtpy($task)) 应该改为 if(!emtpy($this->task))

    call_user_func_array($this->task,$this->$task_param);
    应该改为
    call_user_func_array($this->task,$this->task_param);

    • 检查下,你写的这个有无笔误?
      empty还是emtpy?

      • tao_6272013 年 8 月 11 日下午 1:03 说道:

        楼主,你好,这里我有笔误,应该是empty。
        但是我在使用时,发现一个问题,就是当我使用task和taskparam时,在一个查询数据库的回调函数中,多个线程都会去调用这个回调函数,当没有更多记录时,所有的线程都执行同样的查询,而且设置$this->task=null来避免进一步调用回调函数时,容易出问题,导致程序退出。

  28. 博主写的很赞!

  29. 老江2013 年 7 月 31 日上午 10:29 说道:

    以前没有涉及过多级分层资源的采集,现在才发现博主的采集类,是采集多级分层资源的利器。好象火车头不能采集多级分层资源吧,比如商品信息,有多级商品分类。我想即使火车头能用来采集,效率也是个大问题。如果商品分类数量和商品数量有限,可能不是大问题;当商品分类有n个级别而且数量巨大的时候,不能想像用火车头采集会是什么情况。看来火车头是专为采集文章定做的。

  30. 老江2013 年 7 月 28 日下午 6:47 说道:

      博主的程序构思精巧,我正在学习。但我发现不同类型的网站,回调函数需要重新编写。我准备搞一个通用的,用规则代替回调函数,这一点比较像火车头。呵呵。

      博主的程序很有学习价值,比如将采集分解为任务的方式进行,这让每个任务获得自由,以便打乱顺序充分发挥多线程优势,并且通过使用回调函数使处理智能化自动化。火车头则比较死板,必须分布进行,每一步之间是手动而非自动的。

      有关任务和任务的调度,以前没有涉及过,跟博主学到不少东西。

  31. qxhy1232013 年 7 月 28 日下午 12:25 说道:

    请问tor在linux下如何启动多个实例,我怎么无法启动超过2个实例

    • qxhy1232013 年 7 月 29 日上午 9:41 说道:

      启动多个tor实例已经搞定了,现在的问题就是tor貌似很消耗资源的样子,我2G内存的vps开了80个,内存就跑了80%,负载直接飙到10,而且这些实例貌似不能持续运行,大概5分钟之后就神奇的消失了,只剩3个实例,不知道博主有木有遇到这样的情况

      • tor的源码包中包含有一些控制脚本,就是带start,stop,restart参数的那种脚本,用哪个脚本启动tor客户端,没遇到过那个问题。
        tor有两种运行模式,客户端和服务端,负载大估计你开了没必要的东西,tor的技术性问题我也不太懂,你只能去官网看文档。

  32. tao_6272013 年 7 月 26 日上午 10:03 说道:

    楼主,您好,如果我在curl类运行过程中,突然中断php进程,会有什么后果?
    我测试发现,会有内存泄露,我不知道,这种异常中断情况下,curl中的那个taskpool中的添加的大量任务是否会释放内存?我的qq是48019671,还有问题要请教楼主,项目遇到内存问题,急呀?

    • 突然中断php进程不会有任何后果,php程序结束而已。
      类本身没有内存泄露问题,不管什么中断,php结束后会释放所有内存。
      你说的内存泄露问题,应该是两个原因中的一个,1.程序逻辑有问题。2.你使用了phpQuery,这个库每次调用完了都要手动phpQuery::unloadDocuments(),否则处理的内容会堆积在内存中!

  33. 匿名2013 年 7 月 16 日下午 11:44 说道:

    在windows下的CMD或浏览器运行demo1 ,没有任何反应,然后PHP进程一下保持在50%以上.

    看了下是在while($curlInfo = curl_multi_info_read($this->mh,$this->queueNum)){这一行就卡在这不动了

  34. 飞来飞去2013 年 6 月 25 日上午 3:34 说道:

    当使用read()的时候提示

    Warning: error: code 3, malformed in /include/CURL.php on line 179

  35. 飞来飞支2013 年 6 月 6 日下午 7:38 说道:

    如果在一个回调函数中再加一个采集,要等这个采集结束后,回调函数才结束,造成,如果一个网站有多层的话,效率就很低下,要等最后一层采集完,才一层一层释放资源.
    同样一个网站,如果把URL都采集好,并行采集是快

    • 这个问题已经考虑到了,并且完美解决,请先看完教程 3.链式抓取。
      不管网站结构有多少层都可以并行执行,链式任务是一个堆栈数据结构,所以总是优先完成最内层的任务。
      目前来说一个PHP进程中只需要一个curl对象可以完成所有可能的任务。
      你说的那种情况完全是程序结构问题导致。
      链式抓取根本不需要提前把url采集好,并且没有比这种方式效率更高的方式!

  36. wiskeyjohn2013 年 6 月 4 日下午 9:37 说道:

    楼主,这个怎么防止ip被封,我想采集kuaidi100.com的dhl,fedex,ems,ups等线路的快递跟踪,怎么预防被封ip,请教指导,我看了你说用tor,能否加QQ指导一下。诚心想和 亲亲请教技术上的问题,因为我们公司是深圳的fedex一级代理,希望能自动跟踪包裹.QQ:252341102

    • linux下tor可以做一个socks5代理,启动多个实例可以用多个端口做代理,tor的文档自己google。最近很忙,抽空写一个整套的tor自动化多IP代理,目前还在测试,很不稳定。

      • 博主tor自动化多IP代理弄出来了吗?最近正好需要这东西呢。找到救星了。^_^

        • 写了一个,需要建表和进程同步,还不稳定,失败处理什么的太复杂,不打算搞了,自己多开几个tor写逻辑轮询就行了。

          • 恩。然后。现在的问题是怎么多开实例。研究了一天了。直接/etc/init.d/tor start开一个没问题。网上找了个sh方式多开失败了。端口打开了。但是似乎没能联网。
            代码如下:

            #!/bin/bash

            # Original script from
            http://blog.databigbang.com/distributed-scraping-with-multiple-tor-circuits/

            base_socks_port=9050
            base_control_port=15000

            # Create data directory if it doesn’t exist
            if [ ! -d “data” ]; then
            mkdir “data”
            fi

            TOR_INSTANCES=”$1″

            if [ ! $TOR_INSTANCES ] || [ $TOR_INSTANCES -lt 1 ]; then
            echo “Please supply an instance count”
            echo “Example: ./multi-tor.sh 5”
            exit 1
            fi

            for i in $(seq $TOR_INSTANCES)
            do
            j=$((i+1))
            socks_port=$((base_socks_port+i))
            control_port=$((base_control_port+i))
            if [ ! -d “data/tor$i” ]; then
            echo “Creating directory data/tor$i”
            mkdir “data/tor$i”
            fi

            # Take into account that authentication for the control port is disabled. Must be used in secure and controlled environments
            echo “Running: tor –RunAsDaemon 1 –CookieAuthentication 0 –HashedControlPassword \”\” –ControlPort $control_port –PidFile tor$i.pid –SocksPort $socks_port –DataDirectory data/tor$i”

            tor –RunAsDaemon 1 –CookieAuthentication 0 –HashedControlPassword “” –ControlPort $control_port –PidFile tor$i.pid –SocksPort $socks_port –DataDirectory data/tor$i
            done

            博主能指点下么?

            • /usr/bin/tor -f /srv/tor/torrc –pidfile /srv/tor/10090/tor.pid –log “notice file /srv/tor/10090/tor.log” –runasdaemon 1 –datadirectory /srv/tor/10090/data –WarnUnsafeSocks 0 –SocksPort 10090 –SocksListenAddress 127.0.0.1 –ControlPort 10091 –HashedControlPassword 16:478A547917EEB05B60DDF0895AA0C2A06D1F5E55832E48F521E01AE2CB –user _tor

              用这个命令启动一个tor,/srv/tor/torrc这个配置文件为空即可(配置文件必须有),修改端口可以启动多个进程,多个进程tor的ip不同,具体命令行参数含义见官方文档,如何切换IP本博客搜索”tor切换IP”。有其他问题看官方文档或google自行解决。

  37. 匿名2013 年 5 月 7 日下午 1:49 说道:

    debug_print 提示错误

  38. 这个可以用post提交数据吗?2013 年 4 月 23 日下午 7:52 说道:

    如题,不知道如何设置post数据?

  39. 类很强大,但像豆瓣这样的网站稍微密集访问就会返回403,又不能在本机采集,咋办呢?

  40. haohailuo2013 年 4 月 23 日上午 12:26 说道:

    类非常好用,谢谢分享,不过在大数据量处理时,会遇到内存溢出现象,不知道各位有没有遇到,报如下错误,Fatal error: out of dynamic memory in yy_create_buffer()
    我在名两行下执行demo2的时候就已经报错了,楼主是否也在优化下,感觉有些地方的循环太多,有待优化下。谢谢

    • haohailuo2013 年 4 月 23 日上午 12:27 说道:

      命令行下执行

    • haohailuo2013 年 4 月 23 日上午 12:27 说道:

      另外,debug_print这个方法也不存在,能否提供下,谢谢。

    • haohailuo2013 年 4 月 23 日上午 12:33 说道:

      补充说明:我已经设置了内存大小为1G

    • 从没有遇到过这种错误,一次性添加15W个url内存占用300MB左右,执行demo2不可能内存溢出,除非php配置有问题。类中的每一个循环都是必要的,建议你到googlecode下载最新版本的类。
      类唯一需要优化的地方是curl线程的复用,也就是tcp连接的复用,现在性能,稳定性完全满足要求加上精力有限就先不修改了。
      估计你的代码可能有些问题,可以贴出来帮你测试一下。

      • haohailuo2013 年 4 月 23 日上午 11:37 说道:

        多谢你的回复,我是在CI框架中使用的,不知道是不是与框架本身有关,经常性的报如下错误
        A PHP Error was encountered

        Severity: Warning
        Message: curl_getinfo(): 83 is not a valid cURL handle resource
        Filename: libraries/CURL.php
        Line Number: 173

        Fatal error: Call to undefined function debug_print() in /data/www/app/libraries/CURL.php on line 178

        • debug_print()是对user_error()的封装,直接用查找替换就可以。

          你把curl先关的逻辑代码发到我邮箱,我看下什么问题。aresrr@126.com,包括sql,可能有非法的url,CURL不对url格式进行验证。

          • haohailuo2013 年 4 月 23 日上午 11:48 说道:

            好的,多谢

          • haohailuo2013 年 4 月 23 日下午 12:12 说道:

            已经给你发邮件了,请查收,麻烦了,多谢。
            admin:
            邮件内容和附件我先附到这里,有兴趣的读者可以看下
            http://blog.phpdr.net/wp-content/uploads/2012/11/snatch.zip

            • 通过测试,类没有问题。
              有几点情况必须注意,脚本必须在linux命令行下运行(cygwin没有测试),windows命令行肯定不行,windows下php 5.3.10 $this->curl->read($url)这一步就出问题。
              我的linux环境用的是centos 5.4 final,PHP 5.4.11 (cli) (built: Jan 16 2013 17:14:04) 。
              另外代码中显示状态的函数调用不对,$curl->status()应该在回调函数中调用,这样可以每一秒更新一次状态。修改后的回调函数如下:

              public function test2($res, $url,$curl) {
              	$lists = array();
              	if($res['info']['http_code']==200){
              		phpQuery::clear();
              		$html = phpQuery::newDocumentHTML($res['content']);
              		$list = $html['div.albumList ul li a.albumLink'];
              		if(!empty($list)){
              			foreach($list as $v){
              				$data = array();
              				$v = pq($v);
              				$data['albumName'] = trim($v->find('span.albumName')->text());
              				$data['url'] = trim($v->attr('href'));
              		
              				$lists[] = $data;
              			}
              		}
              	}
              	$curl->status();
              	phpQuery::unloadDocuments();
              	file_put_contents(ROOTPATH.'logs/'.basename($url), print_r($lists, true));
              }

              主程序37行改成了这样:$callback = array(array($this->test, ‘test2’), array($info[‘url’],&$this->curl));
              另外一点一定注意!如果使用phpQuery必须在回调函数中手动调用phpQuery::unloadDocuments();释放,否则phpQuery处理的文档全部都在内存中!!!
              我的虚拟机只分配了128MB内存,跑完你的脚本速度非常快,内存占用完全可以忽略,结果如下:
              ———————————-
              100.00% 100/100(0) 20/s 535.14KB/s 2.61MB ETA 0s
              PHP Fatal error: Call to undefined method CI_Profiler::slowsql_log() in /mnt/hgfs/www_root/test/snatch/system/core/Output.php on line 444

              Fatal error: Call to undefined method CI_Profiler::slowsql_log() in /mnt/hgfs/www_root/test/snatch/system/core/Output.php on line 444
              [root@vm-centos5 www]#
              ————————————
              必定是你的配置有问题。

            • 如果感觉类有问题,建议把逻辑从框架拿出来用最原始的php程序测试一下,因为这类问题基本都是和类本身无关的问题导致。

  41. 问一个问题2013 年 4 月 18 日下午 5:15 说道:

    那啥,我首先用addTask添加采集url
    $href=“”;
    $url=array($href);
    $callback=array(‘demo2_cb2’,array($asin,$href,$reviewpagenum,$r_tb_name));
    $curl->add($url,$callback);
    ————-上面这个是addTask中执行————-
    然后在demo2_cb2中,根据采集内容返回的结果,如果有解析出来的url需要抓取。

    我再用$curl->add($url,$callback);添加解析出来的url,会怎么样?

    • 这就是教程中第3条提到的。
      这么做是没有任何问题的,$curl->add()添加一个任务到$curl的内部数组,为了保持一个固定的并发数$curl始终从这个内部数组中取任务。
      仔细看一下上面“3.链式抓取”

  42. 求助2013 年 4 月 5 日上午 11:01 说道:

    不知道怎么解决了,求助博主。

    我有个大库,需要抓取的种子网址有10万左右,这10万个种子网址。
    假设格式为 a.htm
    需要去访问,然后每个种子网址根据返回的内容来确定是否要继续抓取二级网址,即
    a.html?page=1,a.html?page=2
    这样。。我写了代码,但是发现抓取的速度似乎并不能提升。
    博主能给点思路吗?

    • 求助2013 年 4 月 5 日上午 11:07 说道:

      补上其他情况:
      当然a.htm抓取完后,我回到数据库更新a.htm的状态为已更新。

      但是在这种情况下,我用curl->task来添加每次添加10个种子词到队列中,发现会重复添加种子词。

      即,第一次添加了a.htm,b.html几个种子地址,本来他们需要抓取a.html?page=1等页面的,但是还没抓完,那个addtask又再次执行,又把a.htm,b.html加入了队列,这就造成了无限死循环。貌似。。。

      • 有可能,$curl->task在并发数不够$curl->limit的时候被调用,a.htm,b.html抓取进行时a.htm,b.html数据库状态不会被更新,一旦并发不够就会重复添加造成浪费(CURL类本身没有url排重功能)。
        把你的代码贴出来,我可以帮你看下有什么问题。

        • 求助2013 年 4 月 7 日下午 4:29 说道:

          针对那个url重复添加的问题,我自己在task调用的函数中,搞了个array,把添加过的url存起来,然后下次自动添加url时先在这个数据进行判断。

          • 有时候url个数有几百万,用array占内存较多,我是这么搞的,设置一个
            static $lastId;每次取数据这么取:select id,url from table where id>$lastId order by id asc limit 100;然后设置$lastId为结果中最后一条记录的id。

    • 抓取速度由网络情况和被抓取服务器共同决定,类本身性能是最优的,可以尝试$curl->limit调大一些。可以先检查一下程序逻辑是否有问题。刚才站内的CURL更新到了最新版本,解决了一个特殊情况下的性能问题。

      • 求助2013 年 4 月 7 日下午 4:27 说道:

        $curl->task

        这个启动之后,如果任务已经全部添加完成。怎么关闭这个自动添加任务到队列?

        • 有两种方法:1.在任何代码可以执行到的地方$curl->task=null即可,建议在$curl->task指向的回调函数中操作。
          2.$curl->task回调中实际通过$curl->add()添加任务,不执行这个方法就可以了,也就是$curl->task空跑就行了,这样不优美,不建议这么干。

      • 求助2013 年 4 月 7 日下午 4:55 说道:

        想问一下,比如我建立了$curl,然后,调用了$curl->task=’addUrl’

        在这个 addUrl中,再建立$curl_1,然后通过这个$curl_1来处理任务,这样效率会怎么样?下面是代码

        $curl=new CURL();
        $curl->task=’addNewFetchItem’;
        $curl->go();

        //添加新的url
        function addNewFetchItem()
        {
        global $curl_2,$curl, $sql_connect,$item_tablename,$cid,$r_table_count,$has_success,$has_fetch_array;
        $limit=1;
        $sql = “select url,asin from `$item_tablename` where is_fetch = 0 order by id limit $limit;”;
        $result = mysql_query($sql, $sql_connect);//执行查询
        while($row = mysql_fetch_array($result))
        {
        $href=”xxxxxxx”;
        //判断网址是否已加入队列,如果已加入,则不添加,跳过
        if(!in_array($asin,$has_fetch_array))
        {
        $r_tb_name=getRiviewTable($cid,$r_table_count);
        getFirstReviewPage($asin,$tag,$href,$r_tb_name);
        }
        else
        {
        echo “url is feting ,do no add again”;
        echo “”;
        }
        }
        }

        function getFirstReviewPage($asin,$tag,$href,$r_tb_name)
        {
        global $curl, $sql_connect,$item_tablename,$cid,$has_fetch_array;

        $has_fetch_array[]=$asin;
        $result=$curl->read($href);
        $info=$result[‘content’];
        if (strpos($info,”“))
        {
        insertReivews($info,$asin,$r_tb_name);//如果有评论,则进行处理
        $reviewpagenum= getReviewPagenum($info);//得到评论页数
        if($reviewpagenum>1)
        {
        $curl_2= new CURL();
        for($i=2;$iadd($url,$callback);
        }
        echo “”;
        $curl_2->go();
        }
        else
        {
        }
        }
        else
        {
        }
        }

        • 这代码逻辑比较乱,具体逻辑没仔细看,但是getFirstReviewPage()中$curl_2= new CURL();肯定是有问题的,性能如何没有测试,但肯定不是最优,CURL类本身可以复用,在一个PHP进程中理论上一个CURL对象完全可以做所有的事情。

  43. 你好,请教一个问题~
    PHP 中的curl是线程连接吗? 也就是一个curl连接会一直占用一个线程,只到处理结束释放!

  44. curl error 56, Recv failure: Connection was reset

    这是什么错误?

  45. 路人甲2013 年 1 月 25 日上午 11:25 说道:

    最讨厌的就是 一些网站不允许采集…封IP..

    • 这个用tor就可以解决,同时1000个IP采集,抽空专门写个tor的博文,当然国内服务器的话tor也不一定能解决。

      • juan85102013 年 4 月 9 日上午 1:00 说道:

        怎么用tor同时多个IP采集啊,开了好几个tor客户端机器都卡死了

        • 只需要启动多个tor客户端监听不同端口就可以了,然后用PHP写控制逻辑。
          一个作为客户端最小配置的tor进程大约占用20MB~30MB空间。
          不重启客户端用PHP换IP,http://blog.phpdr.net/tor-change-identity.html

          我是这么干的:
          [root@ares tor]# ps aux|grep tor
          _tor 31431 20.8 6.7 21876 17200 ? S 20:34 0:01 /usr/bin/tor -f /srv/tor/torrc –pidfile /srv/tor/10090/tor.pid –log notice file /srv/tor/10090/tor.log –runasdaemon 1 –datadirectory /srv/tor/10090/data –WarnUnsafeSocks 0 –SocksPort 10090 –SocksListenAddress 127.0.0.1 –ControlPort 10091 –HashedControlPassword 16:478A547917EEB05B60DDF0895AA0C2A06D1F5E55832E48F521E01AE2CB –user _tor

    • juan85102013 年 4 月 9 日上午 1:01 说道:

      呵呵 你采集他 当然要封你了

  46. 不错的类啊,我原来写了简单的类,前段用了rolling curl .但是并发大的时候,很多页面下载不完整。
    现在想换成楼主的类,可以向楼主请教下实际操作吗,我的流程有点不同,试了下不成功。

  47. 路人2012 年 12 月 12 日下午 1:19 说道:

    很强大的东西

  48. 童童2012 年 11 月 22 日下午 8:59 说道:

    博主你好 关注你这个类 好久了
    自己也能简单应用 但是按你的介绍来看 应用的很不完善
    球博主写个demo 有可能的话发个邮件 谢谢

  49. zhouzhou2012 年 11 月 15 日上午 11:39 说道:

    博主,可以把类发过来看看嘛 ?

  50. 希望博主能发整个实例源码到我qq邮箱95864668,感激无私的分享,谢谢!

  51. 麻烦也发我一份 我下载不了那个扩展

  52. 蒋武章2012 年 7 月 31 日上午 10:39 说道:

    你这个类能发给我吗?google一直被大陆屏蔽

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值