【Python实战】基于Python实现博客评论区抽奖功能

Python
182
0
0
2024-05-16
标签   Python实践

前言

最近不少博主反馈,想为粉丝谋点福利,但是不知道以什么方式抽选幸运粉丝,我给他们支了个招:“可以在你的文章评论区抽选”。

但是每次都要人工介入,第一是耗时,第二是可能会带有主观意识,做不到完全公平。

这时,我又给他们支了个招:“写个程序随机抽选呗”。

所以,我这个“大聪明”就用Python编写了一个评论区抽选粉丝程序。为了秉行公平、公正、公开原则,本文会将抽选粉丝程序的思路以及代码的实现展示给大家,有需要的拿走不谢。

还有,腾讯开发者社区推出了新功能【在线运行代码块】,所以,大家在阅读文章的过程中就可以在浏览器上直接运行代码看效果了。如下图

抽选规则

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

  1. 关注了我,即成为我的粉丝。
  2. 评论一次,权重+1,最多3次。

实现思路

  1. 首先需要获取该博客文章的所有评论者。
  2. 筛选符合条件的评论者。
  • 是否为我的粉丝。
  • 评论是否符合当期要求内容(可选)。
  1. 在符合条件的粉丝中随机抽选幸运读者。

代码实现

1.获取评论数据

虽然腾讯云开发者社区不提供直接获取文章评论者的接口,但这难不倒一个开发人员。

我们可以在文章所在页面开启调试模式拿到这个接口:

https://cloud.tencent.com/developer/api/comment/nest-list,参数也清晰明了,如下:

{
    "page":1, 
    "objectId":2377595, #文章编号,https://cloud.tencent.com/developer/article/2377595
    "module":5,
    "sortField":"timeline",
    "pagesize":10
}

响应格式如下:

{
    "list":[
        {
            "beCommentUid":0,
            "channel":"",
            "commentId":...,
            "commentUid":...,
            "content":"...",
            "createTime":...,
            "from":{
                "avatarUrl":"...",
                "nickname":"...",
                "uid":...
            },
            "isLike":0,
            "likeNum":0,
            "module":5,
            "objectId":...,
            "pCommentId":0,
            "rCommentId":0,
            "status":2,
            "subComments":[

            ],
            "subObjectId":0,
            "weight":0
        },
        ....
    ],
    "total":2,
    "validTotal":2
}

接下来就可以基于Python中的requests包直接发起POST请求获取评论数据了,代码如下:

代码运行次数:2

复制

Cloud Studio 代码运行

import requests

if __name__ == '__main__':
    # 评论数据接口
    commentUrl = "https://cloud.tencent.com/developer/api/comment/nest-list"
    # 每次获取评论的数量
    pageSize = 10
    # 文章编号
    objectId=2377595
    # 评论数据接口
    data = {"page": 1, "objectId": objectId, "module": 5, "sortField": "timeline", "pagesize": pageSize}
    headers = {"Content-Type": "application/json", "User-Agent": ""}
    response = requests.post(commentUrl, json=data, headers=headers)
    # 如果请求成功,接收的响应会是一个Response对象
    if response.status_code == 200:
        # 使用json()方法将响应内容解析为JSON
        data = response.json()
        print(data)
    else:
        print("请求失败,状态码:", response.status_code)

这里输出的data就是评论数据。当然,为了实现该接口的分页功能以及代码的可读性和可重用性,这里做一下简单的封装。

代码运行次数:3

复制

Cloud Studio 代码运行

import requests


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


# 获取到所有的评论
def get_comments():
    data = {"page": 1, "objectId": objectId, "module": 5, "sortField": "timeline", "pagesize": pageSize}
    res = request(commentUrl, data)
    # 解析到总页数
    total_pages = res["total"] // pageSize
    # 解析到评论数据
    commentList = res["list"]
    assert len(commentList) > 0, "该博客没有评论数据"
    # 合并所有的评论
    commentList = commentList + [_data["list"] for _data in [request(commentUrl,
                                                                     {"page": page, "objectId": objectId, "module": 5,
                                                                      "sortField": "timeline", "pagesize": pageSize})
                                                             for page in range(2, total_pages + 2)]]
    return commentList

