前言
最近不少博主反馈,想为粉丝谋点福利,但是不知道以什么方式抽选幸运粉丝,我给他们支了个招:“可以在你的文章评论区抽选”。
但是每次都要人工介入,第一是耗时,第二是可能会带有主观意识,做不到完全公平。
这时,我又给他们支了个招:“写个程序随机抽选呗”。
所以,我这个“大聪明”就用Python编写了一个评论区抽选粉丝程序。为了秉行公平、公正、公开原则,本文会将抽选粉丝程序的思路以及代码的实现展示给大家,有需要的拿走不谢。
还有,腾讯开发者社区推出了新功能【在线运行代码块】,所以,大家在阅读文章的过程中就可以在浏览器上直接运行代码看效果了。如下图
抽选规则
抽选评论区中的粉丝要符合以下条件:
- 关注了我,即成为我的粉丝。
- 评论一次,权重+1,最多3次。
实现思路
- 首先需要获取该博客文章的所有评论者。
- 筛选符合条件的评论者。
- 是否为我的粉丝。
- 评论是否符合当期要求内容(可选)。
- 在符合条件的粉丝中随机抽选幸运读者。
代码实现
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”就不符合参与规则了。
现在需要评论内容和评论者这两个数据就可以完成该需求了,即评论接口响应中的content
和from
中的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系统,需要的可以联系博主获取。