主要是掘金传输数据分析,并没有几行代码╮(╯▽╰)╭
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链接没有返回有用的信息,暂不分析(虽然它的参数列表看起来最正常)。
【仅d元素和tags元素为array,其余皆为object】
经过分析,我们可以确定几个爬取有用的键值对,
{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
参数数量的文章。
{
"frontend": "5562b415e4b00c57d9b94ac8",
"android": "5562b410e4b00c57d9b94a92",
"backend": "5562b419e4b00c57d9b94ae2",
"ai": "57be7c18128fe1005fa902de",
"ios": "5562b405e4b00c57d9b94a41",
"freebie": "5562b422e4b00c57d9b94b53"
}
前两个函数用作发送json数据到前端,格式为
后两个函数用作写入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);
}