当前位置: 首页 > 后端技术 > PHP

[PHP]又是知乎,用Beanbun爬知乎用户

时间:2023-03-29 17:48:23 PHP

最近看了很多爬虫入门的文章,发现大部分都是以知乎作为爬取的对象,所以这次也用知乎爬虫的演示,使用的爬虫框架是用PHP写的Beanbun。项目地址:https://github.com/kiddyuchina/Beanbun这次写的内容是爬取知乎用户。下面详细说明编写爬虫的过程。爬知乎用户的思路比较简单,就是从某个用户开始,先抓取这个用户关注的人和他关注的人,抓到这些人之后,再抓取他们的相关用户。现在知乎可以游客浏览了,注册登录的部分也省略了。先找个大V就行了,因为他们粉丝比较多。我选择了大名鼎鼎的张先生。张先生有13万粉丝。也就是说,如果我们只爬他的粉丝,我们可以有13万。用户数据~在用户页面打开chrome浏览器的开发者选项,点击follower可以看到请求地址和数据。就以此为入口开始爬取吧~这里跳过框架的安装和队列的开启,直接看爬虫的代码:(需要跳过的部分可以看文档)name='zhihu_user';$beanbun->count=5;$beanbun->interval=4;$beanbun->seed='https://www.zhihu.com/api/v4/members/zhang-jia-wei/followers?include=data%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=0&limit=20';$beanbun->logFile=__DIR__。'/zhihu_user_access.log';以上是爬虫的配置,同时启动5个进程进行爬取,设置爬取间隔为4秒。在抓取之前,我们还需要设置请求的headers,让网站认为是人,然后浏览他--。标头的内容是从开发人员选项中粘贴的。$beanbun->beforeDownloadPage=function($beanbun){//抓取前设置请求头$beanbun->options['headers']=['Host'=>'www.zhihu.com','Connection'=>'keep-alive','Cache-Control'=>'max-age=0','Upgrade-Insecure-Requests'=>'1','User-Agent'=>'Mozilla/5.0(Macintosh;IntelMacOSX10_12_3)AppleWebKit/537.36(KHTML,likeGecko)Chrome/57.0.2987.133Safari/537.36','Accept'=>'application/json,text/plain,*/*','Accept-Encoding'=>'gzip,deflate,sdch,br','授权'=>'oauthc3cef7c66a1843f8b3a9e6a1e3160e20',];};请求数据后,需要保存到数据库中,因为主要是演示,所以只保存User的id,name,follower,following四个数据。//数据库配置Db::$config['zhihu']=['server'=>'127.0.0.1','port'=>'3306','username'=>'xxxx','password'=>'xxxx','database_name'=>'zhihu','charset'=>'utf8',];$beanbun->afterDownloadPage=function($beanbun){//获取的数据为json,先解析$data=json_decode($beanbun->page,true);//如果没有数据或者报错,可能会被阻塞。如果(isset($data['error'])||!isset($data['data'])){$beanbun->queue()->add($beanbun->网址);$beanbun->error();}//如果抓取的不是最后一页,将下一页加入队列if($data['paging']['is_end']==false){$beanbun->queue()->add($数据['分页']['下一个']);}$插入=[];$date=date('Y-m-dH:i:s');foreach($data['data']as$user){//如果follower或follower小于5,则不保存if($user['follower_count']<5||$user['following_count']<5){继续;}$insert[]=['id'=>$user['id'],'name'=>$user['name'],'follower'=>$user['follower_count'],'following'=>$user['following_count'],'created_at'=>$date,];//将用户的关注者和关注者加入队列$beanbun->queue()->add('https://www.zhihu.com/api/v4/members/'.$user['url_token'].'/followers?include=data%5B*%5D.following_count%2Cfollower_count&limit=20&offset=0');$beanbun->queue()->add('https://www.zhihu.com/api/v4/members/'.$user['url_token'].'/followers?include=data%5B*%5D.following_count%2Cfollower_count&limit=20&offset=0');}}if(count($insert)){Db::instance('zhihu')->insert('zhihu_user',$insert);}//将刚刚爬取的地址标记为已爬取$beanbun->queue()->queued($beanbun->queue);};//发现新URL不需要框架,$beanbun->discoverUrl=function(){};$beanbun->开始();接下来在命令行运行爬虫$phpzhihu_user.phpstart然后看一下数据库,源源不断的用户数据已经保存在了~一切顺利的情况下,我稍微努力了一下,减少了爬取间隔为2秒,所以10分钟后,我就被知乎拉黑了。。。这种情况比较常见的解决方法是使用代理,在原有爬虫的基础上,增加一个简单的代理池,可以定期更新。先停止爬虫$phpzhihu_user.phpstop网上有很多免费代理网站。我只是选择了一个提供免费代理的网站,爬取到代理数据后,先请求163,如果成功,就加入代理池。函数getProxies($beanbun){$client=new\GuzzleHttp\Client();$beanbun->proxies=[];$pattern='/(.+)<\/td>(\d+)<\/td>(.+)(HTTP|HTTPS)<\/td>/isU';for($i=1;$i<5;$i++){$res=$client->get("http://www.mimiip.com/gngao/$i");$html=str_replace(['',"\r","\n"],'',$res->getBody());preg_match_all($pattern,$html,$match);foreach($match[1]as$k=>$v){$proxy=strtolower($match[4][$k])."://{$v}:{$match[2][$k]}";echo"getproxy$proxy";try{$res=$client->get('http://mail.163.com',['proxy'=>$proxy,'timeout'=>6]);echo"success.\n";}catch(\Exception$e){echo"error.\n";}}}}if($argv[1]=='start'){getProxies($beanbun);}$beanbun->startWorker=function($beanbun){//每半小时,更新代理池Beanbun::timer(1800,'getProxies',$beanbun);};添加if(isset($beanbun->proxies)&&count($beanbun->proxies)){$beanbun->options['proxy']=$beanbun->proxies[array_rand($beanbun->proxies)];}再次启动爬虫,爬虫会从之前的队列继续爬取。$phpzhihu_user.phpstart再看数据库,使用代理可能比之前更慢,但是数据不断增加。最终代码可以在Github上查看https://github.com/kiddyuchin...例子中的代理池还是比较简单的,只是为了说明框架的灵活性,爬取到的数据这里就不做图了分析,希望大家注意写爬虫的过程。最后,如果你对这篇文章感兴趣,希望你能在Github上给个star,谢谢~https://github.com/kiddyuchin...