爬取掘金热点

爬取掘金热门文章

主要是掘金传输数据分析,并没有几行代码╮(╯▽╰)╭
6/5: 代码补上了

测试的参数列表

url_entry 后端 安卓 前端
src web web web
limit 20 20 20
category 5562b419e4b00c57d9b94ae2 5562b410e4b00c57d9b94a92 5562b415e4b00c57d9b94ac8
url_punch
sub_location backend android frontend
location welcome welcome welcome
suid J3rzUv6EaFYYfem2QFZQ J3rzUv6EaFYYfem2QFZQ J3rzUv6EaFYYfem2QFZQ
src juejin.im juejin.im juejin.im

检查掘金的网络请求可以发现有三个链接很可疑

$url_entry = 'https://timeline-merger-ms.juejin.im/v1/get_entry_by_rank';

$url_punch = 'https://ubc-api-ms.juejin.im/v1/punch';

$url_recommend = 'https://recommender-api-ms.juejin.im/v1/get_recommended_entry?suid=J3rzUv6EaFYYfem2QFZQ&ab=welcome_3&src=web';

punch链接没有返回有用的信息,暂不分析(虽然它的参数列表看起来最正常)。


get_recommend_entry链接返回json结构

【仅d元素和tags元素为array,其余皆为object】

  • d
    • 0
    • collectionCount
    • commentCount
    • gfw
    • objectId
    • subscribersCount
    • ngxCachedTime
    • recommenderInfo
      • filtered
      • source
      • score
    • tags 【此文章所属的所有技术分类】
      • 0
      • title 【技术分类?】
      • ngxCached
      • ngxCachedTime 【某种顺序编号】
      • id
    • title 【文章标题】
    • content 【文章首句】
    • type
    • updatedAt
    • entryView
    • rankIndex
    • author
    • category 【文章分类】
      • ngxCached
      • title
      • id
      • name 【方向分类?】
      • ngxCachedTime
    • originalUrl 【原始URL,即原网站】
    • buildTime 【记录时间?有四位小数】
    • original
    • user 【用户信息】
      • avatarLarge 【头像链接】
      • community 【社交信息,Github, 微信等】
      • collectedEntriesCount
      • company 【公司信息】
      • followersCount 【关注的人数】
      • followeesCount 【关注着人数】
      • role
      • subscribedTagsCount
      • totalCollectionsCount 【“获得的喜欢”数】
      • totalCommentsCount
      • username 【用户名】
      • viewedEntriesCount
    • verifyCreatedAt 【创建事件】
    • verifyStatus
    • viewsCount 【总访问量】

get_entry_by_rank返回json结构

  • d
    • entrylist
    • 0
      • author
      • buildtime
      • category 【分类】
      • id
      • name 【分类名称】
      • ngxCached
      • ngxCachedTime
      • title 【分类名,英文版,可能用作get参数】
      • checkStatus
      • collectionCount
      • commentsCount
      • content 【内容片段】
      • createAt 【创建时间】
      • english 【是否英文?】
      • entryView
      • gfw
      • hot 【未知,与是否显示“热”没关系】
      • hotIndex 【热度?2700+无“热”,3300+有“热”】
      • isCollected
      • isEvent
      • lastCommentTime 【最后评论时间】
      • ngxCachedTime
      • objectId 【对象编号,接口参数?】
      • original
      • originalUrl
      • rankIndex 【热度等级?】
      • screenshot
      • subscribeCount
      • summaryInfo
      • tags 【标签】
      • 0
        • title 【技术分类?】
        • ngxCached
        • ngxCachedTime 【某种顺序编号】
        • id
      • title 【文章标题】
      • type 【文章类型】
      • updatedAt
      • user
      • avatarLarge 【头像链接】
      • community 【社交信息,Github, 微信等】
      • collectedEntriesCount
      • company 【公司信息】
      • followersCount 【关注的人数】
      • followeesCount 【关注着人数】
      • role
      • subscribedTagsCount
      • totalCollectionsCount 【“获得的喜欢”数】
      • totalCommentsCount
      • username 【用户名】
      • viewedEntriesCount
      • …省略
      • verifyCreateAt
      • verifyStatus
      • viewsCount 【文章阅读数】
    • list 【返回数量】
  • m
  • s

分析结果

经过分析,我们可以确定几个爬取有用的键值对,

