(2)php爬虫---提取优酷动漫的外链与介绍

时间:2022-06-04 05:45:15

  因为最近比较忙,所以距离第一篇的php爬虫已经相隔了比较远的时间了。最近终于解放了,时间也比较充足,而且环境上也不错,有稳定的网络可以使用,所以现在就把之前的坑再填一点吧。

  在第一篇的时候写得比较随意,所以看起来会很乱。所以之后我就重构了代码,将所有的代码都进行了封装使用,这样子就不会太过于乱,也增加了代码重用的可能性了。

首先我们定义一些类变量,用来进行数据保存。

 public  $allUrl,//所有资源的url
$childUrl,//同一部资源的播放页面url
$data;//所有资源信息汇集的数组
private $_ch,//curl的存储变量
$myRegex;//正则规则

然后这个类的话,最重要的一部分就是curl的使用,所以这里面可以直接在初始化函数里面创建一个curl对象,而且这里面的话会涉及到非常多的连接,所以这个变量要到了程序结束之后,才被释放。

//构造函数
public function __construct(){
$this->_ch = curl_init();
// 设置URL和相应的选项
curl_setopt($this->_ch,CURLOPT_HEADER,0);//如果你想把一个头包含在输出中,设置这个选项为一个非零值。
curl_setopt($this->_ch,CURLOPT_RETURNTRANSFER,true);//将数据以字符串形式返回,而不是显示出来
}

//析构函数
function __destruct()
{
// TODO: Implement __destruct() method.
curl_close($this->_ch);
}
这里面还定义了一个去重函数封装在了类里面,因为我的操作都是写在类里面的,所以直接封装起来,使用起来会方便使用。这个函数主要是将二维转为一维数组再使用内置函数array_unique来进行去重,之后再使用explode来将一维数组转为二维数组。

//去重函数
function array_unique_my($arr){
//echo '<br/>进入去重函数处理<br/>';
foreach($arr as $v){
$v = join(',',$v);//降维,变为一维数组
$temp[] = $v;
}
$tmp = array_unique($temp);
unset($temp);
foreach($tmp as $v){
$v = explode(',',$v);//升维,变为二维数组
$temp[] = $v;
}
return $temp;
}

还有一堆基本的函数如下:

传一个正则数组进来:

//初始化正则表达式数组
public function initRegex($arr){
$this->myRegex = $arr;
}
设置一个爬取的页面然后返回一个html文件数据

//设置爬取的页面url
public function setTargetUrl($url){

curl_setopt($this->_ch,CURLOPT_URL,$url);
//var_dump("进入setTargetUrl函数");
$html = curl_exec($this->_ch);
return $html;
}
正则匹配我们所需要的内容函数

这里面记得要处理换行,回车,制表等符号。

//设置正则表达式
public function userRegex($rex,$str){
if(is_array($str)){
$str = serialize($str);
}
//预处理换行,回车,制表
$str = preg_replace("/[\t\n\r]+/","",$str);
preg_match_all($rex,$str,$aUrl,PREG_SET_ORDER);

// echo '正则匹配结果如下:<br/>';
// print_r($aUrl);
// echo '<br/>';
return $aUrl;
}

封装php原生的文件写入和文件读取的函数:

//文件写入调用
public function writeFile($tarFile,$content){
if(!is_file($tarFile)) {
echo "文件".$tarFile."写入成功!".'<br/>';
file_put_contents($tarFile,$content);
}
}
//文件读入调用
public function readFile($tarFile){
$file = file_get_contents($tarFile);
return $file;
}

真正重要的部分来了,这里面我分三步走将动漫的数据全部提取出来。所以这里分为三个函数:step_1,step_2,step_3这三个函数就进行元素的处理。在这里面还有一个main.php的文件,这个文件的话可以用来使用实体化类。

<?php
/**
* Created by PhpStorm.
* User: DMF
* Date: 2017/7/8
* Time: 20:03
*/

require_once './core/common.php';
require_once './core/basic.php';

use core\basic\basic;

//爬取的分类页面的链接集合
//全部动漫
$allLink = Array('http://list.youku.com/category/show/c_100_s_1_d_2.html?spm=a2hcm.20010061.nav-second.5~1~3!7~A');
//不设置爬取的最大时间
set_time_limit(0);

//爬虫基础对象
$crawler = new basic();
//页面提取的html代码保存变量
$html;



//正则公式保存的数组
$myRegex= array(
//key => 0
//爬取优酷的全部动漫中的图片div中的所有信息
'#<div class="p-thumb">(.*?)</div>#',
//key => 1
//获取$regex[0]的div公式里面的a标签的跳转url和标题
'#<a href="(.*?)" title="(.*?)" [^>]*></a>#',
//key => 2
//获取$regex[0]的div公式里面的图片url
'#<img class="quic" [^>]* src="(.*?)" .*?>#',
//key => 3
//根据$regex[1]中提取到的url找到当前的动漫页面信息
//然后提取到当前的动漫的其它集数的标题和url地址
'#<li class="item" .*? title="(.*?)" seq=".*?"><a class="A" href="(.*?)" .*? #',
//key => 4
//找到当前页面上优酷提供的外链
'#<input type="text" class="form_input form_input_s" id=".*?" value="(.*?)" .*?#'
);