if __name__ == '__main__':
    # 评论数据接口
    commentUrl = "https://cloud.tencent.com/developer/api/comment/nest-list"
    # 每次获取评论的数量
    pageSize = 10
    # 文章编号
    objectId = 2383111
    print(get_comments())

如代码所示,将请求接口抽出来作为独立接口,这样,其他url的请求就可以共用了。

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

在获取到评论数据后,我们需要过滤掉不符合规则的评论者。例如,本片文章要求评论为“Java一枝花”,但是读者评论了“666”就不符合参与规则了。

现在需要评论内容和评论者这两个数据就可以完成该需求了,即评论接口响应中的contentfrom中的nickname

接下来就可以根据条件筛选评论者,评论一次权重+1。代码如下,主要关注get_comment_users()这个方法。

代码运行次数:0

复制

Cloud Studio 代码运行

import requests


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


# 获取到所有的评论
def get_comments():
    data = {"page": 1, "objectId": objectId, "module": 5, "sortField": "timeline", "pagesize": pageSize}
    res = request(commentUrl, data)
    # 解析到总页数
    total_pages = res["total"] // pageSize
    # 解析到评论数据
    commentList = res["list"]
    assert len(commentList) > 0, "该博客没有评论数据"
    # 合并所有的评论
    commentList = commentList + [_data["list"] for _data in [request(commentUrl,
                                                                     {"page": page, "objectId": objectId, "module": 5,
                                                                      "sortField": "timeline", "pagesize": pageSize})
                                                             for page in range(2, total_pages + 2)]]
    return commentList

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

if __name__ == '__main__':
    # 评论数据接口
    commentUrl = "https://cloud.tencent.com/developer/api/comment/nest-list"
    # 每次获取评论的数量
    pageSize = 10
    # 文章编号
    objectId = 2383111
    # 指定的评论内容
    needcomment=""
    get_comment_users()

commentUsers最终会输出符合要求的评论者,key为昵称,value为权重值,格式如:{'xxx': 1, 'xxx1': 3}

3.获取关注我的人

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

为什么先过滤符合要求的评论再获取关注我的人?

因为有的博主粉丝过多,如果直接获取关注我的人,那会调用很多次接口,所以直接在已有的条件下再次过滤即可。

同样,还是在页面中拿到“我的粉丝”接口:

https://cloud.tencent.com/developer/services/ajax/user-center?action=GetUserFollowers&uin=10000xxx&csrfCode=438895646

该接口中的uin为腾讯云账号id。

获取粉丝数据代码如下get_fans()方法。

代码运行次数:0

复制

Cloud Studio 代码运行

import requests


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


# 获取到所有的粉丝
def get_fans():
    data = {"action": "GetUserFollowers", "payload": {"uid": uid, "pageNumber": 1, "pageSize": 20}}
    res = request(followersUrl, data)
    # 解析到粉丝数据
    fansList = res["data"]["list"]
    fans_names = [fan["name"] for fan in fansList]
    return fans_names


if __name__ == '__main__':
    # 腾讯云账号ID
    uin = 100008382400
    # 开发者社区uid
    uid = 3981768
    # 关注我的人数据接口
    followersUrl = "https://cloud.tencent.com/developer/services/ajax/user-center?action=GetUserFollowers&uin={}&csrfCode=438895646".format(
        uin)
    print(get_fans())

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

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

代码运行次数:0

复制

Cloud Studio 代码运行

import random

import requests


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


# 获取到所有的评论
def get_comments():
    data = {"page": 1, "objectId": objectId, "module": 5, "sortField": "timeline", "pagesize": pageSize}
    res = request(commentUrl, data)
    # 解析到总页数
    total_pages = res["total"] // pageSize
    # 解析到评论数据
    commentList = res["list"]
    assert len(commentList) > 0, "该博客没有评论数据"
    # 合并所有的评论
    commentList = commentList + [_data["list"] for _data in [request(commentUrl,
                                                                     {"page": page, "objectId": objectId, "module": 5,
                                                                      "sortField": "timeline", "pagesize": pageSize})
                                                             for page in range(2, total_pages + 2)]]
    return commentList


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


