论摸鱼的那些事

首先我今天是来给大家解闷的, 推荐一个有趣的网页聊天室 - 摸鱼派 - 白与画科技,这个网页有一个聊天功能,可以愉快的跟大家摸鱼,但是目标太大

容易被boss发现,所以小编今天给大家整理了一下大家都可以用的操作来减少被发现的办法。

第一个方法

        就是官网自提供的摸鱼插件,仅限于vscodeFishPiOffical/fishpi.vsix: 摸鱼派聊天室 VSCode 扩展

第二个方法

        就是我自己写的python程序

因为是小编自己写的一个隐蔽的窗口,因为隐私的原因所以展示这么多(也就是[用户]:<p>语言</p>),因为这是在python控制台展示的所以相当隐秘,但是缺点很明显就是你在控制台输入 的时候别人发信息就会导致你换行,输错字的时候他就会删除不了

下面是代码展示:

import os
import json
import hashlib
import requests
import websocket
import time
import threading


class FishPiChatroom:
    def __init__(self, username, password, mfa_code="", cache_file="api_key.txt"):
        self.username = username
        self.password_raw = password
        self.password = hashlib.md5(password.encode()).hexdigest()
        self.mfa_code = mfa_code
        self.api_key = None
        self.ws = None
        self.base_url = "https://fishpi.cn"
        self.headers = {
            "User-Agent": "Mozilla/5.0"
        }
        self.cache_file = cache_file
        self.node_info = None
        self.reconnect_count = 0
        self.max_reconnect_attempts = 5
        self.reconnect_delay = 3

    def load_cached_api_key(self):
        if os.path.exists(self.cache_file):
            with open(self.cache_file, "r") as f:
                self.api_key = f.read().strip()
                if self.api_key:
                    print(" 使用缓存 API Key")
                    return True
        return False

    def save_api_key(self):
        with open(self.cache_file, "w") as f:
            f.write(self.api_key)

    def get_api_key(self):
        if self.load_cached_api_key():
            return True

        url = f"{self.base_url}/api/getKey"
        data = {
            "nameOrEmail": self.username,
            "userPassword": self.password
        }
        if self.mfa_code:
            data["mfaCode"] = self.mfa_code

        response = requests.post(url, json=data, headers=self.headers)
        result = response.json()

        msg = result.get("msg", "")
        if result.get("code") == 0:
            self.api_key = result.get("Key")
            self.save_api_key()
            print(f" API Key获取成功并已缓存")
            return True
        elif "频率过快" in msg:
            print(" 登录频率过快,请 5 分钟后再试")
        else:
            print(f" API Key获取失败: {msg}")
        return False

    def get_node_url(https://blog.csdn.net/self):
        if not self.api_key and not self.get_api_key():
            return None

        url = f"{self.base_url}/chat-room/node/get?apiKey={self.api_key}"
        try:
            response = requests.get(url, headers=self.headers)
            if response.status_code != 200:
                print(f" 获取节点失败: {response.status_code}")
                print(f" 响应内容: {response.text}")
                return None

            result = response.json()
            if result.get("code") == 0:
                self.node_info = result
                print(" 节点获取成功")
                return result.get("data")
            else:
                print(f" 节点错误: {result.get('msg')}")
                return None
        except Exception as e:
            print(f" 节点请求异常: {e}")
            return None

    def on_message(self, ws, message):
        try:
            data = json.loads(message)
            print(f"[{data.get('userName', '系统')}]: {data.get('content', '')}")
        except:
            print(" 消息格式错误")

    def on_error(self, ws, error):
        print(f" 连接错误: {error}")
        self.reconnect()

    def on_close(self, ws, close_status_code, close_msg):
        print(f" 连接关闭: {close_status_code} - {close_msg}")
        self.reconnect()

    def reconnect(self):
        if self.reconnect_count >= self.max_reconnect_attempts:
            print(" 达到最大重连次数")
            return
        self.reconnect_count += 1
        print(f" 正在重连({self.reconnect_count})...")
        time.sleep(self.reconnect_delay)
        self.connect()

    def connect(self):
        node_url = self.get_node_url()
        if not node_url:
            print(" 无法连接到聊天室")
            return False
        print(f" 正在连接节点: {node_url}")
        self.ws = websocket.WebSocketApp(
            node_url,
            on_open=lambda ws: print(" WebSocket连接已建立"),
            on_message=self.on_message,
            on_error=self.on_error,
            on_close=self.on_close,
            header=self.headers
        )
        threading.Thread(target=self.ws.run_forever, daemon=True).start()
        return True

    def send_message(self, content):
        if not self.api_key:
            if not self.get_api_key():
                return False
        url = f"{self.base_url}/chat-room/send"
        data = {
            "apiKey": self.api_key,
            "content": content
        }
        try:
            response = requests.post(url, json=data, headers=self.headers)
            result = response.json()
            if result.get("code") == 0:
                return True
            else:
                print(f" 发送失败: {result.get('msg')}")
        except Exception as e:
            print(f" 发送出错: {e}")
        return False

    def send_redpacket(self, count=5, value=32, msg="恭喜发财"):
        payload = {
            "msg": msg,
            "money": value,
            "count": count,
            "type": "random"
        }
        content = f"[redpacket]{json.dumps(payload)}[/redpacket]"
        return self.send_message(content)

    def close(self):
        if self.ws:
            self.ws.close()

#  加上主程序
def main():
    #  替换为你自己的用户名和密码
    username = "请输入你的账号"
    password = "请输入你的密码"

    client = FishPiChatroom(username, password)

    if not client.connect():
        print(" 无法连接到聊天室")
        return

    try:
        while True:
            msg = input("你:")
            if msg.strip().lower() == "exit":
                break
            client.send_message(msg)
    except KeyboardInterrupt:
        print("\n 已终止")
    finally:
        client.close()

#  启动入口
if __name__ == "__main__":
    main()

在请输入你的密码和请输入你的账号就是对应着网站你注册的账号和密码,切记先注册在使用哦,

Python 3.13.5

certifi            2025.7.14
charset-normalizer 3.4.2
idna               3.10
markdown-it-py     3.0.0
mdurl              0.1.2
pip                25.1.1
prompt_toolkit     3.0.51
Pygments           2.19.2
rel                0.4.9.20
requests           2.32.4
rich               14.1.0
urllib3            2.5.0
wcwidth            0.2.13
websocket-client   1.8.0

这是小编项目用到的插件

第三个方法

直接上图!!!

直接做成页面性质的,图片可能是站主有设置,我没有办法上传图片,我可以看到我发的图片但是,别人看不到,表情是可以用的

废话不多说直接上代码(环境同上):

import tkinter as tk
from tkinter.scrolledtext import ScrolledText
from tkinter import filedialog as fd
import hashlib
import requests
import websocket
import json
import time
import os
import threading
import re
from html import unescape
from datetime import datetime

# emoji 数据(可扩展)
EMOJI_LIST = [
    ("😀", "笑脸"), ("😂", "笑泪"), ("😍", "爱心眼"), ("🥺", "可怜"), ("🤔", "思考"),
    ("👍", "点赞"), ("😎", "酷"), ("😭", "大哭"), ("🎉", "庆祝"), ("🔥", "火焰"),
    ("🙌", "举手"), ("😡", "生气"), ("😴", "困"), ("😱", "惊讶"), ("😇", "天使"),
    ("🤯", "爆炸头"), ("🤮", "想吐"), ("🥳", "派对"), ("🤓", "书呆子"), ("😤", "生闷气"),
    ("💀", "笑死"), ("🤡", "小丑"), ("😈", "恶魔"), ("🤑", "发财"), ("🤗", "拥抱"),
    ("💩", "便便")
]

def strip_html_tags(html):
    # 处理 <blockquote> 引用块
    quote_parts = []

    def process_quote_block(match):
        block = match.group(1)

        # 处理图片
        block = re.sub(r'<img[^>]*src="([^"]+)"[^>]*>', lambda m: f"[图片: {m.group(1)}]", block)

        # 提取纯文本
        block = re.sub(r'<.*?>', '', block)
        block = unescape(block.strip())

        # 加前缀
        if block:
            quote_parts.append(f"【引用】{block}")
        return ""  # 移除原始引用块

    # 找出所有 blockquote 内容,并处理
    html = re.sub(r'<blockquote>(.*?)</blockquote>', process_quote_block, html, flags=re.DOTALL)

    # 处理正文中的图片
    html = re.sub(r'<img[^>]*src="([^"]+)"[^>]*>', r'[图片: \1]', html)

    # 清理剩余 HTML 标签
    html = re.sub(r'<.*?>', '', html)
    html = unescape(html.strip())

    # 合并引用和正文
    return "\n".join(quote_parts + [html]) if html else "\n".join(quote_parts)


def upload_with_fallback(file_path, retries=2, delay=2):
    def upload_to_imgurl(https://blog.csdn.net/path):
        try:
            with open(path, "rb") as img:
                res = requests.post("https://imgurl.org/api/v2/upload", files={"file": img}, timeout=10)
                data = res.json()
                if data.get("code") == 200:
                    return data["data"]["url"]
        except: return None

    def upload_to_catbox(path):
        try:
            with open(path, "rb") as img:
                res = requests.post("https://catbox.moe/user/api.php", data={"reqtype": "fileupload"},
                                    files={"fileToUpload": img}, timeout=10)
                if res.status_code == 200 and res.text.startswith("https://"):
                    return res.text.strip()
        except: return None

    def upload_to_telegra(path):
        try:
            with open(path, 'rb') as f:
                res = requests.post("https://telegra.ph/upload", files=[("file", f)], timeout=10)
                if res.status_code == 200 and isinstance(res.json(), list):
                    return "https://telegra.ph" + res.json()[0]["src"]
        except: return None

    for _ in range(retries):
        for method in [upload_to_imgurl, upload_to_catbox, upload_to_telegra]:
            url = method(file_path)
            if url:
                return url
        time.sleep(delay)
    return None

class FishPiChatroom:
    def __init__(self, username, password):
        self.username = username
        self.password = hashlib.md5(password.encode()).hexdigest()
        self.api_key = None
        self.base_url = "https://fishpi.cn"
        self.ws = None
        self.headers = {"User-Agent": "Mozilla/5.0"}

    def get_api_key(self):
        url = f"{self.base_url}/api/getKey"
        data = {"nameOrEmail": self.username, "userPassword": self.password}
        try:
            res = requests.post(url, json=data, headers=self.headers)
            if res.status_code == 200 and res.json().get("code") == 0:
                self.api_key = res.json().get("Key")
                self.user_id = res.json().get("userId")  # 保存自己的 senderId
                return True
        except:
            pass
        return False

    def get_node_url(https://blog.csdn.net/self):
        url = f"{self.base_url}/chat-room/node/get?apiKey={self.api_key}"
        try:
            res = requests.get(url, headers=self.headers)
            if res.status_code == 200 and res.json().get("code") == 0:
                return res.json()["data"]
        except: pass
        return None

    def send_message(self, content):
        url = f"{self.base_url}/chat-room/send"
        data = {"apiKey": self.api_key, "content": content}
        try:
            res = requests.post(url, json=data, headers=self.headers)
            return res.status_code == 200 and res.json().get("code") == 0
        except: return False

    def connect(self, on_message_callback):
        if not self.get_api_key(): return False
        node_url = self.get_node_url()
        if not node_url: return False

        def on_message(ws, message):
            try:
                data = json.loads(message)

                # 判断是否为自己发的消息(用 senderId 而不是 userName)
                sender_id = data.get("senderId")
                if sender_id and hasattr(self, "user_id") and sender_id == self.user_id:
                    return

                user = data.get("userName", "").strip()
                if not user or user.lower() in ("系统", "system", "sys", "null", "none"):
                    user = "系统"

                raw_content = data.get("content", "")

                # 尝试将 content 解析为 dict
                content_data = None
                if isinstance(raw_content, str):
                    try:
                        content_data = json.loads(raw_content)
                    except:
                        pass

                # ===== 处理嵌套红包 =====
                if isinstance(content_data, dict) and content_data.get("msgType") == "redPacket":
                    red_type = content_data.get("type", "")
                    money = content_data.get("money", 0)
                    count = content_data.get("count", 0)
                    msg = content_data.get("msg", "")

                    type_map = {
                        "common": "普通红包",
                        "rockPaperScissors": "猜拳红包",
                        "thunder": "雷红包",
                    }
                    red_type_name = type_map.get(red_type, red_type or "红包")
                    msg_line = f"发送了一个{red_type_name}({count} 个,共 {money} 元)"
                    if msg:
                        msg_line += f":{msg}"
                    on_message_callback(f"[{user}]: {msg_line}")
                    return

                # ===== 普通文本消息 =====
                content = strip_html_tags(raw_content)
                on_message_callback(f"[{user}]: {content}")

            except Exception as e:
                print(f"[调试] 消息处理失败: {e}")

        def on_open(ws): on_message_callback("[系统]: WebSocket连接已建立")

        self.ws = websocket.WebSocketApp(
            node_url, on_message=on_message, on_open=on_open
        )
        threading.Thread(target=self.ws.run_forever, daemon=True).start()
        return True

class EmojiPanel(tk.Toplevel):
    def __init__(self, master, entry):
        super().__init__(master)
        self.entry = entry
        self.configure(bg="#2e2e2e")
        self.overrideredirect(True)
        self.attributes("-topmost", True)
        self.build_ui()

    def build_ui(self):
        for i, (emoji, label) in enumerate(EMOJI_LIST):
            btn = tk.Button(self, text=emoji, width=4, height=2, command=lambda e=emoji: self.insert_emoji(e),
                            bg="#2e2e2e", fg="white", relief="flat")
            btn.grid(row=i // 6, column=i % 6, padx=2, pady=2)

    def insert_emoji(self, emoji):
        self.entry.insert('insert', emoji)
        self.destroy()

class ChatApp:
    def __init__(self, root, client):
        self.client = client
        root.title("FishPi 聊天客户端")
        root.geometry("500x400+1400+700")
        root.configure(bg="#1e1e1e")
        root.resizable(False, False)

        self.text_area = ScrolledText(root, state='disabled', height=20, width=70,
                                      bg="#1e1e1e", fg="#d4d4d4", insertbackground="white", font=("Consolas", 10))
        self.text_area.pack(padx=10, pady=10)

        frame = tk.Frame(root, bg="#1e1e1e")
        frame.pack(padx=10, pady=(0, 10), fill='x')

        self.entry = tk.Entry(frame, width=40, bg="#2e2e2e", fg="#d4d4d4",
                              insertbackground="white", font=("Consolas", 10))
        self.entry.pack(side='left', expand=True, fill='x')
        self.entry.bind("<Return>", self.send_message)

        self.send_btn = tk.Button(frame, text="发送", bg="#4caf50", fg="white", relief="flat", command=self.send_message)
        self.send_btn.pack(side='left', padx=(5, 0))

        self.upload_btn = tk.Button(frame, text="上传图片", bg="#2196f3", fg="white", relief="flat", command=self.send_image)
        self.upload_btn.pack(side='left', padx=(5, 0))

        self.emoji_btn = tk.Button(frame, text="😀", bg="#444", fg="white", relief="flat", command=self.toggle_emoji_panel)
        self.emoji_btn.pack(side='left', padx=(5, 0))

        if not self.client.connect(self.display_message):
            self.display_message("[系统]: 无法连接到聊天室")

        self.emoji_panel = None

    def toggle_emoji_panel(self):
        if self.emoji_panel and self.emoji_panel.winfo_exists():
            self.emoji_panel.destroy()
        else:
            x = self.entry.winfo_rootx()
            y = self.entry.winfo_rooty() - 90
            self.emoji_panel = EmojiPanel(self.entry, self.entry)
            self.emoji_panel.geometry(f"+{x}+{y}")

    def display_message(self, msg):
        timestamp = datetime.now().strftime('%H:%M:%S')
        self.text_area.config(state='normal')
        self.text_area.insert('end', f"{timestamp} {msg}\n")
        self.text_area.yview('end')
        self.text_area.config(state='disabled')

    def send_message(self, event=None):
        content = self.entry.get().strip()
        if content:
            html = f"<p>{content}</p>"
            success = self.client.send_message(html)
            if not success:
                self.display_message("[系统]: 消息发送失败")
        self.entry.delete(0, 'end')

    def send_image(self):
        threading.Thread(target=self._upload_image_thread, daemon=True).start()

    def _upload_image_thread(self):
        try:
            file_path = fd.askopenfilename(filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif")])
            if not file_path:
                return

            if os.path.getsize(file_path) > 2 * 1024 * 1024:
                self.display_message("[系统]: 图片太大,请选择小于2MB的图片")
                return

            self.display_message("[系统]: 正在上传图片,请稍候...")

            img_url = upload_with_fallback(file_path)
            if img_url:
                html = f'<p><img src="{img_url}" /></p>'
                self.client.send_message(html)
                self.display_message(f"[{self.client.username}]: [图片: {img_url}]")
            else:
                self.display_message("[系统]: 所有图床上传失败,请稍后重试")
        except Exception as e:
            self.display_message(f"[系统]: 上传异常:{str(e)}")

if __name__ == '__main__':
    username = "请输入你的账号"
    password = "请输入你的密码"
    client = FishPiChatroom(username, password)

    root = tk.Tk()
    app = ChatApp(root, client)
    root.mainloop()

到此,完美结束,希望大家适当摸鱼,在遇到困境的时候看看聊天室的朋友们在干什么缓缓思维,换换心情,或许就能一敲十行,日进斗金呢,祝愿大家节节高升,薪资高高

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值