资讯专栏INFORMATION COLUMN

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

tomato / 942人阅读

摘要:最近看了很多关于爬虫入门的文章,发现其中大部分都是以知乎为爬取对象,所以这次我也以知乎为目标来进行爬取的演示,用到的爬虫框架为编写的。项目地址这次写的内容为爬取知乎的用户,下面就是详细说一下写爬虫的过程了。

最近看了很多关于爬虫入门的文章,发现其中大部分都是以知乎为爬取对象,所以这次我也以知乎为目标来进行爬取的演示,用到的爬虫框架为 PHP 编写的 Beanbun。

项目地址:https://github.com/kiddyuchina/Beanbun

这次写的内容为爬取知乎的用户,下面就是详细说一下写爬虫的过程了。

爬取知乎用户的思路比较简单,就是从某个用户开始,先抓取这个用户关注的人和关注他的人,抓取到这些人后,再抓取他们的相关的用户。
现在知乎是可以使用游客身份进行浏览的,也省去了注册和登录这一部分。先随便找个大V吧,因为他们的关注者比较多,我选择的是大名鼎鼎的张公子,张公子的关注者有13万,就是说只爬取他的关注者,我们都能有13万的用户数据~

在用户页面中打开chrome浏览器的开发者选项,点击关注者后就可以看到请求地址和数据。

就以这个作为入口开始爬取了~
此处跳过框架的安装和队列的开启,直接上爬虫的代码:
(如果需要跳过的部分,可以看一下文档)

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,好让网站认为是人类再浏览他- -。headers的内容从开发者选项中一股脑粘贴进来。

$beanbun->beforeDownloadPage = function ($beanbun) {
    // 在爬取前设置请求的 headers 
    $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; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept" => "application/json, text/plain, */*",
        "Accept-Encoding" => "gzip, deflate, sdch, br",
        "authorization" => "oauth c3cef7c66a1843f8b3a9e6a1e3160e20",
    ];
};

而在请求到数据后,我还需要把他们存到数据库中,因为主要是演示,所以只保存用户的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);

    // 如果没有数据或报错,那可能是被屏蔽了。就把地址才重新加回队列
    if (isset($data["error"]) || !isset($data["data"])) {        
        $beanbun->queue()->add($beanbun->url);
        $beanbun->error();
    }
    
    // 如果本次爬取的不是最后一页,就把下一页加入队列
    if ($data["paging"]["is_end"] == false) {
        $beanbun->queue()->add($data["paging"]["next"]);
    }

    $insert = [];
    $date = date("Y-m-d H:i:s");

    foreach ($data["data"] as $user) {
        // 如果关注者或者关注的人小于5个,就不保存了
        if ($user["follower_count"] < 5 || $user["following_count"] < 5) {
            continue ;
        }
        $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"] . "/followees?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);
};
// 不需要框架来发现新的网址,
$beanbun->discoverUrl = function () {};
$beanbun->start();

接下来在命令行运行爬虫

$ php zhihu_user.php start

再去看一眼数据库,源源不断的用户数据保存进来了~
在一切顺利的情况下,我又稍微作了一下死,把爬取的间隔减到了2秒,于是在10几分钟之后,我被知乎封掉了....
这种情况比较常见的解决方式就是使用代理,下面就在原有爬虫基础上,增加一个简单的可定时更新的代理池。
先停止爬虫

$ php zhihu_user.php stop

网上有很多免费代理的网站,我随便选了一个提供免费代理的网站,爬取到代理的数据后,先请求一下163,如果成功的话就加入代理池。

function getProxies($beanbun) {
    $client = new GuzzleHttpClient();
    $beanbun->proxies = [];
    $pattern = "/(.+)(d+)(.+)(HTTP|HTTPS)
get("http://www.mimiip.com/gngao/$i"); $html = str_replace([" ", " ", " "], "", $res->getBody()); preg_match_all($pattern, $html, $match); foreach ($match[1] as $k => $v) { $proxy = strtolower($match[4][$k]) . "://{$v}:{$match[2][$k]}"; echo "get proxy $proxy "; try { $res = $client->get("http://mail.163.com", [ "proxy" => $proxy, "timeout" => 6 ]); echo "success. "; } catch (Exception $e) { echo "error. "; } } } } if ($argv[1] == "start") { getProxies($beanbun); } $beanbun->startWorker = function($beanbun) { // 每隔半小时,更新一下代理池 Beanbun::timer(1800, "getProxies", $beanbun); };

再在之前的 beforeDownloadPage 中加入

if (isset($beanbun->proxies) && count($beanbun->proxies)) {
    $beanbun->options["proxy"] = $beanbun->proxies[array_rand($beanbun->proxies)];
}

再次启动爬虫,爬虫还会接着之前的队列继续爬取。

$ php zhihu_user.php start

再看看数据库,使用代理可能会比之前慢一些,不过数据又继续增加了。
最终的代码可以在 Github 上查看

https://github.com/kiddyuchin...

例子中的代理池还是比较简陋的,只是用来说明框架的灵活,而爬取到数据在这里就不做图表进行分析了,希望大家关注的也是写爬虫的过程。
最后如果你对这篇文章感兴趣,希望能到 Github 上给个 star 啦,谢谢~

https://github.com/kiddyuchin...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/22915.html

相关文章

  • php爬虫:知乎户数据爬取和分析

    摘要:背景说明小拽利用的写的爬虫,实验性的爬取了知乎用户的基本信息同时,针对爬取的数据,进行了简单的分析呈现。本程序抓取的是知乎对外提供用户访问的个人信息页面抓取过程需要携带用户才能获取页面。 背景说明:小拽利用php的curl写的爬虫,实验性的爬取了知乎5w用户的基本信息;同时,针对爬取的数据,进行了简单的分析呈现。demo 地址 php的spider代码和用户dashboard的展现代码...

    Jioby 评论0 收藏0
  • php爬虫:知乎户数据爬取和分析

    摘要:背景说明小拽利用的写的爬虫,实验性的爬取了知乎用户的基本信息同时,针对爬取的数据,进行了简单的分析呈现。本程序抓取的是知乎对外提供用户访问的个人信息页面抓取过程需要携带用户才能获取页面。 背景说明:小拽利用php的curl写的爬虫,实验性的爬取了知乎5w用户的基本信息;同时,针对爬取的数据,进行了简单的分析呈现。demo 地址 php的spider代码和用户dashboard的展现代码...

    honhon 评论0 收藏0
  • php爬虫:知乎户数据爬取和分析

    摘要:背景说明小拽利用的写的爬虫,实验性的爬取了知乎用户的基本信息同时,针对爬取的数据,进行了简单的分析呈现。本程序抓取的是知乎对外提供用户访问的个人信息页面抓取过程需要携带用户才能获取页面。 背景说明:小拽利用php的curl写的爬虫,实验性的爬取了知乎5w用户的基本信息;同时,针对爬取的数据,进行了简单的分析呈现。demo 地址 php的spider代码和用户dashboard的展现代码...

    saucxs 评论0 收藏0

发表评论

0条评论

tomato

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<