爬一下知识星球

只做一下记录,将爬取下来的内容全都写成了markdown文件

首先登录网页版, wx.zsxq.com

网上很多文章爬知识星球都是说有个 Authorization 来进行的认证,但不知道是改版了还是怎么,我在写爬虫的时候发现认证依然是 cookie, 其中有一个 zsxq_access_token

首先是 https://api.zsxq.com/v1.10/groups/xxxx/topics?count=20

这个xxxx就是知识星球的id,也就是随便点击一个圈子后,url中 https://wx.zsxq.com/dweb/#/index/xxxxxx 这个 xxx 的部分,其他大概没有什么好说的,主要就是api里怎么取下一页的内容,他没有页标的参数,而是使用 end_time 这个参数来进行分页的

首先访问这个api后会返回一串很大的json

其中 create_time 就是用来进行分页的 end_time 参数的值,并且其中的 :+ 必须得url编码

把topics中的一个主题内容展开来看看其中需要关注的内容有什么

create_time 当然如果这不是本页最后一条就没啥意义了

show_comments 该主题对应的评论数据,返回的是一个列表,其中需要取的值就是 owner.name(评论者name,text (评论内容,其中有可能存在一个键值为 repliee,这个是对某人的评论进行了回复,同样其中是有name和text的键值

talk,主题内容了,取其中的 owner 就是主题作者,text 就是主题内容,但是这里有几个坑点

首先是text中的标签,目前遇到的有三种,一个是标签,就像这样的

一个是很常见的超链接,知识星球返回来的数据中,对标签都做了处理,全都变成了 <e type="xx"> 这种形式

超链接转换后是 <e type="web" href="xxx" title="xxx">

标签转换后是 <e type="hashtag" hid="xx" title="xxx">

最后一个就是 @ 功能

标签长这样 <e type="mention" uid="xxx" title="@xxx">

目前遇到的主题中还没有出现其他的标签。

所以需要对这种的进行一下处理

1
2
3
4
5
6
7
8
9
10
11
12
def handle_link(text):
result = re.findall(r'<e\ [^>]*>', text)
for i in result:
html = PQ(i)
if html.attr('type') == 'web':
template = '[%s](%s)' % (urllib.parse.unquote(html.attr('title')), urllib.parse.unquote(html.attr('href')))
elif html.attr('type') == 'hashtag':
template = ' `%s` ' % urllib.parse.unquote(html.attr('title'))
elif html.attr('type') == 'mention':
template = urllib.parse.unquote(html.attr('title'))
text = text.strip().replace(i, template)
return text

其次就是图片,这个没有什么好说的,就在 talk.images 中,返回的是一个列表,迭代一下取其中 large 类别的链接下载下来就好了

最后是文件,返回的也是一个列表,只不过这个需要再请求一次新的api取下载地址

取到这个 file_id, 然后请求 https://api.zsxq.com/v1.10/files/xxx/download_url,把取到的 file_id 替换掉这个 xxx

返回结果如下,其中的 download_url 就是文件的下载地址了

几个坑

  • 主题内容如果有代码片段,大概率是直接返回没有任何标签的字符串,所以没法进行格式化和高亮的操作,识别不出来
  • 某些主题可能存在没有正文的情况,也就是说talk中可能是没有text这个键的
  • 评论中的表情如果不是emoji,就是 [xx],这个感觉没啥影响,所以就放着了

最后爬下来的一个效果

Author: 4uuu Nya
Link: https://qvq.im/2019/04/17/爬一下知识星球/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.