$crawler->step_1(array('http://list.youku.com/category/show/c_100_s_1_d_1_p_'
,'.html?spm=a2h1n.8251845.0.0'));

$crawler->initRegex($myRegex);

//$crawler->step_2(1,30);



$crawler->step_3();

在后面都会使用到上面的正则传入,所以读到后面的代码如果是不懂变量的值的话,可以看一个上面的main.php里面的值就一清二楚了。

第一步我们要提取我们需要的动漫页面上面的数据,例如:

(2)php爬虫---提取优酷动漫的外链与介绍(2)php爬虫---提取优酷动漫的外链与介绍

(2)php爬虫---提取优酷动漫的外链与介绍

从上面的图片我们可以看出来,它们都是含有一个共同的c_100_s_1_d_2_p_的前缀的,这里面忽略它的参数,就是?后面的。因为这个不会影响我们显示整个页面出来,所以这里面我就找到了它的规律,然后再看一下一共有多少页,那么代码就是如下了。

//爬取含有全部动漫信息的文件
public function step_1($arr,$index=1){
//$arr用来保存url字符串的数组,$index是循环的开始下标
for($i=$index;$i<=30;++$i){
$url = $arr[0].$i.$arr[1];
$html = $this->setTargetUrl($url);
$this->writeFile('./html/temp/'.$i.'.html',$html);
var_dump($i.'文件爬取完成!');
}
}

这样子就可以将所有的数据都保存下来了。这里面我都是采用直接采集数据为html文件后再处理,因为我有时候在敲代码的时候没法保证百分百的正确,所以如果不断的重复爬取页面是有可能被封的。

之后就是根据上面爬取到的动漫页面上的图标来寻找页面的a标签的href来跳转到播放页面。

(2)php爬虫---提取优酷动漫的外链与介绍

在这里面的话,我发现在这里提取img不太方便,因为这里面的数据的url也是不必要的,所以这里面就先不提取着img的url,因为到时候我们还要提取简介的信息,所以这里面可以顺便一起做,存储在一个数组上也方便。

所以代码如下:

//爬取动漫的页面介绍信息和跳转url
public function step_2($start,$end,$road='/html/temp/'){
var_dump('进入step_2函数');
echo '<br/>';
$road = dirname(dirname(__FILE__)).$road;
//根据要爬取的页面循环爬取
for($i=$start;$i<=$end;++$i){
// 提取当前要爬的动漫所有url
$html = $this->readFile($road.$i.'.html');

// 爬取所有的动漫页面信息
$cartonUrl = $this->userRegex($this->myRegex[0],$html);
// 根据动漫中的所有信息提取a标签和img的url
$a = $this->userRegex($this->myRegex[1],$cartonUrl);
//$img = $this->userRegex($this->myRegex[2],$cartonUrl);

$a = $this->array_unique_my($a);
//$img = $this->array_unique_my($img);


//newA重新组装的数据
foreach($a as $k => $v){
$newA[$i][$k][] = 'http:'.$v[1];
$newA[$i][$k][] = $v[2];
//$newA[$i][$k][] = $img[$k][1];
//var_dump($img[$k][1]);
}
//var_dump($newA);
//var_dump($newA);
//newA的格式
// 1动漫页面url
// 2动漫标题
}
file_put_contents('./html/json/step_2.json',serialize($newA));
}

完成上面的操作后,我们就有一堆的每个代码的播放页面代码了。

(2)php爬虫---提取优酷动漫的外链与介绍

所以这个页面的信息量是很丰富的,这里面有一个节目简介的a标签,右边有一排的节目信息的url,所以这里我可以获取到其它的分集的url,然后就可以找到页面上的分享外链了。但是在这里的话,右面的集我还是比较弱,无法对大于100集的数据进行提取,因为大于100级之后就会出现ajax的方式来重新获取集的信息,这里面我知道了url,但是就是不清楚如何在页面自动获取到它,如果有大神看到我的问题的话,希望可以给小弟一些提示,谢谢。