{index} ——列表索引
在url_entry中要改为d->entrylist->{index}

  • 文章标题相关

    • 相关键值对

    • d->{index}->title

      文章标题

    • d->{index}->content

      文章内容片段

  • 文章的url

    • 相关键值对

    • d->{index}->originalUrl

      文章的原始地址,即掘金转码前的地址(可能是掘金原创文章)

    • d->{index}->type

      文章类型,已知有两种,"article"/"post",对应的链接参数为entry/post

    • d->{index}->objectId 对象ID,24位数字,应该是文章在掘金的唯一编号

    • URL格式

    https://juejin.im/entry/{objectId}

    article类型文章的url,在花括号位置替换为相应参数

    测试后发现post类型文章也可以用entry&id的格式打开入口连接,之后会显式跳转到post类型链接

    d->{index}->originalUrl

    post类型的文章url,应该都是掘金原创文章,post参数下的编号

  • 文章分类

    • 相关键值对

    • d->{index}->category->name

      用于展示的分类名称

    • d->{index}->category->title

      用作参数的分类名称

    • 一般展示用name视觉效果更好

  • 文章标签

    • 相关键值对

    • d->{index}->tags->{index}->title

      标签名称,用作参数或者展示皆可,类似于d->category->title

  • 作者信息

    • 相关键值对

    • d->{index}->user->username

      用户名

    • d->{index}->user->avatarLarge

      用户头像URL,来自稀土的图床

    • d->{index}->user->community

      用户的社交信息,包括微信、Github等,内部有用户名、头像等信息


接下来是爬取方法

get_recommand网址可以直接使用原参数爬取json数据

get_entry网址可以构建参数:

  • src

    原参数即可(web

  • limit

    返回的文章数

  • category

    文章种类对应的id,可在每篇文章的json的category->id一项看到

  • before

    可选参数,用作翻页相关的信息,加上此参数,将会返回自文章中rankIndex于before参数相同的文章之后limit参数数量的文章。

已知category

{
    "frontend": "5562b415e4b00c57d9b94ac8",
    "android": "5562b410e4b00c57d9b94a92",
    "backend": "5562b419e4b00c57d9b94ae2",
    "ai": "57be7c18128fe1005fa902de",
    "ios": "5562b405e4b00c57d9b94a41",
    "freebie": "5562b422e4b00c57d9b94b53"
}

PHP实例

前两个函数用作发送json数据到前端,格式为

  • {index} 【数字索引】
    • title
    • tags
    • {index} 【数字索引】
    • url

后两个函数用作写入Markdown文件,

function sendEntryToFronted(string $kind, int $limit) {

    $category = [
        'frontend' => '5562b415e4b00c57d9b94ac8',
        'android' => '5562b410e4b00c57d9b94a92',
        'backend' => '5562b419e4b00c57d9b94ae2',
        'ai' => '57be7c18128fe1005fa902de',
        'ios' => '5562b405e4b00c57d9b94a41',
        'freebie' => '5562b422e4b00c57d9b94b53'
    ];
    $url_entry = 'https://timeline-merger-ms.juejin.im/v1/get_entry_by_rank?src=web&limit='.$limit.'&category='.$category[$kind];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 掘金采取https协议需要设置此参数才能爬取内容
    curl_setopt($ch, CURLOPT_URL, $url_entry);

    $content = json_decode(curl_exec($ch));

    $data = [];
    $i = 0;
    foreach ($content->d->entrylist as $item) {

        $data[$i]['title'] = $item->title;
        $j = 0;
        foreach ($item->tags as $tag) {

            $data[$i]['tags'][$j++] = $tag->title;
        }
        $data[$i++]['url'] = 'https://juejin.im/entry/'.$item->objectId;
    }
    echo(json_encode($data));
}

function sendRecommendToFronted() {

    $url_recommend = 'https://recommender-api-ms.juejin.im/v1/get_recommended_entry?suid=J3rzUv6EaFYYfem2QFZQ&ab=welcome_3&src=web';

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 掘金采取https协议需要设置此参数才能爬取内容
    curl_setopt($ch, CURLOPT_URL, $url_recommend);

    $content = json_decode(curl_exec($ch));

    $data = [];
    $i = 0;
    foreach ($content->d as $item) {

        $data[$i]['title'] = $item->title;
        $j = 0;
        foreach ($item->tags as $tag) {

            $data[$i]['tags'][$j++] = $tag->title;
        }
        $data[$i++]['url'] = 'https://juejin.im/entry/'.$item->objectId;
    }
    echo(json_encode($data));
}

function dumpRecommendToMarkdown(string $file, object $content) {

    $fp = fopen($file, "w");

    foreach ($content->d as $item) {

        fwrite($fp, '## '.$item->title."\n");
        foreach ($item->tags as $tag) {

            fwrite($fp, '【'.$tag->title.'】');
        }
        if ($item->type === 'post') {

            $type = 'post';
        } else {

            $type = 'entry';
        }
        fwrite($fp, "\n\n[点此查看](".'https://juejin.im/'.$type.'/'.$item->objectId.")\n\n\n");
    }

    fclose($fp);
}

function dumpHotArticleToMarkdown(string $file, object $content) {



    $fp = fopen($file, 'w');
    foreach ($content->d->entrylist as $article) {

        fwrite($fp, '## '.$article->title."\n\n[点此查看]".'(https://juejin.im/entry/'.$article->objectId.")\n\n");
    };

    return fclose($fp);
}

你可能感兴趣的:(爬虫)