前言

看到舍友最近对爬虫感兴趣,然后尝试写一个自动签到脚本,但是他的方案好麻烦呀,遂写一篇文章分析之。

网页分析 - 登录

首先,目标是咸鱼单机-单机游戏交流分享平台,我们需要分析他的登录机制。

F12打开浏览器的开发者工具,这里有一个小技巧,勾选保留日志,因为登录行为往往伴随页面刷新,如果不勾选保存日志,登录的具体日志就会一闪而过,不利于分析。

这登录也忒简单了吧……!没有验证码,非常nice.

登录一下看看日志具体是怎么样的。


发了一个POST请求,包含明文的username和password,然后从响应中通过“set-cookies”返回cookies信息给浏览器。

方案选型

这里有两种方法:
①我们主动存储cookies信息,然后下一次访问签到API的时候在请求头中带上

②使用requests.Session,一套搞定。

③使用selenium,模拟浏览器真实操作
这里介绍方法②。

什么是requests.Session对象?
在Python的requests库中,requests.Session对象是一个用于发送HTTP请求的实例。与直接使用requests.get()或requests.post()发送单独的请求不同,使用Session对象可以在多个请求之间保留一些状态信息,例如cookies、headers等,从而实现更高效的HTTP通信。

说白了就是,它帮我们存储cookies和header这一堆拉杂东西,极大简化代码量。哎,人生苦短,我用Python.

代码实现

import requests

# 模拟登录
session = requests.Session()
login_url = "https://www.xianyudanji.net/wp-admin/admin-ajax.php"
login_data = {
    'action': 'user_login',
    'username': '',  #用户名
    'password': '',  #密码
    'rememberme': '1'
}

response = session.post(login_url, data=login_data) #post和get的时候调用前文定义的对象就可以了
if response.status_code == 200 and '"status":"1"' in response.text:
    print("登录成功")
else:
    print("登录失败")
    exit()

现在,session对象内就已经存有了cookies等一系列信息了,我们只要继续找一下签到的方法,然后下一次继续调用session.post()或者session.get()就好。

然后是签到。

网页分析 - 签到

单击按钮后发起一个POST请求。

这里的“nonce”有点意思,大概率是一个动态变化的值,我们检查一下它是怎么来的吧。

Ctrl+F激活搜索工具,输入我们刚刚的nonce e91b5f2d29:
找到了。

代码如下:
<button class="btn btn-sm btn-info w-100 mt-3 go-user-qiandao" disabled data-nonce="e91b5f2d29" data-toggle="tooltip" data-placement="bottom" title="每日签到奖励: 0.3赞助币"><i class="fa fa-check-square-o"></i> 今日已签到</button>

我们需要使用bs库来拿到这个动态的nonce值:
qiandao_button = soup.find('button', {'class': 'go-user-qiandao'})

另外查了一下这个nonce的用途:

这是 WordPress 的安全机制之一,称为 "nonce"(数字一次性使用密码),用于防止跨站请求伪造 (CSRF) 攻击。这个值确保请求来自合法用户而非恶意脚本。nonce 值是由服务器生成的,并在页面中通过 JavaScript 提供

代码实现

from bs4 import BeautifulSoup

#...这里就是前文的内容,我省略掉了

# 获取包含签到按钮的页面
user_page = session.get('https://www.xianyudanji.net/user')

# 解析页面获取签到按钮的状态和 nonce
soup = BeautifulSoup(user_page.text, 'html.parser')
qiandao_button = soup.find('button', {'class': 'go-user-qiandao'})

# 检查签到按钮是否被禁用
if 'disabled' in qiandao_button.attrs:
    print("今日已签到,无法重复签到")
else:
    # 提取 nonce 值
    nonce = qiandao_button['data-nonce']
    print(f"获取到的 nonce 值: {nonce}")

    # 构建签到请求
    qiandao_url = "https://www.xianyudanji.net/wp-admin/admin-ajax.php"
    qiandao_data = {
        'action': 'user_qiandao',
        'nonce': nonce
    }

    # 发送签到请求
    qiandao_response = session.post(qiandao_url, data=qiandao_data)

    # 检查签到是否成功
    if qiandao_response.status_code == 200 and '"status":"1"' in qiandao_response.text:
        print("签到成功:", qiandao_response.json().get('msg'))
    else:
        print("签到失败")

结尾

最后我优化了一下,下面是成品

import requests
from bs4 import BeautifulSoup
import math

# 目标赞助币
goal_coin = 49
# 每次签到获得的赞助币
coin_per_signin = 0.3

# 模拟登录
session = requests.Session()
login_url = "https://www.xianyudanji.net/wp-admin/admin-ajax.php"
login_data = {
    'action': 'user_login',
    'username': ' ',  #用户名
    'password': ' ',  #密码
    'rememberme': '1'
}

response = session.post(login_url, data=login_data)
if response.status_code == 200 and '"status":"1"' in response.text:
    print("登录成功")
else:
    print("登录失败")
    exit()

# 获取用户页面,包含余额和签到按钮
user_page = session.get('https://www.xianyudanji.net/user/aff')

# 解析页面,获取当前余额和签到按钮状态
soup = BeautifulSoup(user_page.text, 'html.parser')

# 获取当前余额(假设余额在 badge-warning-lighten 类中)
balance_span = soup.find('span', {'class': 'badge-warning-lighten'})
if balance_span:
    current_balance = float(balance_span.text.strip())  # 提取当前余额,转换为 float 类型
    print(f"当前赞助币余额: {current_balance}")
else:
    print("无法获取当前余额")
    exit()

# 计算到达目标的剩余天数
remaining_coin = goal_coin - current_balance
if remaining_coin <= 0:
    print("已达到或超过目标金额")
else:
    remaining_days = math.ceil(remaining_coin / coin_per_signin)
    print(f"距离目标 {goal_coin} 赞助币,还需 {remaining_days} 天")

# 获取签到按钮并检查是否可以签到
qiandao_button = soup.find('button', {'class': 'go-user-qiandao'})
if 'disabled' in qiandao_button.attrs:
    print("今日已签到,无法重复签到")
else:
    # 提取 nonce 值
    nonce = qiandao_button['data-nonce']
    print(f"获取到的 nonce 值: {nonce}")

    # 构建签到请求
    qiandao_url = "https://www.xianyudanji.net/wp-admin/admin-ajax.php"
    qiandao_data = {
        'action': 'user_qiandao',
        'nonce': nonce
    }

    # 发送签到请求
    qiandao_response = session.post(qiandao_url, data=qiandao_data)

    # 检查签到是否成功
    if qiandao_response.status_code == 200 and '"status":"1"' in qiandao_response.text:
        print("签到成功:", qiandao_response.json().get('msg'))
    else:
        print("签到失败")

收获

熟悉了一下request.Session的基本使用~