如何实现CSDN评论区粉丝幸运抽选功能:一场代码与运气的碰撞

news2024/11/24 18:59:19

文章目录

  • 前言
  • 抽选规则
  • 实现思路
  • 代码实现
    • 1.获取评论数据
    • 2.过滤符合抽选规则的评论者
    • 3.获取粉丝数据
    • 4.过滤符合抽选规则的粉丝
    • 5.增加公众号留言权重
    • 6.抽选粉丝
  • 完整的代码
  • 效果展示
  • 结语

前言

为了回馈粉丝们一直以来的的关注和支持,我近期开启了赠书活动,活动期间会在每一期的文章评论中随机抽选几位粉丝赠送本期书籍。为了确保绝对的公平,我借鉴了@东离与糖宝的想法,编写了一个评论区抽选粉丝程序。秉行公平、公正、公开原则,本文会将抽选粉丝程序的思路以及代码的实现展示给大家。

抽选规则

抽选评论区中的粉丝要符合以下条件:

  1. 关注了我的博客,即成为我的粉丝。
  2. 评论一次权重+1,最多3次,评论内容见当期参与方式。

同时,关注公众号并留言权重+3,留言内容见当期参与方式。

活动见赠书专栏

实现思路

  1. 首先需要获取该博客文章的所有评论者。
  2. 筛选符合条件的评论者。
    • 是否为我的粉丝。
    • 是否评论当期要求内容(可选)。
  3. 对于既是当期内容评论者又是公众号的粉丝,给予更高的权重值。
  4. 在符合条件的粉丝中随机抽选幸运读者。

代码实现

1.获取评论数据

虽然CSDN不提供直接获取文章评论者的接口,但这难不倒一个开发人员。我们可以在文章所在页面开启调试模式拿到这个接口:https://blog.csdn.net/phoenix/web/v1/comment/list/132678231?page=1&size=20,参数清晰明了,响应格式如下:

{
    "code":200,
    "message":"success",
    "traceId":"b3e6eb62-396d-4289-a937-710767e68680",
    "data":{
        "count":86,
        "pageCount":83,
        "floorCount":83,
        "foldCount":1,
        "list":[
            {
                "info":{
                    "commentId":28613264,
                    "articleId":132678231,
                    "parentId":0,
                    "postTime":"2023-09-09 16:16:10",
                    "content":"这里是评论内容",
                    "userName":"qq_28314431",
                    "digg":0,
                    "diggArr":[

                    ],
                    "loginUserDigg":false,
                    "parentUserName":"qq_28314431",
                    "parentNickName":"叫我二蛋",
                    "avatar":"https://profile-avatar.csdnimg.cn/55e249ffc0b54ab287ecde8615968cca_qq_28314431.jpg!1",
                    "nickName":"这里是用户昵称",
                    "dateFormat":"前天 16:16",
                    "years":8,
                    "vip":true,
                    "vipIcon":"https://img-home.csdnimg.cn/images/20210121052537.png",
                    "vipUrl":"https://mall.csdn.net/vip",
                    "companyBlog":false,
                    "companyBlogIcon":"",
                    "flag":false,
                    "flagIcon":"",
                    "levelIcon":"https://csdnimg.cn/identity/blog6.png",
                    "commentFromTypeResult":{
                        "index":1,
                        "key":"pc",
                        "title":"PC"
                    },
                    "isTop":true,
                    "isBlack":false,
                    "region":"IP:陕西省",
                    "orderNo":"",
                    "redEnvelopeInfo":null
                },
                "sub":[

                ],
                "pointCommentId":null
            }
        ]
    }
}

这里基于Python直接发起POST请求获取评论数据,代码如下:

import requests
commentUrl = "https://blog.csdn.net/phoenix/web/v1/comment/list/132678231?page=1&size=20"
# 发送Post请求
headers = {"User-Agent": ""}
response = requests.get(commentUrl,headers=headers)
# 如果请求成功,接收的响应会是一个Response对象
if response.status_code == 200:
    # 使用json()方法将响应内容解析为JSON
    data = response.json()
    print(data)
else:
    print("请求失败,状态码:", response.status_code)

