一个PHP实现的轻量级简单爬虫

Posted qq^^614136809

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个PHP实现的轻量级简单爬虫相关的知识,希望对你有一定的参考价值。

最近需要收集资料,在浏览器上用另存为的方式实在是很麻烦,而且不利于存储和检索。所以自己写了一个小爬虫,在网上爬东西,迄今为止,已经爬了近百 万张网页。现在正在想办法着手处理这些数据。

爬虫的结构:
爬虫的原理其实很简单,就是分析下载的页面,找出其中的连接,然后再下载这些链接,再分析再下载,周而复始。在数据存储方面,数据库是首选,便于检索,而 开发语言,只要支持正则表达式就可以了,数据库我选择了mysql,所以,开发脚本我选择了php。它支持perl兼容正则表达式,连接mysql很方 便,支持http下载,而且windows系统和linux系统都可以部署。

正则表达式:
正则表达式是处理文字的基本工具,要取出html中的链接和图片,使用的正则表达式如下。
代码如下:

 "#<a[^>]+href=(['\\"])(.+)\\\\1#isU"   处理链接
    "#<img[^>]+src=(['\\"])(.+)\\\\1#isU" 处理图片

其他问题:
写爬虫还需要注意的一个问题是,对于已经下载过的url,不能重复进行下载,而有些网页的链接会形成环路,所以需要处理这个问题,我的处理方法是计算已经 处理的url的MD5 值,并存入数据库,这样就可以检验是否已经下载过。当然还有更好的算法,有兴趣的话,可以在网上找一下。

相关协议:
爬虫也有自己的协议,有个robots.txt文件定义了那些是网站允许遍历的,但是由于我的时间有限,没有实现这个功能。

其他说明:
php支持类编程,我写的爬虫主要的类.
1.url处理web_site_info,主要用处理url,分析域名等。
2.数据库操作mysql_insert.php,处理和数据库相关的操作。
3.历史记录处理,记录已经处理的url。
4.爬虫类。

存在的问题和不足

这个爬虫在小数据量的情况下,运行良好,但是在大数据量的情况下,历史记录处理类的效率就不是很高,通过在数据库结构中,对相关字段进行了索引,速度有了 提高,但是需要不断得读取数据,可能和php本身的array实现有关系,如果一次加载10万条历史记录,速度非常慢。
不支持多线程,每次只能处理一个url。
php运行本身有内存使用量限制
使用的时候,先在mysql中创建net_spider数据库,然后用db.sql创建相关表。再在config.php中设置mysql 的用户名口令。
最后
代码如下:

php -f spider.php 深度(数值) url

就可以开始工作。如
代码如下:
php -f spider.php 20

现在感觉下来,其实做个爬虫没那么复杂,难的是数据的存储和检索。我现在的数据库,最大一个数据表已经15G,正在想办处理这些数据,mysql进 行查询已经感觉有点力不从心了。这点上还真佩服google

<?php
#加载页面
function curl_get($url)
    $ch=curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch,CURLOPT_HEADER,1);
    $result=curl_exec($ch);
    $code=curl_getinfo($ch,CURLINFO_HTTP_CODE);
    if($code!='404' && $result)
     return $result;
    
    curl_close($ch);

