全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-07-21_「转」写个有点用的Bot:掘金作者画像

您的位置:首页 >> 新闻 >> 行业资讯

写个有点用的Bot:掘金作者画像 1. 引言??上周五,掘金又发布了 Coze(扣子) 有关的活动 → 《?? 玩转沸点 | 成为AI魔法大师,释放你的完美创造力!》,不需要写文章,只需要 建Bot发布到掘金,并在 AI聊天室 中发 沸点@ 该Bot进行对话就能参与。 ?? 活动参与门槛大大降低了啊,然后交流群就有小??汁开始整活,有喜欢对骂的 隔壁老王: 还有各种 优弧 的Bot: ?? 不得不说 群友个个都是人才~ ?? Coze搭Bot的玩法很 简单,难点是 Bot的创意,即 应用场景,你打算用它来 解决什么问题。先确定 思路,再来 搭。具体玩法和案例可以参考我之前写的几篇文章: 《用Coze扣子轻松搭个Bot,从此告别"标题党"》《【踩坑】用Coze订制一只专属AI小秘??》《???♂?Coze国内版插件汇总-By油猴》《Coze + 爬虫 = 周末去哪不用愁??》《???♀?Coze官方插件不够用?手把手教你自己造(白嫖)》?? 如果你刚开始尝试搭Bot,应该能对你有所 启发,当然,也可以参考 《官方:扣子帮助文档》来搭建~ ?? 最近在梳理自己的知识体系,看到其中一个分类 → 个人品牌/标签,让我想到了一个 idea??,能否写一个Bot来 帮助读者快速了解一个掘金作者的用户画像。即:用户@Bot并发送一个 作者主页的url,Bot对该作者的 所有文章的标题、摘要、文章标签 进行分析,构建一些 描述作者特征的概要 (如擅长的专业知识领域),同时提供一些 附加信息,如文章数量、阅读量、点赞量等,以及提供一些 阅读推荐 (如该作者最热的10篇文章链接)。 ?? 以下是对Bot的期望返回结果: ??【】于【加入掘金的日期】加入掘金,共计发布了【文章数】篇文章,收获了:???♂?x关注数|??x点赞数|??x阅读量|??x掘力值,它的作者画像概要如下: 大模型对作者所有的文章标题、概要、文章标签等进行文本分析,生成一段符合作者特征的概要 ? TA擅长的领域 (取前四个,剩下的归类为其它): - 1、前端 (符合标签的文章占比%, 10篇) → 如:前端 (18.2%, 5篇) - 2、xxx ?? TA热度最高的文章 (不足十篇有多少取多少): - [《标题》](链接) - ... 接着以 返回结果 为导向,思考下具体实现这个Bot,?? 本质是还是那两步:获取数据、处理数据,接着按部就班实现一波~! 2. 获取数据???♂? 需要获取的数据有:作者的用户信息 + 所有文章信息,老规矩,先看下有没有现成的,没有再自己捣鼓。在 Coze插件商店 搜了下 掘金,发现只有一个 掘金热榜 的插件,只提供了:优质作者榜、掘金文章榜和文章收藏榜。 明显满足不了我们的需求,那就自己造噜,?? 看过我文章的都知道,Coze里自己搞 数据源 的两种玩法: 自定义插件调接口,但只支持json格式的返回数据;工作流代码节点 里用 requests_async库 写爬虫模拟请求;掘金的api网上还挺多,Github上就有好些,这里还是自己抓,授之于渔嘛~ 2.1. 用户信息浏览器F12进 开发者模式,开下抓包,随便输入个人主页的url,如:https://juejin.cn/user/4142615541321928,加载完随手搜下 掘力值 对应的数字,定位到下述接口: ?? 简单爬取原则:优先选 没有加密参数 + 有所需数据 的接口,后面三个返回Json的接口都有加密参数: ?? 那就只能 代码节点模拟请求爬页面html + 正则 提取目标数据了,直接新建一个工作流,添加一个 代码节点 开爬: importrequests_async importre fromdatetimeimportdatetime #请求头 request_headers={ "Origin":"https://juejin.cn", "Referer":"https://juejin.cn/editor/drafts/new?v=2", "User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/122.0.0.0Safari/537.36" } #用户信息类 classUserInfo: def__init__(self,user_name=None,description=None,register_time=None,follower_count=None, post_article_count=None,got_digg_count=None,got_view_count=None,article_list=None): self.user_name=user_name self.description=description self.register_time=register_time self.follower_count=follower_count self.post_article_count=post_article_count self.got_digg_count=got_digg_count self.got_view_count=got_view_count self.article_list=article_listifarticle_listelse[] def__str__(self): return"作者名:{},作者描述:{},注册时间:{},粉丝数:{},文章数:{},获得点赞数:{},获得阅读数:{},文章列表:{}".format( self.user_name,self.description,self.register_time,self.follower_count,self.post_article_count, self.got_digg_count,self.got_view_count,self.article_list) defto_json(self): return{ "user_name":self.user_name, "description":self.description, "register_time":self.register_time, "follower_count":self.follower_count, "post_article_count":self.post_article_count, "got_digg_count":self.got_digg_count, "got_view_count":self.got_view_count, "article_list":[] } #提取输入url中的用户信息 asyncdeffetch_user_info(user_url): #获取作者名的正则 author_name_pattern=re.compile(r'title(.*?)的个人主页',re.S) #请求用户主页 resp=awaitrequests_async.get(user_url,headers=request_headers) content=resp.text #提取作者名称 author_result=author_name_pattern.search(content) ifauthor_result: #获取作者名 user_name=author_result.group(1) #拼接获取用户信息的正则 user_info_patter_str=r'user_name:"{}".*?'.format( user_name)+r'description:"(.*?)",.*?register_time:(\d+).*?follower_count:(\d+),post_article_count:('\ r'\d+).*?got_digg_count:(\d+),got_view_count:(\d+)' user_info_pattern=re.compile(user_info_patter_str,re.S) #提取匹配的用户信息,只要第一个匹配结果 results=user_info_pattern.findall(content) ifresultsandlen(results)0: user_info=UserInfo() user_info.user_name=user_name user_info.description=results[0][0] user_info.register_time=datetime.fromtimestamp(int(results[0][1])).strftime('%Y-%m-%d%H:%M:%S') user_info.follower_count=results[0][2] user_info.post_article_count=results[0][3] user_info.got_digg_count=results[0][4] user_info.got_view_count=results[0][5] returnuser_info.to_json() else: returnNone asyncdefmain(args:Args)-Output: params=args.params #写死一个url调用试试看 result=awaitfetch_user_info("https://juejin.cn/user/4142615541321928") ret:Output={ "result":resultifresultelse{} } returnret 测试代码 处点击 运行,输出结果如下: ?? Nice,该拿的信息都拿到了,接着搞下文章信息~ 2.2. 文章信息在个人主页,点击 文章 的Tab,下拉加载更多看请求,不难看出这就是 目标接口: 看下请求参数: 阔以,木有加密,试下了uuid是可以不填的,咦,?? 返回数据是json的话,是不是能 自定义插件?试试?新建插件,添加下述请求参数: 保存并接续,点击自动解析生成输出参数,保存并继续,试下输入参数: ?? 并不太行,又尝试了一下,设置请求头里的 Content-Type 为 application/json,指定传递的数据编码为JSON格式,结果还是不行。试下 代码节点 模拟请求: asyncdeffetch_article_infos(): resp=awaitrequests_async.post("https://api.juejin.cn/content_api/v1/article/query_list", json={"user_id":"4142615541321928","sort_type":2,"cursor":"0"}) returnresp.json() asyncdefmain(args:Args)-Output: params=args.params result=awaitfetch_article_infos() ret:Output={ "result":str(result) } returnret 运行输出结果: 好吧,可以,??em... 也不知道是扣子的插件POST不支持JSON数据只支持表单数据,还是我的用法不对。算咯,直接写代码爬: importrequests_async importre importtime #请求头 request_headers={ "Origin":"https://juejin.cn", "Referer":"https://juejin.cn/editor/drafts/new?v=2", "User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/122.0.0.0Safari/537.36" } #文章信息类 classArticleInfo: def__init__(self,title=None,brief_content=None,view_count=0,collect_count=0,digg_count=0, comment_count=0,tags=None,link_url=None): self.title=title self.brief_content=brief_content self.view_count=view_count self.collect_count=collect_count self.digg_count=digg_count self.comment_count=comment_count self.tags=tags self.link_url=link_url def__str__(self): return"文章标题:{},文章简介:{},阅读数:{},收藏数:{},点赞数:{},评论数:{},标签:{},文章链接:{}".format( self.title,self.brief_content,self.view_count,self.collect_count,self.digg_count,self.comment_count, self.tags,self.link_url) defto_json(self): return{ "title":self.title, "brief_content":self.brief_content, "view_count":self.view_count, "collect_count":self.collect_count, "digg_count":self.digg_count, "comment_count":self.comment_count, "tags":self.tagsifself.tagselse[], "link_url":self.link_url } #爬取作者的文章列表 asyncdeffetch_article_infos(user_url): #正则提取下user_id user_id_result=re.search(r"(\d+)",user_url) ifuser_id_result: user_id=user_id_result.group(1) cursor=0 article_info_list=[] #死循环,当返回的条数少于10条时跳出循环 whileTrue: #虚假的休眠防封 time.sleep(2) #拼接请求的json request_json={"user_id":user_id,"sort_type":2,"cursor":str(cursor)} resp=awaitrequests_async.post("https://api.juejin.cn/content_api/v1/article/query_list",headers=request_headers,json=request_json) ifresp: article_info=resp.json() ifarticle_infoandarticle_info["data"]: #遍历提取文章数据 forarticleinarticle_info["data"]: article_info_list.append( ArticleInfo(title=article["article_info"]["title"], brief_content=article["article_info"]["brief_content"], view_count=article["article_info"]["view_count"], collect_count=article["article_info"]["collect_count"], digg_count=article["article_info"]["digg_count"], comment_count=article["article_info"]["comment_count"], tags=list(map(lambdax:x["tag_name"],article["tags"])), link_url="https://juejin.im/post/"+article["article_id"]).to_json()) #长度少于10跳出死循环 iflen(article_info["data"])10: break #否则游标+10 else: cursor+=10 else: break else: break returnarticle_info_list asyncdefmain(args:Args)-Output: params=args.params result=awaitfetch_article_infos("https://juejin.cn/user/3178040962848480/posts") ret:Output={ "result":resultifresultelse[] } returnret 运行看下输出结果: ?? Nice,数据同样拿到了~ 2.3. 并行爬取??上面通过死循环的方式获取作者的所有文章,存在一个问题,当作者文章比较多时,比如 200篇,需要循环执行20次,而单次休眠2s,假设请求和响应的时间为2s,那么完成所有请求,需要至少80s,即1分20秒。这样玩大概率的输出结果会是:节点响应超时。扣子应该是为每个节点设置了一个最长响应事件,超过多久没返回结果,就认为节点任务执行失败。 ?? 所以,我们需要将 爬取任务队列 拆分成几个,然后复制粘贴多个上述 代码节点,充分利用工作流支持多个节点 并行 的特性,然后追加一个代码节点,对数据进行汇总。爬取作者信息那个代码节点加五个输出参数: 写个简单的循环生成cursor参数列表,右侧是点击运行后的输出结果: 接着修改下爬取文章信息的结点,入参和代码做下调整,然后运行试试看: 行吧,拿到数据了,接着复制粘贴三个,改下入参,并追加一个代码节点,用于整个四个节点的返回数据: asyncdefmain(args:Args)-Output: params=args.params first_article_info_list=params["first_article_info_list"] second_article_info_list=params["second_article_info_list"] third_article_info_list=params["third_article_info_list"] forth_article_info_list=params["forth_article_info_list"] #合并四个数组中的数据 article_info_list=[] article_info_list.extend(first_article_info_list) article_info_list.extend(second_article_info_list) article_info_list.extend(third_article_info_list) article_info_list.extend(forth_article_info_list) ret:Output={ "article_info_list":article_info_list, } returnret 最终的工作流如下: 点击试运行,输入作者的主页url,然后看下输出结果: ?? Nice,作者的176篇文章信息都成功获取到啦,而且整体耗时也才4s~ 3. 处理数据3.1. 生成作者画像这里本来想用 云雀大模型 的,折腾了近一个小时的 提示词,一直 答非所问,实在是太拉跨了??: 无奈,只能试试其它的模型了,试了下国产AI-智谱AI****,输出结果还算可以,新注册+实名送500w Token~ 应该能玩几下吧,直接新起一个代码节点,直接HTTP调用的方式调它的API,扣子的节点竟然不支持 jwt 库,只能调内置的 hmac、base64、hashlib 库来生成鉴权Token,这部直接让GPT代劳,最终写出模拟请求代码~ importrequests_async importhmac importjson importtime importbase64 importhashlib #生成鉴权Token defgenerate_token(apikey:str,exp_seconds:int): try: kid,secret=apikey.split(".") exceptExceptionase: raiseException("invalidapikey",e) #Header header={ "alg":"HS256", "sign_type":"SIGN" } #Payload payload={ "api_key":kid, "exp":int(round(time.time()*1000))+exp_seconds*1000, "timestamp":int(round(time.time()*1000)), } #EncodeHeader header_encoded=base64.urlsafe_b64encode(json.dumps(header).encode()).decode().rstrip('=') #EncodePayload payload_encoded=base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip('=') #CreateSignature to_sign=f'{header_encoded}.{payload_encoded}'.encode() signature=hmac.new(secret.encode(),to_sign,hashlib.sha256) signature_encoded=base64.urlsafe_b64encode(signature.digest()).decode().rstrip('=') #CreateJWT jwt_token=f'{header_encoded}.{payload_encoded}.{signature_encoded}' returnjwt_token asyncdefmain(args:Args)-Output: params=args.params secret_key="智谱AI的Key" input_content=params['input_content'] ai_response=awaitrequests_async.post("https://open.bigmodel.cn/api/paas/v4/chat/completions",headers={ "Content-Type":"application/json", "Authorization":"Bearer"+generate_token(secret_key,60) },data=json.dumps({ "model":"glm-3-turbo", "stream":False, "messages":[ { "role":"user", "content":"基于以下文章摘要列表,请你分析并生成一个尽可能准确的作者画像,不要超过200个字。请考虑作者的写作风格、专业知识领域等方面。{}".format(input_content) } ] })) result_content=ai_response.json()['choices'][0]['message']['content'] ret:Output={ "result":result_content, } returnret 运行看下输出结果: 卧槽,牛批,毕竟当前 国产第一梯队的AI!!!强无敌,对比之下的 云雀: ?? 生成作者画像 这部分算是拿捏了,接着处理下其它数据~ 3.2. 擅长领域这部分就是遍历文章列表,统计标签然后计算百分比啥的,比较简单,直接写出处理代码: importoperator asyncdefmain(args:Args)-Output: params=args.params article_list=params["input"] #文章总数 article_count=len(article_list) #标签计数字典 tag_count_dict={} #遍历所有文章,根据tag进行计数 forarticleinarticle_list: fortaginarticle["tags"]: tag_count=0 iftagintag_count_dict: tag_count=tag_count_dict[tag] tag_count_dict[tag]=tag_count+1/len(article["tags"])/article_count #字典按照降序排列成新的列表 sorted_list=sorted(tag_count_dict.items(),key=operator.itemgetter(1),reverse=True) result_list=[] #判断列表长度是否5,是截取游标4后的元素进行合并 iflen(sorted_list)5: end_list=sorted_list[4:] percent=0.0 forelementinend_list: percent+=element[1] result_list.extend(sorted_list[:4]) result_list.append(("其它",percent)) else: result_list=sorted_list #输出字符串拼接 result_content="?TA擅长的领域:\n" forpos,elementinenumerate(result_list): result_content+="-{}、{}({}%,{}篇)\n".format(pos+1,element[0],format(element[1]*100,'.2f'),format(element[1]*article_count,'.2f')) ret:Output={ "result":result_content, } returnret 运行输出结果: ?? Tips:这里篇数为小数的原因:一篇文章能有多个标签,比如三个,单个标签的权重就是0.33~ 3.3. 最热文章?? 这边不知道掘金文章的 热度值计算公式,那就根据自己的感觉来拟咯~ H(热度值) = 0.15 * R(阅读量)/100 + 0.25 * L(点赞量) + 0.35 * C(评论量) + 0.25 * F(收藏量) 接着就是遍历文章列表,然后套公式算每篇文章的热力值,最后排序筛出前10篇文章,格式化输出~ importoperator asyncdefmain(args:Args)-Output: params=args.params article_list=params["input"] #文章计数字典 article_count_dict={} forarticleinarticle_list: score=(article["view_count"]/100*0.15 +article["digg_count"]*0.25 +article["comment_count"]*0.35 +article["collect_count"]*0.25) article_count_dict["[《{}》-{}]({})".format(article["title"],score,article["link_url"])]=score #按照value降序排列 sorted_list=sorted(article_count_dict.items(),key=operator.itemgetter(1),reverse=True) #字符串拼接,只取前十 result_content="??TA热度最高的文章:\n" forresultinsorted_list[:10]: result_content+="-{}\n".format(result) ret:Output={ "result":result_content, } returnret 运行输出结果如下: ?? 行吧,到此就把数据都处理完了~ 4. 汇总输出?? 最后就是各种微调,然后汇总输出了,调整下用户画像那里,追加下返回头: user_info=params["user_info"] result_content="??【{}】于【{}】加入掘金,共计发布了【{}】篇文章,收获了???♂?x{}|??x{}|??x{}|??x{},它的作者画像:\n\n{}\n\n".format( user_info["user_name"],user_info["register_time"],user_info["post_article_count"],user_info["follower_count"], user_info["got_digg_count"],user_info["got_view_count"],user_info["jpower"],ai_response.json()['choices'][0]['message']['content'] ) 结束结点直接汇总下三个结果合并输出: 试运行后,输入笔者的主页链接,最终输出结果如下: ??【coder_pig】于【2016-04-11 09:18:44】加入掘金,共计发布了【176】篇文章,收获了???♂?x10329|??x7787|??x814304|??x29071,它的作者画像: 根据文章摘要列表,作者是一位技术博客作者,主要关注移动应用开发,特别是Android和Flutter技术。作者对移动应用开发有深入了解,擅长使用各种技术和工具进行应用开发和自动化,如AccessibilityService、Xposed、爬虫技术等。此外,作者还关注代码优化、性能提升以及各种编程语言和技术的学习,如Python、Java、Kotlin、Dart等。文章风格幽默风趣,语言通俗易懂,适合初学者和有一定基础的开发者阅读。 ? TA擅长的领域: - 1、Python (20.50%, 36.08篇) - 2、Android (17.19%, 30.25篇) - 3、架构 (6.49%, 11.42篇) - 4、设计模式 (6.06%, 10.67篇) - 5、其它 (49.76%, 87.58篇) ?? TA热度最高的文章: - [《因一纸设计稿,我把竞品APP扒得裤衩不剩(上)》-274.3755](https://juejin.im/post/6844903989603991565) - [《纳尼?我的Gradle build编译只要1s》-232.4535](https://juejin.im/post/6844903728282091527) - [《忘了他吧!我偷别人APP的代码养你》-219.6495](https://juejin.im/post/6844903904547700743) - [《补齐Android技能树 - 从害怕到玩转Android代码混淆》-208.29500000000002](https://juejin.im/post/6966526844552085512) - [《我写小程序像菜虚鲲——1、唱,跳,rap,篮球》-170.143](https://juejin.im/post/6844903862533373959) - [《【杰哥带你玩转Android自动化】学穿:ADB》-156.187](https://juejin.im/post/7147631074183479303) - [《换个姿势,带着问题看Handler》-146.39350000000002](https://juejin.im/post/6844904150140977165) - [《??补齐Android技能树——从AGP构建过程到APK打包过程》-136.60899999999998](https://juejin.im/post/6963527524609425415) - [《浅谈"李跳跳"停更 & 简单七步跳过Android开屏广告》-132.633](https://juejin.im/post/7272735633457086498) - [《逮虾户!Android程序调试竟简单如斯》-117.2555](https://juejin.im/post/6844903733088747528) 卧槽,屌啊,此处应该有掌声?????? 5. 发布Bot到掘金2333,工作流写完,才发现自己还建Bot,直接新建一个 掘金作者画像 的Bot,随便写下功能介绍: 随便写两句提示词,接着AI润色下,自己调整一波,主要是检测到用户输入了url而且包含 https://juejin.cn/user/ 就调工作流: 接着同样AI生成下开场白文案,预设问题随便填两个url: 点击其中一个试试看~ 2333,哈哈哈,??这作者画像... 行吧,接着把Bot发布到 掘金,如果前面的打钩是不可点,配置然后授权就好了~ 稍等片刻,成功提交发布后,点击 立即对话: 跳转页面后,随便输入一个作者的主页: 因为沸点要 审核,所以等了一会儿机器人的评论才放出来,评论不支持md,这稀烂的排版??... 然后豆包和飞书都是正常的~ 行吧,以上就是本节的全部内容,应该是目前写过复杂度最高的Bot了,赶紧来 @掘金作者画像 试试吧??~ 阅读原文

上一篇:2025-06-09_全画幅变焦鱼眼新纪元:老蛙8-15mm F2.8开启预售 下一篇:2021-03-24_哈佛、MIT学者联手,创下矩阵乘法运算最快纪录

TAG标签:

21
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价