# 获取到所有的粉丝
def get_fans():
    data = {"action": "GetUserFollowers", "payload": {"uid": uid, "pageNumber": 1, "pageSize": 20}}
    res = request(followersUrl, data)
    # 解析到粉丝数据
    fansList = res["data"]["list"]
    fans_names = [fan["name"] for fan in fansList]
    return fans_names


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


if __name__ == '__main__':
    # 评论数据接口
    commentUrl = "https://cloud.tencent.com/developer/api/comment/nest-list"
    # 每次获取评论的数量
    pageSize = 10
    # 文章编号
    objectId = 2383111
    # 指定的评论内容
    needcomment = ""
    # 腾讯云账号ID
    uin = 100008382400
    # 开发者社区uid
    uid = 3981768
    # 关注我的人数据接口
    followersUrl = "https://cloud.tencent.com/developer/services/ajax/user-center?action=GetUserFollowers&uin={}&csrfCode=438895646".format(
        uin)

    print("符合抽选规则的粉丝{}".format(get_satisfied_fans(get_comment_users())))

6.抽选粉丝

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

完整的代码

至此,基于Python实现博客评论区抽奖功能就完成了。

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

代码运行次数:1

复制

Cloud Studio 代码运行

import random

import requests


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


# 获取到所有的评论
def get_comments():
    data = {"page": 1, "objectId": objectId, "module": 5, "sortField": "timeline", "pagesize": pageSize}
    res = request(commentUrl, data)
    # 解析到总页数
    total_pages = res["total"] // pageSize
    # 解析到评论数据
    commentList = res["list"]
    assert len(commentList) > 0, "该博客没有评论数据"
    # 合并所有的评论
    commentList = commentList + [_data["list"] for _data in [request(commentUrl,
                                                                     {"page": page, "objectId": objectId, "module": 5,
                                                                      "sortField": "timeline", "pagesize": pageSize})
                                                             for page in range(2, total_pages + 2)]]
    return commentList


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


# 获取到所有的粉丝
def get_fans(page):
    data = {"action": "GetUserFollowers", "payload": {"uid": uid, "pageNumber": page, "pageSize": pageSize}}
    res = request(followersUrl, data)
    # 粉丝数据
    fansList = res["data"]["list"]
    # 粉丝页数
    totalPage = (res["data"]["total"] // pageSize)+1
    fans_names = [fan["name"] for fan in fansList]
    return None if totalPage == page else page+1 , fans_names


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


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


# 符合抽选规则的粉丝
def satisfied_fans():
    satisfiedFans = {}
    commentUsers = get_comment_users()
    assert commentUsers, "没有符合条件的评论者"
    fanId = 1
    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 select_fans():
    try:
        fans = satisfied_fans()
        assert fans, "没有符合抽选规则的粉丝"
        print("——————开始抽选粉丝——————")
        for i in range(1, (selectCount if len(fans) >= selectCount else len(fans))+1):
            luckfans = weighted_random_choice(list(fans.keys()), list(fans.values()))
            # 移除该粉丝
            fans.pop(luckfans)
            print("恭喜第{}为幸运粉丝:{}".format(i, luckfans))

    except Exception as e:
        print(e)


if __name__ == '__main__':
    # 评论数据接口
    commentUrl = "https://cloud.tencent.com/developer/api/comment/nest-list"
    # 每次获取评论的数量
    pageSize = 10
    # 文章编号
    objectId = 2382339
    # 指定的评论内容
    needcomment = ""
    # 腾讯云账号ID
    uin = 100008382400
    # 开发者社区uid
    uid = 3981768
    # 关注我的人数据接口
    followersUrl = "https://cloud.tencent.com/developer/services/ajax/user-center?action=GetUserFollowers&uin={}&csrfCode=438895646".format(
        uin)
    # 抽选粉丝个数
    selectCount = 3
    select_fans()

效果展示

执行代码中的使用示例后结果如下图,如果粉丝过于多,可能需要等待数秒。

好了,大家快去试试吧。

结语

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