2.过滤符合抽选规则的评论者

获取的评论数据中我们只需要评论内容和评论者昵称这两个数据,及字段content、nickName,接下来就可以根据条件筛选评论者,并且评论一次权重+1,代码如下:

commentList = data["data"]["list"]
commentUsers={}
    for item in commentList:
        nickName = item["info"]["nickName"]
        content = item["info"]["content"]
        if needcomment in content:
            commentCount=commentUsers.get(nickName)
            if commentCount is None:
                commentUsers[nickName]=1;
            else:
                commentUsers[nickName]=commentCount+1;

commentUsers最终会输出一个字典类型,key为昵称,value为权重值,格式如:{'EmotionFlying': 1, '小 王': 1}

符合条件的评论者筛选出来后要确定是否为我的粉丝,不是的话将其从commentUsers移除。

3.获取粉丝数据

同样,还是在页面中拿到“我的粉丝”接口:https://mp-action.csdn.net/interact/wrapper/pc/fans/v1/api/getFansOffsetList?pageSize=500&username=qq_28314431&fanId=,该接口中的fanId可以理解为‘page’页码,每次请求成功后会返回下一个fanId。获取粉丝数据代码如下:

import requests
fanUrl = "https://mp-action.csdn.net/interact/wrapper/pc/fans/v1/api/getFansOffsetList?pageSize=500&username=qq_28314431&fanId="
# 发送Post请求
headers = {"User-Agent": ""}
response = requests.get(fanUrl,headers=headers)
# 如果请求成功,接收的响应会是一个Response对象
if response.status_code == 200:
    # 使用json()方法将响应内容解析为JSON
    data = response.json()
    print(data)
else:
    print("请求失败,状态码:", response.status_code)

4.过滤符合抽选规则的粉丝

在获取到粉丝后,将commentUsers中不在粉丝列表的数据移除就好,代码如下:

fansNickname = list(set([d['nickname'] for d in fansList]) & set(list(commentUsers.keys())))

fans = {nickname: commentUsers.pop(nickname) for nickname in fansNickname}

fans 就是符合抽选规则的粉丝。

5.增加公众号留言权重

对于公众号留言的粉丝,需要手动将他们的昵称作为一个参数传入程序中,直接遍历fans,增加其权重,代码如下

gzhfans=["粉丝1","粉丝2"]
gzhfans = [fan for fan in gzhfans if fan in fans and isinstance(fans[fan], int)]
fans = fans | {fan: fans[fan] + 3 for fan in gzhfans}

fans 就是最终抽选粉丝的集合数据。

6.抽选粉丝

最后,就可以基于fans随机抽选粉丝了,这里用python 自带的random.choices随机方法,代码如下:

random.choices(list(fans.keys()), weights=list(fans.values()))[0]

完整的代码

由于接口中存在分页问题,同时为了提高代码的可读性和可用性,我对剩余的代码进行了完善,以下是完善后的代码:

import sys
import random
import requests

'''
介绍
    - 该脚本用来随机抽选评论区粉丝
使用方法: 
    - python3 selectFans.py
    - blogID: 博客ID
    - bloggerID: 博主ID
    - selectCount:抽选粉丝个数
    - needcomment: 符合的评论内容
    - gzhfans: 公众号留言的粉丝,添加权重
依赖:
    - python3
    - random
    - requests
'''

# 评论数据接口
commentUrlT = "https://blog.csdn.net/phoenix/web/v1/comment/list/{}?page={}&size={}"
# 每次获取接口数据的数量,csdn的上限
pageSize = 500
# 粉丝数据接口
fansUrlT = "https://mp-action.csdn.net/interact/wrapper/pc/fans/v1/api/getFansOffsetList?pageSize={}&username={}&fanId={}"


# 抽选粉丝
def select_fans():
    try:
        fans = satisfied_fans()
        assert fans, "没有符合抽选规则的粉丝"
        add_weight(fans, gzhfans);
        print("——————开始抽选粉丝——————")
        for i in range(1, selectCount + 1):
            luckfans = weighted_random_choice(list(fans.keys()), list(fans.values()))
            # 移除该粉丝
            fans.pop(luckfans)
            print("恭喜第{}为幸运粉丝:{}".format(i, luckfans))

    except Exception as e:
        print(e)


