[PHP采集]基于querylist爬取P站的视频,利用aria2下载视频

2020-01-05 15:45 3301 次阅读 PHP成长
距上一次爬取图片已经过去一个多月,期间由于不满足于图片的我开始打起了P站的注意,也成功的爬取了很多视频,苦于我留下了没有硬盘的泪,硬盘只有3T,现在还剩一百多G了,留着以后装其他重要的东西。研究这个代码和写这个代码可能花了接近大半个月吧,具体时间也记不清了,下载视频花了一段时间,慢速下10M每秒也下了挺久的,主要是要在服务器上中转一次。开始的时候疯狂的下,感觉就是几百年没看过电源一样,过了几天后发现,索然无味!,有小伙伴迫切的想学习下代码,so,我就分享出来。这个P站呢,估计大部分老司机都是懂得。在这里呢也发现个php的好东西
![](https://skapi-1253927675.cos.ap-guangzhou.myqcloud.com/blog/202001/68401266e30d092198a10a86532dc34f.png)
一个采集框架,这么好的一个东西怎么会没有早点发现他,此次的一个主角之一就是他了,采集框架。如果会点jquery的话用这个用起来应该是相当的顺手。只不过文档上面写的用法都比较基础,需要更深入的用法则需要自己深入了解下才行。具体怎么深入呢?来不及解释了,赶快上车。我是用的tp5.0的框架,composer引入进来的这个querylist。找到网址,最好带参数页码的这种比如:https://cn.xxxxxxx.com/video?c=111&page= 这种,这里只做技术交流
```php
$rules = [
'name'=>['.thumbnail-info-wrapper.clearfix>span>a','text'],
'src'=>['.linkVideoThumb.js-linkVideoThumb.img','href'],
'ima_src'=>['.js-pop.js-videoThumb.thumb.js-videoPreview.lazy','src'],
'time'=>['.marker-overlays.js-noFade>var','text'],
'hp'=>['.rating-container.neutral>.value','text'],
];
$sq = QueryList::getInstance();
//注册一个browser
$sq->use(PhantomJs::class,'/项目目录/vendor/jaeger/querylist-phantomjs/phantomjs-2.1.1-linux-x86_64/bin/phantomjs','browser');
for ($i=1;$i<=499;$i++){
$page = $i;
$url = 'https://cn.xxxxxx.com/video?c=111&page='.$page;
$data = $sq->browser($url)
->rules($rules)
->queryData();
$insert_data = [];
$count = 0;
foreach ($data as $k => $v){
if ($k >= 4 && !empty($v['ima_src'])){
$v['time'] = $v['time'].':00';
$url = $host.$v['src'];
$v['src'] = $url;
$v['page'] = $page;
$v['type'] = 'rb';
$insert_data[] = $v;
$count++;
}
}
$rst = Db::name('video_url')->insertAll($insert_data);
}
```
我这里是存入的数据库,当然还可以做其他操作,比如这里开始循环直接下载视频。不过我是存入数据库选择性下载,上面的代码中PhantomJs这个是个插件,大概就是采集js渲染的页面,因为我的采集目标有些元素是js生成的,还有些什么伪元素的,这些我都不懂,不过只要能拿到数据就好了。那个$rules就是规则,类似于正则之类的,不过这个比正则速度快,他用的jq选择器。对于那个name我举个例子
![](https://skapi-1253927675.cos.ap-guangzhou.myqcloud.com/blog/202001/82796dcfea19791b9f5bf9f6be760691.png)
这里`'name'=>['.thumbnail-info-wrapper.clearfix>span>a','text'],`这个就是选择同时拥有thumbnail-info-wrapper和clearfix这两种class属性的元素,这个元素从图中看出是个div,>就是找他的下级元素,找他的下级元素span标签,span标签的下级元素a标签,后面的‘text’就是找这个a标签的text文本内容也就是他的这部电影的名字,以此类推src是这个电影的链接,也就是播放地址,但并不是下载地址。我们既然能拿到这个播放地址了,这个播放地址是一直有效的,除非视频被下架了,所以这个地址可以存数据库,他和下载地址不一样。下载地址是有时间限制的,还有ip限制,所以下载地址需要及时的进行下载并不能长时间保存,具体时间我没测试过。进入这个地址后就可以找到下载地址了
![](https://skapi-1253927675.cos.ap-guangzhou.myqcloud.com/blog/202001/ee238aa3416999325bb91b4e97de1d11.png)
在当时我并没有研究出如何登陆,在querylist的一个付费群里也没什么人鸟我,大概是大佬都很忙吧。关于这个js生成的下载地址我也是摸索了好久,各种查资料找到这个。我当时的一个解决方案是:
1、把所有视频的播放地址,封面地址,title和时长都储存到数据库。
2、写一个页面把数据根据封面渲染出来并做好分页。
3、点击封面的时候跳转后台抓取页面的一段js代码,php直接输出html和JavaScript,在js脚本里面生成一个带参数的按钮并赋值下载地址。
4、点击按钮,提交至后台推送给aria2下载。
这样能做到选择性的提交下载,并且不会有下载链接超时不能下载的情况。(因为下载有ip验证所以只能先下载到境外服务器,然后才能下载到本地)
不过后来还是找到了登陆下载的方法,可以挂代理登陆上去,获取cookie值,携带cookie请求链接,就会是登陆状态,cookie需要完全复制
```php
$list = ['视频列表集'];
$rules = ['name'=>['.downloadBtn.greyButton','text'],'src'=>['.downloadBtn.greyButton','href']];
$header = [
'Accept'=>'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
'Accept-Encoding'=>' deflate, br',
'Accept-Language'=>'zh-CN,zh;q=0.9',
'Cache-Control'=>'max-age=0',
'Connection'=>'keep-alive',
'Content-Type'=>'text/html; charset=UTF-8',
'Cookie'=>"你成功登陆后的cookie",
'Host'=>'cn.pornhubpremium.com',
'Sec-Fetch-Mode'=>'navigate',
'Sec-Fetch-Site'=>'none',
'Sec-Fetch-User'=>'?1',
'Upgrade-Insecure-Requests'=>'1',
'User-Agent'=>'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
];
$sq = QueryList::getInstance();
$sq->use(PhantomJs::class,'/项目地址/vendor/jaeger/querylist-phantomjs/phantomjs-2.1.1-linux-x86_64/bin/phantomjs','browser');
foreach ($list as $k => $v){
$aria2 = new \Aria2('http://127.0.0.1:6800/jsonrpc');
$this->wait($aria2);
$v['name'] = str_replace(' ','-',$v['name']).'.mp4';
$v['name'] = str_replace('/','-',$v['name']).'.mp4';
$data = $sq
->browser(function (RequestInterface $r)use ($header,$v){
$r->setHeaders($header);
$r->setMethod('GET');
$r->setUrl($v['src']);
$r->setTimeout(10000); // 10 seconds
return $r;
})
->rules($rules)
->queryData();
if (!empty($data)){
$data[0]['name'] = str_replace(' ','',$data[0]['name']);
$data[0]['name'] = str_replace('高清','',$data[0]['name']);
dump($data[0]);
Db::name('video_url')->where('id','=',$v['id'])->update([$data[0]['name']=>1]);
$rst = $aria2->addUri(
[$data[0]['src']],//下载地址
['dir' => '/视频保存文件夹地址/', 'out'=>'['.$data[0]['name'].']'.$v['name'],]
);
echo '['.$data[0]['name'].']'.$v['name'];
echo '提交aria2下载';
}else{
Db::name('video_url')->where('id','=',$v['id'])->update(['xiajia'=>1]);
echo '已下架';
}
echo PHP_EOL;
}
```
`$r->setHeaders($header);`这个方法querylist关于phantomjs插件的说明并未说明,phantomjs的官方文档,说实话,我确实没看懂。后来我怎么发现的这个方法我自己都不知道。当然这里我是默认下载的最高清的视频。这段代码中可能大家注意到了有一个aria2,这个就是我们今天的另一个主角,她是一个多线程下载器balabala一大堆,此处省略三千字,github有aria2-php代码,一搜就出来了,linux安装aria2也很好安装,yum一把梭,使用起来非常简单`$rst = $aria2->addUri(
[$data[0]['src']],//下载地址
['dir' => '/视频保存文件夹地址/', 'out'=>'['.$data[0]['name'].']'.$v['name'],]
);`就这样就能够推送给aria2下载了。