我不是技术
PHP成长
ARTICLE
linux相关
ARTICLE
其他类别
ARTICLE
文章
> [PHP采集]基于querylist爬取P站的视频,利用aria2下载视频
15:45
2020/01/05
1168
[PHP采集]基于querylist爬取P站的视频,利用aria2下载视频
距上一次爬取图片已经过去一个多月,期间由于不满足于图片的我开始打起了P站的注意,也成功的爬取了很多视频,苦于我留下了没有硬盘的泪,硬盘只有3T,现在还剩一百多G了,留着以后装其他重要的东西。研究这个代码和写这个代码可能花了接近大半个月吧,具体时间也记不清了,下载视频花了一段时间,慢速下10M每秒也下了挺久的,主要是要在服务器上中转一次。开始的时候疯狂的下,感觉就是几百年没看过电源一样,过了几天后发现,索然无味!,有小伙伴迫切的想学习下代码,so,我就分享出来。这个P站呢,估计大部分老司机都是懂得。在这里呢也发现个php的好东西  一个采集框架,这么好的一个东西怎么会没有早点发现他,此次的一个主角之一就是他了,采集框架。如果会点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我举个例子  这里`'name'=>['.thumbnail-info-wrapper.clearfix>span>a','text'],`这个就是选择同时拥有thumbnail-info-wrapper和clearfix这两种class属性的元素,这个元素从图中看出是个div,>就是找他的下级元素,找他的下级元素span标签,span标签的下级元素a标签,后面的‘text’就是找这个a标签的text文本内容也就是他的这部电影的名字,以此类推src是这个电影的链接,也就是播放地址,但并不是下载地址。我们既然能拿到这个播放地址了,这个播放地址是一直有效的,除非视频被下架了,所以这个地址可以存数据库,他和下载地址不一样。下载地址是有时间限制的,还有ip限制,所以下载地址需要及时的进行下载并不能长时间保存,具体时间我没测试过。进入这个地址后就可以找到下载地址了  在当时我并没有研究出如何登陆,在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下载了。