# 添加公众号留言粉丝的权重
def add_weight(fans, gzhfans):
    print("——————添加公众号留言粉丝的权重——————")
    if gzhfans:
        gzhfans = [fan for fan in gzhfans if fan in fans and isinstance(fans[fan], int)]
        fans = fans | {fan: fans[fan] + 3 for fan in gzhfans}
        print("权重增加后的粉丝:{}".format(fans))
    else:
        print("没有公众号留言的粉丝")


# 符合抽选规则的粉丝
def satisfied_fans():
    satisfiedFans = {}
    commentUsers = get_comment_users()
    assert commentUsers, "没有符合条件的评论者"
    fanId = ""
    one = True;
    # 如果是第一次或者 fanId 有值 ,并且评论者未被移除完,继续筛选。
    while one or (fanId is not None and commentUsers):
        one = False
        fanId, fans = get_satisfied_fans(commentUsers, fanId)
        satisfiedFans = satisfiedFans | fans

    print("符合抽选规则的粉丝:{}".format(satisfiedFans))
    return satisfiedFans


# 获取符合抽选规则的粉丝
def get_satisfied_fans(commentUsers, fanId):
    fanId, fansList = get_fans(fanId)
    # 在粉丝列表中的评论者
    fansNickname = list(set([d['nickname'] for d in fansList]) & set(list(commentUsers.keys())))
    # 移除并返回commentUsers的粉丝
    return fanId, {nickname: commentUsers.pop(nickname) for nickname in fansNickname}


# 获取符合条件的评论者
def get_comment_users():
    commentUsers = {}
    for item in get_comments():
        # 解析评论者ID
        userName = item["info"]["userName"]
        if userName == bloggerID:
            continue
        # 解析评论者
        nickName = item["info"]["nickName"]
        # 解析评论内容
        content = item["info"]["content"]
        # 判断评论内容是否符合要求
        if len(needcomment) == 0 or needcomment in content:
            commentCount = commentUsers.get(nickName)
            # 组装评论者及其权重
            if commentCount is None:
                commentUsers[nickName] = 1
            else:
                if commentUsers[nickName] < 3:
                    commentUsers[nickName] = commentCount + 1
    print("符合条件的评论者{}".format(commentUsers))
    return commentUsers


# 获取到所有的评论
def get_comments():
    commentUrl = commentUrlT.format(1, pageSize)
    data = request(commentUrl)
    # 解析到总页数
    total_pages = data["data"]["pageCount"]
    # 解析到评论数据
    commentList = data["data"]["list"]
    assert len(commentList) > 0, "该博客没有评论数据"
    for page in range(2, total_pages + 1):
        commentUrl = commentUrlT.format(page, pageSize)
        _data = request(commentUrl)
        _commentList = _data["data"]["list"]
        # 将所有评论数据合并
        commentList = commentList + _commentList
    return commentList


# 获取到所有的粉丝
def get_fans(fanId):
    fansUrl = fansUrlT.format(fanId)
    data = request(fansUrl)
    # 解析到下一fanId
    fanId = data["data"]["fanId"]
    # 解析到粉丝数据
    fansList = data["data"]["list"]
    return fanId, fansList


# 调用接口获取数据
def request(url):
    headers = {"User-Agent": ""}
    response = requests.get(url, headers=headers)
    # 如果请求成功,接收的响应会是一个Response对象
    if response.status_code == 200:
        # 使用json()方法将响应内容解析为JSON
        return response.json()
    else:
        print("请求失败,状态码:", response.status_code)


def weighted_random_choice(choices, weights):
    return random.choices(choices, weights=weights)[0]