//获取每部动漫信息,提取每个动漫url,和外链
public function step_3(){
$msg = unserialize(file_get_contents('./html/json/step_2.json'));
// foreach($msg as $k =>$v){
// echo '<br/>';
// foreach($v as $kk => $vv){
// echo '<br/>';
// var_dump($vv);
// echo '<br/>';
// }
// echo '<br/>';
// }
//爬取数据放进文件里面
// $i = 1;
// foreach($msg as $k =>$v){
//
// foreach($v as $kk => $vv) {
//
// $this->writeFile('./html/temp/step_3/'.$i.'.html',$this->setTargetUrl($vv[0]));
// $i++;
// }
// }
//获取简介url start
// for($i=1;$i<=59;++$i){
// $html = $this->readFile('./html/temp/step_3/'.$i.'.html');
// $r = $this->userRegex('#<a class="desc-link" href="(.*?)" target="_blank">节目简介</a>#',$html);
// $res[] = 'http:'.$r[0][1];
// }
// $this->writeFile('./html/temp/step_3/s1.json',serialize($res));
// foreach($res as $k=>$v){
// var_dump($v);
// echo '<br/>';
// }
//获取简介url end
//提取简介上的有用信息 start
// $res = $this->readFile('./html/temp/step_3/s1.json');
// $res = unserialize($res);
// for($i=0;$i<59;++$i) {
// $html = $this->setTargetUrl($res[$i]);
// $this->writeFile('./html/temp/step_3/abstract/'.$i.'.html',$html);
// }

// for($i=0;$i<59;++$i){
// $html = $this->readFile('./html/temp/step_3/abstract/'.$i.'.html');
// $r = $this->userRegex('#<span class="text">简介:(.*?)</span>#',$html);
// $abstract[$i][] = $r[0][1];
// $r = $this->userRegex('#<i class="bg"></i><img src="(.*?)" alt="(.*?)"[^>]+?#',$html);
// $abstract[$i][] = $r[0][1];
// $abstract[$i][] = $r[0][2];
// echo '<br/>';
// var_dump($r[0][1]);
// echo '<br/>';
// var_dump($r[0][2]);
// echo '<br/>';
// }
// foreach($abstract as $k=> $v){
// foreach($v as $kk=>$vv){
// echo '<br/>';
// var_dump($vv);
// echo '<br/>';
// }
// }
// $this->writeFile('./html/temp/step_3/s2.json',serialize($abstract));
//$this->writeFile('./html/temp/step_3/s2.json',serialize($abstract));

//提取简介上的有用信息 end

//提取每个播放页面上的其它集数 start
// for($i=0;$i<59;++$i){
// $html = file_get_contents('./html/temp/step_3/'.($i+1).'.html');
//
// $r = $this->userRegex($this->myRegex[3],$html);
// //var_dump($r);
// echo $i.'<br/><br/>';
// foreach($r as $k=>$v) {
// echo '<br/>';
// echo $v[1]." ".'http:'.$v[2];
// $res[$i][] = Array($v[1],'http:'.$v[2]);
// echo '<br/>';
// }
// echo '<br/><br/>';
// //$res[] = Array($r[0][1],$r[0][2]);
// }
// $this->writeFile('./html/temp/step_3/s3.json',serialize($res));
// $i = 1;
// foreach($res as $k=>$v){
// echo $i++.'<br/>';
// var_dump($v);
// echo '<br/>';
// }
//提取每个播放页面上的其它集数 end


$arr = unserialize($this->readFile('./html/temp/step_3/s3.json'));
//提取每个播放页面上的外链 start
//因为优酷上有防爬虫处理,所以数据太多请求过多会导致被封,所以要将网页爬下来,而不能在线处理数据
// foreach($arr as $k => $v) {
//
// foreach ($v as $kk => $vv) {
// if($k>=34){
// $html = $this->setTargetUrl($vv[1]);
// $this->writeFile('./html/temp/step_3/66/'.$k.'_'.$kk.'.html',$html);
// }
// }
// }

foreach($arr as $k => $v){

echo '<br/>';
foreach($v as $kk => $vv){
echo '<br/>';
//var_dump($vv);
$html = $this->readFile('./html/temp/step_3/66/'.$k.'_'.$kk.'.html');
//echo $vv[1];
$r = $this->userRegex('#<input type="text" class="form_input form_input_s" id=".*?" value="([^<>]+?)" [^<>]+?#',$html);
$arr[$k][$kk][1] = $r[0][1];
//echo '<br/>';
}
echo '<br/>';
}
foreach($arr as $k => $v){
echo '<br/>';
var_dump($arr);
echo '<br/>';
}

$this->writeFile('./html/temp/step_3/s4.json',serialize($arr));


//echo $arr[0][0][1];
//$html = $this->setTargetUrl($arr[0][0][1]);
//$this->writeFile('./html/temp/step_3/abstract/60.html',$html);

// $html = $this->readFile('./html/temp/step_3/abstract/60.html');
// $r = $this->userRegex('#<input type="text" class="form_input form_input_s" id=".*?" value="([^<>]+?)" [^<>]+?#',$html);
// echo $r[0][1];
// echo '<vedio src='.$r[0][1].'></vedio>';

//提取每个播放页面上的外链 end


}
上面的代码我都是注释掉的,因为我是一步步的尝试出来的,你们可以直接不注释就可以了。

这里面还存在一个问题,那就是使用浏览器进行的话,有可能会直接奔溃掉,所以我这里使用的是控制台来进行代码的运行,在当前文件目录php main.php或者是php -f "main.php"就可以在命令行玩了,结果如下:

(2)php爬虫---提取优酷动漫的外链与介绍
(2)php爬虫---提取优酷动漫的外链与介绍

单个动漫数据汇总结果如上

经过这几个步骤之后,我们就将动漫的信息都爬出来了,这里面的信息我是存在了s1-s4这几个json文件上的,所以下一个文章就是如何将数据导入数据库

感谢看完!