Java 实现百度贴吧自动签到

简介

本文将介绍如何使用 Java 编写一个简单的百度贴吧自动签到脚本。整个流程分为以下四个步骤:
1、获取 Cookie(BDUSS)
2、获取 TBS(贴吧操作令牌)
3、获取用户关注的贴吧列表
4、对每个未签到的贴吧执行签到操作

获取Cookie

在电脑浏览器中登录百度贴吧后,打开开发者工具(F12),复制key=BDUSS的值即可。
⚠️ 注意:BDUSS 是百度账户的重要凭证,请勿泄露!

图片[1]-Java 实现百度贴吧自动签到

获取tbs

把TBS当成贴吧的token即可,每次请求都需携带。可通过以下接口获取:。

  • 接口地址:http://tieba.baidu.com/dc/common/tbs
  • 请求方式:GET
  • 必要Header:
    • Cookie: BDUSS=你的BDUSS值
var bduss = "bdussbdussbdussbdussbdussbdussbduss";
try (HttpClient client = HttpClient.newHttpClient()) {
    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("http://tieba.baidu.com/dc/common/tbs"))
            //重要
            .header("Cookie", String.format("BDUSS=%s", bduss))
            .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36")
            .header("charset", "UTF-8")
            .GET()
            .build();
    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body());
}

返回报文如下:
is_login: 1-登录,0-未登录

{"tbs":"f11a783f750c07321767707148","is_login":1}

获取关注列表

通过以下接口获取用户已关注的贴吧信息:

  • 接口地址:https://tieba.baidu.com/mo/q/newmoindex
  • 请求方式:GET
  • 必要 Header:同样需携带 BDUSS
request = HttpRequest.newBuilder()
        .uri(URI.create("https://tieba.baidu.com/mo/q/newmoindex"))
        .GET()
        .header("Cookie", String.format("BDUSS=%s", bduss))
        .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36")
        .header("charset", "UTF-8")
        .build();
response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

返回数据中的 data.like_forum 数组包含所有关注的贴吧,每个对象包含 forum_name(贴吧名)、is_sign(是否已签到)等字段。我们只需提取 forum_name 即可。

{
  "no": 0,
  "error": "success",
  "data": {
    "uid": 114514,
    "tbs": "00114514",
    "itb_tbs": "4fb2c44114514",
    "like_forum": [
      {
        "forum_name": "java",
        "user_level": "1",
        "user_exp": "11",
        "forum_id": 693735,
        "is_like": true,
        "favo_type": 2,
        "is_sign": 1
      }
    ],
    "ubs_sample_ids": "",
    "ubs_abtest_config": [
      {
        "sid": "hotrecommendstrategy"
      },
      {
        "sid": "topicstyle_c"
      }
    ]
  }
}

签到

签到接口比较麻烦,需构造带签名的 POST 请求:

  • 接口地址:https://tieba.baidu.com/mo/q/newmoindex
  • 请求方式:POST
  • Content-Typeapplication/x-www-form-urlencoded
  • 请求参数:
    • kw=贴吧名(URL 编码)
    • tbs=第2步的tbs
    • sign=签名(见下文)

签名规则:sign = MD5("kw=原始贴吧名tbs=你的tbs值tiebaclient!!!")

var forumName = forumMap.get("forum_name").toString();
var encodeForumName = URLEncoder.encode(forumName, StandardCharsets.UTF_8);
var sign = Md5(String.format("kw=%stbs=%stiebaclient!!!", forumName, tbs));
var signReqBody = String.format("kw=%s&tbs=%s&sign=%s", encodeForumName, tbs, sign);
request = HttpRequest.newBuilder()
        .uri(URI.create("http://c.tieba.baidu.com/c/c/forum/sign"))
        .POST(HttpRequest.BodyPublishers.ofString(signReqBody))
        .header("Cookie", String.format("BDUSS=%s", bduss))
        .header("Content-Type", "application/x-www-form-urlencoded")
        .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36")
        .header("charset", "UTF-8")
        .build();
response = client.send(request, HttpResponse.BodyHandlers.ofString());
var resSignJson = response.body();
System.out.println(resSignJson);
var resSignMap = new ObjectMapper().readValue(resSignJson, new TypeReference<HashMap<String, Object>>() {});
System.out.println(resSignMap);

返回报文如下:这是签到失败的报文,成功的报文忘了存了
✅ 当 error_code 为 "0" 时表示签到成功。

{"error_code":"110001","error_msg":"\u672a\u77e5\u9519\u8bef","info":[],"server_time":6296,"time":1767710314,"ctime":0,"logid":2314086709}

注意事项

以上几个接口偶尔会302,可增加重试机制。
请勿高频请求,避免被百度风控。
BDUSS 有效期较长,不要泄露!!
本文代码引入了Jackson 。

完整代码

代码写的很粗糙,仅为了演示使用。

package org.example;

import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;


public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {

        var bduss = "5-114514sdsddsds";

        try (HttpClient client = HttpClient.newHttpClient();) {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("http://tieba.baidu.com/dc/common/tbs"))
                    .header("Cookie", String.format("BDUSS=%s", bduss))
                    .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36")
                    .header("charset", "UTF-8")
                    .GET()
                    .build();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            var resTbsJson = response.body();
            System.out.println(resTbsJson);
            var resTbsMap = new ObjectMapper().readValue(resTbsJson, new TypeReference<HashMap<String, Object>>() {});
            var tbs = resTbsMap.get("tbs").toString();
            System.out.println(tbs);

            request = HttpRequest.newBuilder()
                    .uri(URI.create("https://tieba.baidu.com/mo/q/newmoindex"))
                    .GET()
                    .header("Cookie", String.format("BDUSS=%s", bduss))
                    .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36")
                    .header("charset", "UTF-8")
                    .build();
            response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());

            var resFollowJson = response.body();
            var resFollowMap = new ObjectMapper().readValue(resFollowJson, new TypeReference<HashMap<String, Object>>() {});
            var resFollowData = (HashMap<String, Object>) resFollowMap.get("data");
            var resFollowDataList = (ArrayList<HashMap<String, Object>>) resFollowData.get("like_forum");

            for (var forumMap : resFollowDataList) {
                var forumName = forumMap.get("forum_name").toString();
                var encodeForumName = URLEncoder.encode(forumName, StandardCharsets.UTF_8);
                var sign = Md5(String.format("kw=%stbs=%stiebaclient!!!", forumName, tbs));
                var signReqBody = String.format("kw=%s&tbs=%s&sign=%s", encodeForumName, tbs, sign);
                System.out.println(signReqBody);


                request = HttpRequest.newBuilder()
                        .uri(URI.create("http://c.tieba.baidu.com/c/c/forum/sign"))
                        .POST(HttpRequest.BodyPublishers.ofString(signReqBody))
                        .header("Cookie", String.format("BDUSS=%s", bduss))
                        .header("Content-Type", "application/x-www-form-urlencoded")
                        .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36")
                        .header("charset", "UTF-8")
                        .build();
                response = client.send(request, HttpResponse.BodyHandlers.ofString());
                var resSignJson = response.body();
                System.out.println(resSignJson);
                var resSignMap = new ObjectMapper().readValue(resSignJson, new TypeReference<HashMap<String, Object>>() {});
                System.out.println(resSignMap);
            }

        }
    }

    public static String Md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : hash) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
© 版权声明
THE END
此法若妙,愿君传于同道。
点赞10 分享
fate的头像-万宝阁