if __name__ == '__main__':
    # 博客ID
    blogID = input("博客ID:")
    # 博主ID
    bloggerID = input("博主ID:")
    # 抽选粉丝个数
    selectCount = int(input("抽选粉丝个数:"))
    # 符合的评论内容
    needcomment = input("符合的评论内容(不填写则不对评论内容有要求):")
    # 公众号留言的粉丝
    gzhfans = input("公众号留言的粉丝,可以为空,以','分隔:").split()
    # 评论数据接口
    commentUrlT = commentUrlT.format(blogID, "{}", "{}")
    # 粉丝数据接口
    fansUrlT = fansUrlT.format(
        pageSize, bloggerID, "{}")

    select_fans()

效果展示

执行代码中的使用示例后结果如下图,如果粉丝过于多,可能需要等待数秒,因为粉丝接口一次最多只能读500条,希望官方看到后可以为我们开个口子😁。

在这里插入图片描述

结语

为了方便大家的使用,我已将程序打包成可执行文件,支持Windows和Mac系统,需要的可以联系博主获取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1004293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 Nginx 实现企业微信域名配置中的校验文件跳转

背景 在企业微信中配置业务域名时&#xff0c;通常需要在该域名的根路径下放置一个校验文件&#xff0c;以验证域名的所有权。然而&#xff0c;如果该域名是第三方的&#xff0c;你可能无法直接在根路径下放置文件。在这种情况下&#xff0c;你可以使用 Nginx 来实现校验文件的…

软件测试/测试开发丨使用ChatGPT自动进行需求分析

简介 在实际工作过程中&#xff0c;常常需要拿到产品的PRD文档或者原型图进行需求分析&#xff0c;为产品的功能设计和优化提供建议。 而使用ChatGPT可以很好地帮助分析和整理用户需求。 实践演练 接下来&#xff0c;需要使用ChatGPT 辅助我们完成需求分析的任务 注意&…

pgsql操作json类型