#获取页面url链接
function get_page_urls($spider_page_result,$base_url)
  $get_url_result=preg_match_all("/<[a|A].*?href=[\\'\\"]0,1([^>\\'\\"\\]*).*?>/",$spider_page_result,$out);
  if($get_url_result)
    return $out[1];
  else
    return;
  

#相对路径转绝对路径
function xdtojd($base_url,$url_list)
 if(is_array($url_list))
  foreach($url_list as $url_item)
    if(preg_match("/^(http:\\/\\/|https:\\/\\/|javascript:)/",$url_item))
      $result_url_list[]=$url_item;
    else 
     if(preg_match("/^\\//",$url_item))
      $real_url = $base_url.$url_item;
     else
      $real_url = $base_url."/".$url_item;
     
     #$real_url = 'http://www.sumpay.cn/'.$url_item; 
     $result_url_list[] = $real_url; 
    
  
   return $result_url_list;
 else
   return;
 

#删除其他站点url
function other_site_url_del($jd_url_list,$url_base)
 if(is_array($jd_url_list))
  foreach($jd_url_list as $all_url)
    echo $all_url;
    if(strpos($all_url,$url_base)===0)
     $all_url_list[]=$all_url;
      
  
  return $all_url_list;
 else
  return;
 

#删除相同URL
function url_same_del($array_url)
   if(is_array($array_url))
     $insert_url=array();
     $pizza=file_get_contents("/tmp/url.txt");
     if($pizza)
        $pizza=explode("\\r\\n",$pizza);
        foreach($array_url as $array_value_url)
         if(!in_array($array_value_url,$pizza))
          $insert_url[]=$array_value_url; 
         
        
        if($insert_url)
           foreach($insert_url as $key => $insert_url_value)
             #这里只做了参数相同去重处理
             $update_insert_url=preg_replace('/=[^&]*/','=leesec',$insert_url_value);
             foreach($pizza as $pizza_value)
                $update_pizza_value=preg_replace('/=[^&]*/','=leesec',$pizza_value);
                if($update_insert_url==$update_pizza_value)
                   unset($insert_url[$key]);
                   continue;
                
             
           
             
     else
        $insert_url=array();
        $insert_new_url=array();
        $insert_url=$array_url;
        foreach($insert_url as $insert_url_value)
         $update_insert_url=preg_replace('/=[^&]*/','=leesec',$insert_url_value);
         $insert_new_url[]=$update_insert_url;  
        
        $insert_new_url=array_unique($insert_new_url);
        foreach($insert_new_url as $key => $insert_new_url_val)
          $insert_url_bf[]=$insert_url[$key];
         
        $insert_url=$insert_url_bf;
     
     return $insert_url;
   else
    return; 
   

  
$current_url=$argv[1];
$fp_puts = fopen("/tmp/url.txt","ab");//记录url列表 
$fp_gets = fopen("/tmp/url.txt","r");//保存url列表 
$url_base_url=parse_url($current_url);
if($url_base_url['scheme']=="")
  $url_base="http://".$url_base_url['host'];
else
  $url_base=$url_base_url['scheme']."://".$url_base_url['host'];

do
  $spider_page_result=curl_get($current_url);
  #var_dump($spider_page_result);
  $url_list=get_page_urls($spider_page_result,$url_base);
  #var_dump($url_list);
  if(!$url_list)
   continue;
  
  $jd_url_list=xdtojd($url_base,$url_list);
  #var_dump($jd_url_list);
  $result_url_arr=other_site_url_del($jd_url_list,$url_base);
  var_dump($result_url_arr);
  $result_url_arr=url_same_del($result_url_arr); 
  #var_dump($result_url_arr); 
  if(is_array($result_url_arr)) 
    $result_url_arr=array_unique($result_url_arr);
       foreach($result_url_arr as $new_url)  
         fputs($fp_puts,$new_url."\\r\\n"); 
       
  
while ($current_url = fgets($fp_gets,1024));//不断获得url 
preg_match_all("/<a[^>]+href=[\\"']([^\\"']+)[\\"'][^>]+>/",$spider_page_result,$out);
# echo a href
#var_dump($out[1]);
?>

PHP简单爬虫 基于QueryList采集库 和 ezsql数据库操作类

QueryList是一个基于phpQuery的PHP通用列表采集类,得益于phpQuery,让使用QueryList几乎没有任何学习成本,只要会CSS3选择器就可以轻松使用QueryList了,它让PHP做采集像jQuery选择元素一样简单。

官方地址:https://querylist.cc/

ezSQL PHP 是用php开发的一套轻量级的数据库类,这个数据库类占用服务器资源小,代码简洁,同时支持多种数据库的使用,安全性高。

下载地址:sjolzy.cn/php/ezSQL/bak/ez_sql_2.05.zip

搭建一个简单的框架目录结构:

db里放得是ezsql类相关文件

lib里放得是querylist相关文件

index.php 为主程序

 

以采集猫眼电影TOP100为例代码如下:

index.php

<?php
require \'lib/phpQuery.php\';
require \'lib/QueryList.php\';
require "db/shared/ez_sql_core.php";  
require "db/mysql/ez_sql_mysql.php";  
use QL\\QueryList;

//抓取猫眼电影TOP100榜单内容 
$db = new ezSQL_mysql(\'root\', \'root\', \'spider\', \'localhost\');  
$offset=0;
for($i=0;$i<10;$i++){

    $gurl="http://maoyan.com/board/4?offset=".$offset;
    // echo $gurl.PHP_EOL;
    $rules = array(
        //采集id为one这个元素里面的纯文本内容
        \'url\' => array(\'.movie-item-info .name a\',\'href\',\'\',function($content){
            return \'http://maoyan.com\'.$content;
        }),//链接
    );
    $data = QueryList::Query($gurl,$rules)->data;
    // print_r($data);
    foreach ($data as $key => $val) {
        getContents($db,$val[\'url\']);
    }
    $offset+=10;
    echo "".($i+1)."页完成".PHP_EOL;
}


//取电影内容 传入内容页的链接地址 
function getContents($db,$url){
    $rules = array(
        //采集id为one这个元素里面的纯文本内容
        \'name\' => array(\'.movie-brief-container .name\',\'text\'),//电影名
        \'ename\' => array(\'.movie-brief-container .ename\',\'text\',\'\',function($content){
            return str_replace("\'","\\\'",$content);
        }),//英文名 
        \'type\' => array(\'.movie-brief-container ul li:eq(0)\',\'text\'),//电影类型
        \'area\' => array(\'.movie-brief-container ul li:eq(1)\',\'text\',\'\',function($content){
            return trim(explode("/", $content)[0]);
        }),//产地
        \'timelen\' => array(\'.movie-brief-container ul li:eq(1)\',\'text\',\'\',function($content){
            return trim(explode("/", $content)[1]);
        }),//片长
     
        \'addtime\' => array(\'.movie-brief-container ul li:eq(2)\',\'text\',\'\',function($content){
            return substr($content,0,10);
        }),//上映时间
        \'addarea\' => array(\'.movie-brief-container ul li:eq(2)\',\'text\',\'\',function($content){
            return substr($content,10);
        }),//上映地点

    );

    $data = QueryList::Query($url,$rules)->data;

    print_r($data);


    $name=$data[0]["name"];
    $ename=$data[0]["ename"];
    $area=$data[0]["area"];
    $type=$data[0]["type"];
    $timelen=$data[0]["timelen"];
    $addtime=$data[0]["addtime"];
    $addarea=$data[0]["addarea"];



    $db->query("INSERT INTO maoyan (name, ename,type,area,timelen,addtime,addarea) 
        VALUES (\'$name\',\'$ename\',\'$area\',\'$type\',\'$timelen\',\'$addtime\',\'$addarea\')");
}

 

 采集的结果:

 项目下载:https://files.cnblogs.com/files/wordblog/spider.rar

以上是关于一个PHP实现的轻量级简单爬虫的主要内容,如果未能解决你的问题,请参考以下文章

Python 开发轻量级爬虫03

Python 开发轻量级爬虫01

十分钟就能快速上手的PHP爬虫框架

PHP 中有关 Web 爬虫的错误

PHP实现爬虫的一种简单方案

PHP爬虫技术知识点总结