加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP爬虫:百万级别知乎用户数据爬取与说明

发布时间:2016-10-29 12:13:52 所属栏目:PHP教程 来源:Hector
导读:副标题#e# 这次抓取了110万的用户数据,数据分析结果如下: 开发前的准备 安装Linux系统(Ubuntu14.04),在VMWare虚拟机下安装一个Ubuntu; 安装PHP5.6或以上版本; 安装MySQL5.5或以上版本; 安装curl、pcntl扩展。 使用PHP的curl扩展抓取页面数据 PHP的c

实现了多进程编程之后,就想着多开几条进程不断地抓取用户的数据,后来开了8调进程跑了一个晚上后发现只能拿到20W的数据,没有多大的提升。于是 查阅资料发现,根据系统优化的CPU性能调优,程序的最大进程数不能随便给的,要根据CPU的核数和来给,最大进程数最好是cpu核数的2倍。因此需要查 看cpu的信息来看看cpu的核数。在Linux下查看cpu的信息的命令:

  1. cat /proc/cpuinfo 

结果如下:

PHP爬虫:百万级别知乎用户数据爬取与说明

其中,model name表示cpu类型信息,cpu cores表示cpu核数。这里的核数是1,因为是在虚拟机下运行,分配到的cpu核数比较少,因此只能开2条进程。最终的结果是,用了一个周末就抓取了110万的用户数据。

多进程编程中Redis和MySQL连接问题

在多进程条件下,程序运行了一段时间后,发现数据不能插入到数据库,会报mysql too many connections的错误,redis也是如此。

下面这段代码会执行失败:

  1. <php 
  2.      for ($i = 0; $i < 10; $i++) { 
  3.           $pid = pcntl_fork(); 
  4.           if ($pid == -1) { 
  5.                echo "Could not fork!n"; 
  6.                exit(1); 
  7.           } 
  8.           if (!$pid) { 
  9.                $redis = PRedis::getInstance(); 
  10.                // do something     
  11.                exit; 
  12.           } 
  13.      } 

根本原因是在各个子进程创建时,就已经继承了父进程一份完全一样的拷贝。对象可以拷贝,但是已创建的连接不能被拷贝成多个,由此产生的结果,就是各个进程都使用同一个redis连接,各干各的事,最终产生莫名其妙的冲突。

解决方法: >程序不能完全保证在fork进程之前,父进程不会创建redis连接实例。因此,要解决这个问题只能靠子进程本身了。试想一下,如果在子进程中获 取的实例只与当前进程相关,那么这个问题就不存在了。于是解决方案就是稍微改造一下redis类实例化的静态方式,与当前进程ID绑定起来。

改造后的代码如下:

  1. <php 
  2.      public static function getInstance() { 
  3.           static $instances = array(); 
  4.           $key = getmypid();//获取当前进程ID 
  5.           if ($empty($instances[$key])) { 
  6.                $inctances[$key] = new self(); 
  7.           } 
  8.  
  9.           return $instances[$key]; 
  10.      } 

PHP统计脚本执行时间

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读