目录 一、表结构 二、实体类 三、json处理器 四、配置文件 五、josn数据 1、插入 2、查找 一、表结构 CREATE TABLE "public"."pg_user" ("id" int8 NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 MINVALUE 1 MAXVALUE 92233720…

肖sir__mysql之navicat安装__003

navicat 工具 一、navicat 介绍 &#xff1a;Navicat是一套可创建多个连接的数据库管理工具&#xff0c;用以方便管理 MySQL&#xff0c;创建、管理和维护数据库 二、navicat安装 1、安装包 2、查看navicat中安装包&#xff0c;并创建快捷方式 3、创建快捷键图标&#xff1a…

Vue3 学习-组件通讯(二)

文章目录 前言一、props通信二、自定义事件&#xff08;emit&#xff09;三、全局事件总线(EventBus)四、v-model五、userAttrs六、ref和$parent七、Provide与Inject八、pinia九、slot插槽总结 前言 本文主要记录Vue3的九种组件通信方式 一、props通信 子组件需要用defineProp…

MCU主频 服务器台式机主频 处理器主频那些事

几十M级别的 几百M级别的 几个G级别 早期的典型的51单片机外部接12MHz晶振&#xff0c;内部电路对12MHz的原始时钟进行12分频变成1MHz的时钟给CPU&#xff0c;所以早期典型的51内核的主频是1MHz。后来工艺改良了单片机也设计也改良了&#xff0c;CPU可以耐受的主频提升了&am…

【Unity3D】UI Toolkit数据动态绑定

1 前言 本文将实现 cvs 表格数据与 UI Toolkit 元素的动态绑定。 如果读者对 UI Toolkit 不是太了解&#xff0c;可以参考以下内容。 UI Toolkit简介UI Toolkit容器UI Toolkit元素UI Toolkit样式选择器UI Toolkit自定义元素 本文完整资源见→UI Toolkit数据动态绑定。 2 数据…

如何制作医疗科普宣传片

科普宣传片通过视觉呈现、简化浓缩、故事叙述、情感引导等手段&#xff0c;将科学知识生动地传达给观众&#xff0c;覆盖广泛的传播渠道使其影响力更大。制作医疗科普宣传片需要综合考虑目标受众、内容传递、专业性和吸引力等因素。下面是一些制作医疗科普宣传片的步骤和建议&a…

在滴滴和字节划水四年半,太真实了...

先简单交代一下吧&#xff0c;沅哥是某不知名211的本硕&#xff0c;18年毕业加入滴滴&#xff0c;之后跳槽到了头条&#xff0c;一直从事测试开发相关的工作。之前没有实习经历&#xff0c;算是四年半的工作经验吧。 这四年半之间他完成了一次晋升&#xff0c;换了一家公司&am…

【数据结构-二叉树】二叉树

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

什么是软件测试?5分钟带你快速了解!

经常有人问我&#xff0c;你的公司是做什么的&#xff1f;我回答“软件测试”&#xff0c;看着对方一脸的迷茫。何为软件测试&#xff1f;软件测试究竟测试什么&#xff1f; 一、软件测试的定义和意义 软件测试是伴随着软件工程的重要组成部分&#xff0c;是软件质量保证的重…

在python程序中用windows的icon

这个exe的弹窗功能会使用到一个ico文件&#xff0c;如图&#xff1a; 用软件GreenfishIconEditorProPortable或者使用在线软件将你需要的图片制作成windows的icon 用程序将ico文件生成文本文件 import base64picture_name "logo.ico" open_pic open("%s…

VirtualBox宿主机和虚拟机文件互传设置

一、如图1、2、3步骤&#xff0c;设置共享粘贴板和拖放为双向 二、 在启动的虚拟机设置的里面&#xff0c;安装增强插件&#xff0c;然后重启虚拟机。 三、在网络位置就可以看到了

十种数据库缓存相关的技术和机制

数据库的缓存 -- 通过将数据库中的数据或结果集保存在内存或其他快速访问的介质中&#xff0c;能够加快查询响应&#xff0c;减少对磁盘或远程服务器的访问&#xff0c;降低资源消耗。 根据缓存的位置、内容、粒度、更新方式等不同&#xff0c;数据库缓存技术有多种类型和策略。…

NAT(网络地址转换)

文章目录 一、产生背景二、公有地址和私有地址三、定义四、分类五、常用命令 首先可以看下思维导图&#xff0c;以便更好的理解接下来的内容。 一、产生背景 IPv4公网地址资源耗尽&#xff1a; 由于IPv4地址空间有限&#xff0c;公网IPv4地址资源逐渐耗尽&#xff0c;导致难以分…

图像尺寸测量仪:解析适用零部件与应用领域

图像尺寸测量仪也叫一键测量仪器&#xff0c;全自动闪测仪等&#xff0c;是一种精密二次元测量仪器。它能够精确测量各种零部件的形状和尺寸&#xff0c;核心优势在于测量大批量小型精密零部件&#xff0c;这对于质量控制和生产流程的优化至关重要。 图像尺寸测量仪适用于哪些…

简记——示波器测量上电冲击、电源纹波方法

一、示波器测量上电冲击 1、用稳压电源给电路板供电&#xff0c;在正极上串联一个20欧的电阻&#xff0c;设置示波器如下&#xff1a; 类型&#xff1a; “边沿触发”&#xff0c; 斜率&#xff1a; “上升”&#xff0c; 触发方式&#xff1a; …

工信部短信核验常见问题

1、收不到管局发送的核验短信怎么办&#xff1f; 如果你未收到管局发送的核验短信&#xff0c;请按以下信息进行排查。检查信息是否被手机管家识别为垃圾或骚扰短信被拦截&#xff0c;确认能不能正常接收其他短信。检查手机是否欠费停机。建议你将手机卡插入其他手机&#xff…

unity 接收拼接数据进行纹理替换且保存相机纹理到rtsp server(一)

1 rtsp 协议后编码解码 rtsp协议的问题就是&#xff0c;拼接完成后&#xff0c;还需要编码&#xff0c;而unity里面再需要解码&#xff0c;需要的过程多了一步编码再解码&#xff0c;大大加重了 2 rtsp 协议后轻量编码 rtsp协议使用mjpeg进行图片传输。why&#xff1f;这样做…

C++信息学奥赛1170:计算2的N次方

#include <iostream> #include <string> #include <cstring>using namespace std;int main() {int n;cin >> n; // 输入一个整数nint arr[100];memset(arr, -1, sizeof(arr)); // 将数组arr的元素初始化为-1&#xff0c;sizeof(arr)表示arr数组的字节…