最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python簡(jiǎn)單編寫一個(gè)股票監(jiān)控系統(tǒng)

 更新時(shí)間:2024年12月19日 10:31:16   作者:PieroPc  
這篇文章主要為大家詳細(xì)介紹了如何使用Python簡(jiǎn)單編寫一個(gè)股票監(jiān)控系統(tǒng),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

圖樣

最小化時(shí)

上代碼

import json
import logging
import threading
from typing import Dict, List
import efinance as ef
import time
from datetime import datetime
import smtplib
from email.mime.text import MIMEText
import sys
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import queue
import requests
 
# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('stock_monitor.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
 
class StockMonitorGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("股票監(jiān)控系統(tǒng)")
        self.root.geometry("1024x600")
        
        # 添加最小化事件綁定
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.root.bind("<Unmap>", self.on_minimize)
        
        self.float_window = None  # 懸浮窗口
        self.is_minimized = False
        
        self.monitor = StockMonitor()
        self.monitor.set_log_callback(self.add_log)
        self.running = False
        self.monitor_thread = None
        self.log_queue = queue.Queue()
        
        self.setup_gui()
        self.update_log()
        self.update_stock_table(self.get_initial_stock_data())
 
    def setup_gui(self):
        # 創(chuàng)建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 股票信息表格
        table_frame = ttk.LabelFrame(main_frame, text="股票監(jiān)控列表", padding="5")
        table_frame.grid(row=0, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        self.tree = ttk.Treeview(table_frame, columns=('代碼', '名稱', '當(dāng)前價(jià)格', '買入價(jià)', '賣出價(jià)', '狀態(tài)'), show='headings', height=8)  # 設(shè)置固定高度
        self.tree.heading('代碼', text='代碼')
        self.tree.heading('名稱', text='名稱')
        self.tree.heading('當(dāng)前價(jià)格', text='當(dāng)前價(jià)格')
        self.tree.heading('買入價(jià)', text='買入價(jià)')
        self.tree.heading('賣出價(jià)', text='賣出價(jià)')
        self.tree.heading('狀態(tài)', text='狀態(tài)')
        
        # 設(shè)置列寬
        self.tree.column('代碼', width=80)
        self.tree.column('名稱', width=100)
        self.tree.column('當(dāng)前價(jià)格', width=80)
        self.tree.column('買入價(jià)', width=80)
        self.tree.column('賣出價(jià)', width=80)
        self.tree.column('狀態(tài)', width=100)
        
        self.tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 添加滾動(dòng)條
        scrollbar = ttk.Scrollbar(table_frame, orient=tk.VERTICAL, command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)
        scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
        
        # 日志顯示區(qū)域
        log_frame = ttk.LabelFrame(main_frame, text="運(yùn)行日志", padding="5")
        log_frame.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        self.log_text = scrolledtext.ScrolledText(log_frame, height=8)  # 減小日志區(qū)域高度
        self.log_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 控制按鈕
        button_frame = ttk.Frame(main_frame, padding="5")
        button_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E))
        
        # 使用更緊湊的按鈕布局
        self.start_button = ttk.Button(button_frame, text="開(kāi)始監(jiān)控", command=self.start_monitoring, width=10)
        self.start_button.grid(row=0, column=0, padx=3)
        
        self.stop_button = ttk.Button(button_frame, text="停止監(jiān)控", command=self.stop_monitoring, state=tk.DISABLED, width=10)
        self.stop_button.grid(row=0, column=1, padx=3)
        
        self.add_button = ttk.Button(button_frame, text="添加股票", command=self.show_add_dialog, width=10)
        self.add_button.grid(row=0, column=2, padx=3)
        
        self.edit_button = ttk.Button(button_frame, text="修改股票", command=self.show_edit_dialog, width=10)
        self.edit_button.grid(row=0, column=3, padx=3)
        
        self.delete_button = ttk.Button(button_frame, text="刪除股票", command=self.delete_stock, width=10)
        self.delete_button.grid(row=0, column=4, padx=3)
        
        self.email_settings_button = ttk.Button(button_frame, text="郵件設(shè)置", command=self.show_email_settings, width=10)
        self.email_settings_button.grid(row=0, column=5, padx=3)
        
        self.qq_settings_button = ttk.Button(button_frame, text="QQ設(shè)置", command=self.show_qq_settings, width=10)
        self.qq_settings_button.grid(row=0, column=6, padx=3)
        
        self.weixin_settings_button = ttk.Button(button_frame, text="微信設(shè)置", command=self.show_weixin_settings, width=10)
        self.weixin_settings_button.grid(row=0, column=7, padx=3)
        
        # 調(diào)整窗口大小
        self.root.geometry("800x500")  # 減小窗口高度
        
        # 配置grid權(quán)重
        self.root.grid_rowconfigure(0, weight=1)
        self.root.grid_columnconfigure(0, weight=1)
        main_frame.grid_rowconfigure(1, weight=1)  # 讓日志區(qū)域可以擴(kuò)展
        main_frame.grid_columnconfigure(0, weight=1)
 
    def update_log(self):
        while True:
            try:
                log_message = self.log_queue.get_nowait()
                self.log_text.insert(tk.END, log_message + '\n')
                self.log_text.see(tk.END)
            except queue.Empty:
                break
        self.root.after(100, self.update_log)
 
    def update_stock_table(self, stock_data):
        # 清空現(xiàn)有數(shù)據(jù)
        for item in self.tree.get_children():
            self.tree.delete(item)
            
        # 插入新數(shù)據(jù)
        for stock in stock_data:
            self.tree.insert('', tk.END, values=stock)
        
        # 更新懸浮窗口
        self.update_float_window(stock_data)
 
    def start_monitoring(self):
        self.add_log("啟動(dòng)股票監(jiān)控系統(tǒng)...")
        self.running = True
        self.start_button.config(state=tk.DISABLED)
        self.stop_button.config(state=tk.NORMAL)
        self.monitor_thread = threading.Thread(target=self.monitoring_task)
        self.monitor_thread.daemon = True
        self.monitor_thread.start()
 
    def stop_monitoring(self):
        self.running = False
        self.start_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.add_log("正在停止股票監(jiān)控系統(tǒng)...")
 
    def monitoring_task(self):
        self.add_log("開(kāi)始監(jiān)控股票...")
        while self.running:
            try:
                stock_data = self.monitor.get_stock_data()
                self.root.after(0, self.update_stock_table, stock_data)
                time.sleep(self.monitor.check_interval)
            except Exception as e:
                self.add_log(f"錯(cuò)誤: {str(e)}")
                time.sleep(self.monitor.check_interval)
        self.add_log("停止監(jiān)控股票...")
 
    def show_add_dialog(self):
        dialog = tk.Toplevel(self.root)
        dialog.title("添加股票")
        dialog.geometry("300x200")
        dialog.transient(self.root)
        
        ttk.Label(dialog, text="股票代碼:").grid(row=0, column=0, padx=5, pady=5)
        code_entry = ttk.Entry(dialog)
        code_entry.grid(row=0, column=1, padx=5, pady=5)
        
        ttk.Label(dialog, text="股票名稱:").grid(row=1, column=0, padx=5, pady=5)
        name_entry = ttk.Entry(dialog)
        name_entry.grid(row=1, column=1, padx=5, pady=5)
        
        ttk.Label(dialog, text="買入價(jià):").grid(row=2, column=0, padx=5, pady=5)
        buy_entry = ttk.Entry(dialog)
        buy_entry.grid(row=2, column=1, padx=5, pady=5)
        
        ttk.Label(dialog, text="賣出價(jià):").grid(row=3, column=0, padx=5, pady=5)
        sell_entry = ttk.Entry(dialog)
        sell_entry.grid(row=3, column=1, padx=5, pady=5)
        
        def save_stock():
            try:
                new_stock = {
                    "code": code_entry.get(),
                    "name": name_entry.get(),
                    "buy_price": float(buy_entry.get()),
                    "sell_price": float(sell_entry.get())
                }
                
                if not new_stock["code"] or not new_stock["name"]:
                    messagebox.showerror("錯(cuò)誤", "股票代碼和名稱不能為空!")
                    return
                
                self.monitor.add_stock(new_stock)
                dialog.destroy()
                self.add_log(f"添加股票成功:{new_stock['name']}")
                self.update_stock_table(self.get_initial_stock_data())
            except ValueError:
                messagebox.showerror("錯(cuò)誤", "請(qǐng)輸入有效的價(jià)格!")
        
        ttk.Button(dialog, text="保存", command=save_stock).grid(row=4, column=0, columnspan=2, pady=20)
 
    def show_edit_dialog(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("提示", "請(qǐng)先選擇要修改的股票!")
            return
            
        item = self.tree.item(selected[0])
        values = item['values']
        
        dialog = tk.Toplevel(self.root)
        dialog.title("修改股票")
        dialog.geometry("300x200")
        dialog.transient(self.root)
        
        ttk.Label(dialog, text="股票代碼:").grid(row=0, column=0, padx=5, pady=5)
        code_entry = ttk.Entry(dialog)
        code_entry.insert(0, values[0])
        code_entry.config(state='readonly')
        code_entry.grid(row=0, column=1, padx=5, pady=5)
        
        ttk.Label(dialog, text="股票名稱:").grid(row=1, column=0, padx=5, pady=5)
        name_entry = ttk.Entry(dialog)
        name_entry.insert(0, values[1])
        name_entry.grid(row=1, column=1, padx=5, pady=5)
        
        ttk.Label(dialog, text="買入價(jià):").grid(row=2, column=0, padx=5, pady=5)
        buy_entry = ttk.Entry(dialog)
        buy_entry.insert(0, values[3])
        buy_entry.grid(row=2, column=1, padx=5, pady=5)
        
        ttk.Label(dialog, text="賣出價(jià):").grid(row=3, column=0, padx=5, pady=5)
        sell_entry = ttk.Entry(dialog)
        sell_entry.insert(0, values[4])
        sell_entry.grid(row=3, column=1, padx=5, pady=5)
        
        def save_changes():
            try:
                updated_stock = {
                    "code": values[0],
                    "name": name_entry.get(),
                    "buy_price": float(buy_entry.get()),
                    "sell_price": float(sell_entry.get())
                }
                
                if not updated_stock["name"]:
                    messagebox.showerror("錯(cuò)誤", "股票名稱不能為空!")
                    return
                
                self.monitor.update_stock(updated_stock)
                dialog.destroy()
                self.add_log(f"修改股票成功:{updated_stock['name']}")
                self.update_stock_table(self.get_initial_stock_data())
            except ValueError:
                messagebox.showerror("錯(cuò)誤", "請(qǐng)輸入有效的價(jià)格!")
        
        ttk.Button(dialog, text="保存", command=save_changes).grid(row=4, column=0, columnspan=2, pady=20)
 
    def delete_stock(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("提示", "請(qǐng)先選擇要?jiǎng)h除的股票!")
            return
            
        item = self.tree.item(selected[0])
        stock_code = item['values'][0]
        stock_name = item['values'][1]
        
        if messagebox.askyesno("確認(rèn)", f"確定要?jiǎng)h除股票 {stock_name} 嗎?"):
            self.monitor.delete_stock(stock_code)
            self.add_log(f"刪除股票成功:{stock_name}")
            self.update_stock_table(self.get_initial_stock_data())
 
    def show_email_settings(self):
        dialog = tk.Toplevel(self.root)
        dialog.title("郵件服務(wù)設(shè)置")
        dialog.geometry("400x350")  # 增加一點(diǎn)高度
        dialog.transient(self.root)
        
        frame = ttk.Frame(dialog, padding="10")
        frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 添加啟用郵件通知選項(xiàng)
        enabled_var = tk.BooleanVar(value=self.monitor.email_config.get('enabled', False))
        ttk.Checkbutton(frame, text="啟用郵件通知", variable=enabled_var).grid(row=0, column=0, columnspan=2, pady=5)
        
        # SMTP服務(wù)器???置
        ttk.Label(frame, text="SMTP服務(wù)器:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        host_entry = ttk.Entry(frame, width=30)
        host_entry.insert(0, self.monitor.email_config['host'])
        host_entry.grid(row=1, column=1, padx=5, pady=5)
        
        # 端口設(shè)置
        ttk.Label(frame, text="端口:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
        port_entry = ttk.Entry(frame, width=30)
        port_entry.insert(0, "465")  # 默認(rèn)端口
        port_entry.grid(row=2, column=1, padx=5, pady=5)
        
        # 用戶名設(shè)置
        ttk.Label(frame, text="郵箱賬號(hào):").grid(row=3, column=0, padx=5, pady=5, sticky=tk.W)
        user_entry = ttk.Entry(frame, width=30)
        user_entry.insert(0, self.monitor.email_config['user'])
        user_entry.grid(row=3, column=1, padx=5, pady=5)
        
        # 密碼設(shè)置
        ttk.Label(frame, text="授權(quán)密碼:").grid(row=4, column=0, padx=5, pady=5, sticky=tk.W)
        pass_entry = ttk.Entry(frame, width=30, show="*")
        pass_entry.insert(0, self.monitor.email_config['password'])
        pass_entry.grid(row=4, column=1, padx=5, pady=5)
        
        # 發(fā)件人設(shè)置
        ttk.Label(frame, text="發(fā)件人:").grid(row=5, column=0, padx=5, pady=5, sticky=tk.W)
        sender_entry = ttk.Entry(frame, width=30)
        sender_entry.insert(0, self.monitor.email_config['sender'])
        sender_entry.grid(row=5, column=1, padx=5, pady=5)
        
        # 收件人設(shè)置
        ttk.Label(frame, text="收件人:").grid(row=6, column=0, padx=5, pady=5, sticky=tk.W)
        receivers_entry = ttk.Entry(frame, width=30)
        receivers_entry.insert(0, ",".join(self.monitor.email_config['receivers']))
        receivers_entry.grid(row=6, column=1, padx=5, pady=5)
        
        # 郵件主題設(shè)置
        ttk.Label(frame, text="郵件主題:").grid(row=7, column=0, padx=5, pady=5, sticky=tk.W)
        title_entry = ttk.Entry(frame, width=30)
        title_entry.insert(0, self.monitor.email_config['title'])
        title_entry.grid(row=7, column=1, padx=5, pady=5)
        
        def test_email():
            if not enabled_var.get():
                messagebox.showwarning("提示", "請(qǐng)先啟用郵件通知!")
                return
 
            # 臨時(shí)保存當(dāng)前設(shè)置
            temp_config = {
                'enabled': enabled_var.get(),
                'host': host_entry.get(),
                'user': user_entry.get(),
                'password': pass_entry.get(),
                'sender': sender_entry.get(),
                'receivers': [r.strip() for r in receivers_entry.get().split(',')],
                'title': title_entry.get()
            }
            
            try:
                with smtplib.SMTP_SSL(temp_config['host'], 465) as smtp:
                    smtp.login(temp_config['user'], temp_config['password'])
                    message = MIMEText("這是一封測(cè)試郵件,如果您收到這封郵件,說(shuō)明郵件服務(wù)設(shè)置正確。", 'plain', 'utf-8')
                    message['From'] = temp_config['sender']
                    message['To'] = ",".join(temp_config['receivers'])
                    message['Subject'] = "測(cè)試郵件"
                    smtp.sendmail(
                        temp_config['sender'],
                        temp_config['receivers'],
                        message.as_string()
                    )
                messagebox.showinfo("成功", "測(cè)試郵件發(fā)送成功!")
            except Exception as e:
                messagebox.showerror("錯(cuò)誤", f"測(cè)試郵件發(fā)送失?。簕str(e)}")
        
        def save_settings():
            try:
                new_config = {
                    'enabled': enabled_var.get(),
                    'host': host_entry.get(),
                    'user': user_entry.get(),
                    'password': pass_entry.get(),
                    'sender': sender_entry.get(),
                    'receivers': [r.strip() for r in receivers_entry.get().split(',')],
                    'title': title_entry.get()
                }
                
                # 驗(yàn)證必填字段
                if new_config['enabled'] and not all([new_config['host'], new_config['user'], 
                          new_config['password'], new_config['sender'],
                          new_config['receivers'], new_config['title']]):
                    messagebox.showerror("錯(cuò)誤", "啟用郵件通知時(shí)所有字段都必須填寫!")
                    return
                
                # 更新配置
                self.monitor.update_email_config(new_config)
                messagebox.showinfo("成功", "郵件設(shè)置已保存!")
                dialog.destroy()
                
            except Exception as e:
                messagebox.showerror("錯(cuò)誤", f"保存設(shè)置失?。簕str(e)}")
        
        # 按鈕框架
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=8, column=0, columnspan=2, pady=20)
        
        test_button = ttk.Button(button_frame, text="測(cè)試", command=test_email)
        test_button.grid(row=0, column=0, padx=5)
        
        save_button = ttk.Button(button_frame, text="保存", command=save_settings)
        save_button.grid(row=0, column=1, padx=5)
 
    def show_qq_settings(self):
        dialog = tk.Toplevel(self.root)
        dialog.title("QQ機(jī)器人設(shè)置")
        dialog.geometry("400x250")
        dialog.transient(self.root)
        
        frame = ttk.Frame(dialog, padding="10")
        frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 啟用QQ通知
        enabled_var = tk.BooleanVar(value=self.monitor.qq_config.get('enabled', False))
        ttk.Checkbutton(frame, text="啟用QQ通知", variable=enabled_var).grid(row=0, column=0, columnspan=2, pady=5)
        
        # API地址
        ttk.Label(frame, text="API地址:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        api_entry = ttk.Entry(frame, width=30)
        api_entry.insert(0, self.monitor.qq_config.get('api_url', 'http://127.0.0.1:5700'))
        api_entry.grid(row=1, column=1, padx=5, pady=5)
        
        # QQ號(hào)
        ttk.Label(frame, text="接收QQ:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
        qq_entry = ttk.Entry(frame, width=30)
        qq_entry.insert(0, self.monitor.qq_config.get('qq_id', ''))
        qq_entry.grid(row=2, column=1, padx=5, pady=5)
        
        # 訪問(wèn)令牌
        ttk.Label(frame, text="訪問(wèn)令牌:").grid(row=3, column=0, padx=5, pady=5, sticky=tk.W)
        token_entry = ttk.Entry(frame, width=30, show="*")
        token_entry.insert(0, self.monitor.qq_config.get('access_token', ''))
        token_entry.grid(row=3, column=1, padx=5, pady=5)
        
        def test_qq():
            config = {
                'enabled': enabled_var.get(),
                'api_url': api_entry.get(),
                'qq_id': qq_entry.get(),
                'access_token': token_entry.get()
            }
            
            try:
                url = f"{config['api_url']}/send_private_msg"
                params = {
                    'user_id': config['qq_id'],
                    'message': "這是一條測(cè)試消息,如果您收到這消息,說(shuō)明QQ機(jī)器人設(shè)置正確。"
                }
                headers = {
                    'Authorization': f"Bearer {config['access_token']}"
                }
                
                response = requests.get(url, params=params, headers=headers)
                if response.status_code == 200:
                    messagebox.showinfo("成功", "測(cè)試消息發(fā)送成功!")
                else:
                    messagebox.showerror("錯(cuò)誤", f"測(cè)試消息發(fā)送失?。簕response.text}")
            except Exception as e:
                messagebox.showerror("錯(cuò)誤", f"測(cè)試消息發(fā)送失敗:{str(e)}")
        
        def save_settings():
            try:
                new_config = {
                    'enabled': enabled_var.get(),
                    'api_url': api_entry.get(),
                    'qq_id': qq_entry.get(),
                    'access_token': token_entry.get()
                }
                
                if new_config['enabled'] and not all([new_config['api_url'], new_config['qq_id']]):
                    messagebox.showerror("錯(cuò)誤", "啟用QQ通知時(shí)必須填寫API地址和接收QQ!")
                    return
                
                self.monitor.qq_config = new_config
                self.monitor.config['qq'] = new_config
                self.monitor._save_config()
                messagebox.showinfo("成功", "QQ設(shè)置已保存!")
                dialog.destroy()
                
            except Exception as e:
                messagebox.showerror("錯(cuò)誤", f"保存設(shè)置失敗:{str(e)}")
        
        # 按鈕框架
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=4, column=0, columnspan=2, pady=20)
        
        test_button = ttk.Button(button_frame, text="測(cè)試", command=test_qq)
        test_button.grid(row=0, column=0, padx=5)
        
        save_button = ttk.Button(button_frame, text="保存", command=save_settings)
        save_button.grid(row=0, column=1, padx=5)
 
    def show_weixin_settings(self):
        dialog = tk.Toplevel(self.root)
        dialog.title("企業(yè)微信設(shè)置")
        dialog.geometry("400x300")
        dialog.transient(self.root)
        
        frame = ttk.Frame(dialog, padding="10")
        frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 啟用微信通知
        enabled_var = tk.BooleanVar(value=self.monitor.weixin_config.get('enabled', False))
        ttk.Checkbutton(frame, text="啟用企業(yè)微信通知", variable=enabled_var).grid(row=0, column=0, columnspan=2, pady=5)
        
        # 企業(yè)ID
        ttk.Label(frame, text="企業(yè)ID:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        corp_id_entry = ttk.Entry(frame, width=30)
        corp_id_entry.insert(0, self.monitor.weixin_config.get('corp_id', ''))
        corp_id_entry.grid(row=1, column=1, padx=5, pady=5)
        
        # 應(yīng)用ID
        ttk.Label(frame, text="應(yīng)用ID:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
        agent_id_entry = ttk.Entry(frame, width=30)
        agent_id_entry.insert(0, self.monitor.weixin_config.get('agent_id', ''))
        agent_id_entry.grid(row=2, column=1, padx=5, pady=5)
        
        # 應(yīng)用密鑰
        ttk.Label(frame, text="應(yīng)用密鑰:").grid(row=3, column=0, padx=5, pady=5, sticky=tk.W)
        secret_entry = ttk.Entry(frame, width=30, show="*")
        secret_entry.insert(0, self.monitor.weixin_config.get('corp_secret', ''))
        secret_entry.grid(row=3, column=1, padx=5, pady=5)
        
        # 接收用戶
        ttk.Label(frame, text="接收用戶:").grid(row=4, column=0, padx=5, pady=5, sticky=tk.W)
        to_user_entry = ttk.Entry(frame, width=30)
        to_user_entry.insert(0, self.monitor.weixin_config.get('to_user', '@all'))
        to_user_entry.grid(row=4, column=1, padx=5, pady=5)
        
        def test_weixin():
            if not enabled_var.get():
                messagebox.showwarning("提示", "請(qǐng)先啟用企業(yè)微信通知!")
                return
            
            config = {
                'enabled': enabled_var.get(),
                'corp_id': corp_id_entry.get(),
                'agent_id': agent_id_entry.get(),
                'corp_secret': secret_entry.get(),
                'to_user': to_user_entry.get()
            }
            
            # 創(chuàng)建臨時(shí)的 StockMonitor 實(shí)例來(lái)測(cè)試
            temp_monitor = StockMonitor()
            temp_monitor.weixin_config = config
            temp_monitor.set_log_callback(self.add_log)
            
            temp_monitor.send_weixin_message("這是一條測(cè)試消息,如果您收到這條消息,說(shuō)明企業(yè)微信設(shè)置正確。")
        
        def save_settings():
            try:
                new_config = {
                    'enabled': enabled_var.get(),
                    'corp_id': corp_id_entry.get(),
                    'agent_id': agent_id_entry.get(),
                    'corp_secret': secret_entry.get(),
                    'to_user': to_user_entry.get()
                }
                
                if new_config['enabled'] and not all([new_config['corp_id'], 
                                                    new_config['agent_id'], 
                                                    new_config['corp_secret']]):
                    messagebox.showerror("錯(cuò)誤", "啟用企業(yè)微信通知時(shí)必須填寫企業(yè)ID、應(yīng)用ID和應(yīng)用密鑰!")
                    return
                
                self.monitor.weixin_config = new_config
                self.monitor.config['weixin'] = new_config
                self.monitor._save_config()
                messagebox.showinfo("成功", "企業(yè)微信設(shè)置已保存!")
                dialog.destroy()
                
            except Exception as e:
                messagebox.showerror("錯(cuò)誤", f"保存設(shè)置失?。簕str(e)}")
        
        # 按鈕框架
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=5, column=0, columnspan=2, pady=20)
        
        test_button = ttk.Button(button_frame, text="測(cè)試", command=test_weixin)
        test_button.grid(row=0, column=0, padx=5)
        
        save_button = ttk.Button(button_frame, text="保存", command=save_settings)
        save_button.grid(row=0, column=1, padx=5)
 
    def add_log(self, message: str):
        """添加日志到界面"""
        self.log_text.insert(tk.END, message + '\n')
        self.log_text.see(tk.END)  # 滾動(dòng)到最新的日志
 
    def get_initial_stock_data(self):
        """獲取初始股票數(shù)據(jù)用于顯示"""
        result = []
        for stock in self.monitor.stocks:
            result.append((
                stock['code'],
                stock['name'],
                '等待更新',  # 初始顯示時(shí)還沒(méi)有實(shí)時(shí)價(jià)格
                stock['buy_price'],
                stock['sell_price'],
                '等待監(jiān)控'   # 初始狀態(tài)
            ))
        return result
 
    def create_float_window(self):
        """創(chuàng)建懸浮窗口"""
        self.float_window = tk.Toplevel()
        self.float_window.title("股票監(jiān)控")
        
        # 設(shè)置窗口屬性
        self.float_window.attributes('-topmost', True)  # 始終置頂
        self.float_window.overrideredirect(True)  # 無(wú)邊框
        self.float_window.attributes('-alpha', 0.9)  # 設(shè)置透明度
        
        # 獲取屏幕尺寸
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        
        # 設(shè)置窗口位置(右下角)
        window_width = 200
        window_height = 300
        x = screen_width - window_width - 10
        y = screen_height - window_height - 50
        self.float_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
        
        # 創(chuàng)建標(biāo)題欄
        title_frame = ttk.Frame(self.float_window)
        title_frame.pack(fill=tk.X, padx=2, pady=2)
        
        ttk.Label(title_frame, text="股票監(jiān)控").pack(side=tk.LEFT, padx=5)
        
        # 添加關(guān)閉和還原按鈕
        ttk.Button(title_frame, text="□", width=3, command=self.restore_window).pack(side=tk.RIGHT, padx=1)
        ttk.Button(title_frame, text="×", width=3, command=self.on_closing).pack(side=tk.RIGHT, padx=1)
        
        # 添加拖動(dòng)功能
        title_frame.bind("<Button-1>", self.start_move)
        title_frame.bind("<B1-Motion>", self.on_move)
        
        # 創(chuàng)建股票信息顯示區(qū)域
        self.float_tree = ttk.Treeview(self.float_window, columns=('名稱', '價(jià)格', '狀態(tài)'), show='headings', height=10)
        self.float_tree.heading('名稱', text='名稱')
        self.float_tree.heading('價(jià)格', text='價(jià)格')
        self.float_tree.heading('狀態(tài)', text='狀態(tài)')
        
        # 設(shè)置列寬
        self.float_tree.column('名稱', width=60)
        self.float_tree.column('價(jià)格', width=60)
        self.float_tree.column('狀態(tài)', width=60)
        
        self.float_tree.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)
 
    def update_float_window(self, stock_data):
        """更新懸浮窗口的股票信息"""
        if self.float_window and self.is_minimized:
            for item in self.float_tree.get_children():
                self.float_tree.delete(item)
            
            for stock in stock_data:
                self.float_tree.insert('', tk.END, values=(stock[1], stock[2], stock[5]))
 
    def start_move(self, event):
        """開(kāi)始拖動(dòng)窗口"""
        self.x = event.x
        self.y = event.y
 
    def on_move(self, event):
        """拖動(dòng)窗口"""
        deltax = event.x - self.x
        deltay = event.y - self.y
        x = self.float_window.winfo_x() + deltax
        y = self.float_window.winfo_y() + deltay
        self.float_window.geometry(f"+{x}+{y}")
 
    def on_minimize(self, event):
        """最小化主窗口時(shí)顯示懸浮窗"""
        if not self.float_window:
            self.create_float_window()
        self.is_minimized = True
        self.float_window.deiconify()
 
    def restore_window(self):
        """還原主窗口"""
        self.root.deiconify()
        self.is_minimized = False
        if self.float_window:
            self.float_window.withdraw()
 
    def on_closing(self):
        """關(guān)閉程序"""
        if messagebox.askokcancel("退出", "確定要退出程序嗎?"):
            if self.float_window:
                self.float_window.destroy()
            self.root.destroy()
 
class StockMonitor:
    def __init__(self, config_file: str = 'stock_config.json'):
        self.config = self._load_config(config_file)
        self.email_config = self.config['email']
        self.qq_config = self.config.get('qq', {'enabled': False})  # 添加QQ配置
        self.weixin_config = self.config.get('weixin', {'enabled': False})  # 添加微信配置
        self.stocks = self.config['stocks']
        self.check_interval = self.config['check_interval']
        self.log_callback = None  # 添加日志回調(diào)函數(shù)
 
    def set_log_callback(self, callback):
        """設(shè)置日志回調(diào)函數(shù)"""
        self.log_callback = callback
 
    def log(self, message: str, level: str = 'info'):
        """統(tǒng)一的日志處理方法"""
        if level == 'error':
            logging.error(message)
        else:
            logging.info(message)
            
        if self.log_callback:
            self.log_callback(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {message}")
 
    def _load_config(self, config_file: str) -> Dict:
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except FileNotFoundError:
            logging.error(f"配置文件 {config_file} 不存在")
            sys.exit(1)
        except json.JSONDecodeError:
            logging.error(f"配置文件 {config_file} 格式錯(cuò)誤")
            sys.exit(1)
 
    def send_email(self, content: str) -> None:
        """發(fā)送郵件"""
        if not self.email_config.get('enabled', False):  # 檢查是否啟用
            return
 
        message = MIMEText(content, 'plain', 'utf-8')
        message['From'] = self.email_config['sender']
        message['To'] = ",".join(self.email_config['receivers'])
        message['Subject'] = self.email_config['title']
 
        try:
            with smtplib.SMTP_SSL(self.email_config['host'], 465) as smtp:
                smtp.login(self.email_config['user'], self.email_config['password'])
                smtp.sendmail(
                    self.email_config['sender'],
                    self.email_config['receivers'],
                    message.as_string()
                )
            self.log("郵件發(fā)送成功!")
        except Exception as e:
            self.log(f"郵件發(fā)送失敗: {str(e)}", 'error')
 
    def get_stock_status(self, current_price: float, buy_price: float, sell_price: float) -> str:
        if current_price <= buy_price:
            return "建議買入"
        elif current_price >= sell_price:
            return "建議賣出"
        return "觀察中"
 
    def send_qq_message(self, message: str) -> None:
        """發(fā)送QQ消息"""
        if not self.qq_config.get('enabled', False):
            return
 
        try:
            url = f"{self.qq_config['api_url']}/send_private_msg"
            params = {
                'user_id': self.qq_config['qq_id'],
                'message': message
            }
            headers = {
                'Authorization': f"Bearer {self.qq_config.get('access_token', '')}"
            }
            
            response = requests.get(url, params=params, headers=headers)
            if response.status_code == 200:
                self.log("QQ消息發(fā)送成功!")
            else:
                self.log(f"QQ消息發(fā)送失敗: {response.text}", 'error')
        except Exception as e:
            self.log(f"QQ消息發(fā)送失敗: {str(e)}", 'error')
 
    def send_weixin_message(self, message: str) -> None:
        """發(fā)送企業(yè)微信消息"""
        if not self.weixin_config.get('enabled', False):
            return
 
        try:
            # 獲取訪問(wèn)令牌
            token_url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken"
            token_params = {
                'corpid': self.weixin_config['corp_id'],
                'corpsecret': self.weixin_config['corp_secret']
            }
            
            token_response = requests.get(token_url, params=token_params)
            token_data = token_response.json()
            
            if token_data['errcode'] != 0:
                self.log(f"獲取微信訪問(wèn)令牌失敗: {token_data['errmsg']}", 'error')
                return
            
            access_token = token_data['access_token']
            
            # 發(fā)送消息
            send_url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}"
            send_data = {
                'touser': self.weixin_config['to_user'],
                'msgtype': 'text',
                'agentid': self.weixin_config['agent_id'],
                'text': {
                    'content': message
                }
            }
            
            response = requests.post(send_url, json=send_data)
            result = response.json()
            
            if result['errcode'] == 0:
                self.log("微信消息發(fā)送成功!")
            else:
                self.log(f"微信消息發(fā)送失敗: {result['errmsg']}", 'error')
        except Exception as e:
            self.log(f"微信消息發(fā)送失敗: {str(e)}", 'error')
 
    def get_stock_data(self) -> List:
        try:
            df = ef.stock.get_realtime_quotes()
            stock_list = df.values.tolist()
            result = []
            
            for stock_info in self.stocks:
                stock_data = next(
                    (item for item in stock_list if item[0] == stock_info['code']),
                    None
                )
                
                if stock_data:
                    current_price = float(stock_data[3])
                    status = self.get_stock_status(
                        current_price,
                        stock_info['buy_price'],
                        stock_info['sell_price']
                    )
                    
                    result.append((
                        stock_info['code'],
                        stock_info['name'],
                        current_price,
                        stock_info['buy_price'],
                        stock_info['sell_price'],
                        status
                    ))
                    
                    # 檢查是否需要發(fā)送提醒
                    if status in ["建議買入", "建議賣出"]:
                        content = f'當(dāng)前{stock_info["name"]}的價(jià)格是: {current_price}, {status}'
                        self.send_email(content)
                        self.send_qq_message(content)
                        self.send_weixin_message(content)  # 添加微信消息提醒
                        self.log(content)
                    else:
                        self.log(f'當(dāng)前{stock_info["name"]}的價(jià)格是: {current_price} 耐心觀察中...')
                else:
                    self.log(f"未找到股票 {stock_info['code']} 的數(shù)據(jù)", 'error')
                    
            return result
        except Exception as e:
            self.log(f"獲取股票數(shù)據(jù)失敗: {str(e)}", 'error')
            return []
 
    def add_stock(self, stock: Dict) -> None:
        self.stocks.append(stock)
        self._save_config()
 
    def update_stock(self, updated_stock: Dict) -> None:
        for i, stock in enumerate(self.stocks):
            if stock['code'] == updated_stock['code']:
                self.stocks[i] = updated_stock
                break
        self._save_config()
 
    def delete_stock(self, stock_code: str) -> None:
        self.stocks = [s for s in self.stocks if s['code'] != stock_code]
        self._save_config()
 
    def _save_config(self) -> None:
        try:
            self.config['stocks'] = self.stocks
            with open('stock_config.json', 'w', encoding='utf-8') as f:
                json.dump(self.config, f, indent=4, ensure_ascii=False)
        except Exception as e:
            logging.error(f"保存配置文件失敗: {str(e)}")
 
    def update_email_config(self, new_config: Dict) -> None:
        self.email_config = new_config
        self.config['email'] = new_config
        self._save_config()
 
def main():
    root = tk.Tk()
    app = StockMonitorGUI(root)
    root.mainloop()
 
if __name__ == "__main__":
    main()

上配置文件:stock_config.json

{
    "email": {
        "enabled": false,
        "host": "smtp.163.com",
        "user": "i238@163.com",
        "password": "JIMRV",
        "sender": "i25@163.com",
        "receivers": [
            "123@qq.com"
        ],
        "title": "股票監(jiān)控買賣提示"
    },
    "qq": {
        "enabled": false,
        "api_url": "http://127.0.0.1:5700",
        "qq_id": "123456789",
        "access_token": "your_access_token"
    },
    "weixin": {
        "enabled": false,
        "corp_id": "your_corp_id",
        "agent_id": "your_agent_id",
        "corp_secret": "your_corp_secret",
        "to_user": "@all"
    },
    "stocks": [
        {
            "code": "000776",
            "name": "廣發(fā)證券",
            "buy_price": 11.3,
            "sell_price": 12.6
        },
        {
            "code": "002945",
            "name": "華林證券",
            "buy_price": 12.0,
            "sell_price": 16.0
        }
    ],
    "check_interval": 60
}

上文檔說(shuō)明--- 股票監(jiān)控系統(tǒng)使用說(shuō)明

1. 系統(tǒng)簡(jiǎn)介

這是一個(gè)基于Python開(kāi)發(fā)的股票監(jiān)控系統(tǒng),可以實(shí)時(shí)監(jiān)控多支股票的價(jià)格變動(dòng),并通過(guò)多種方式(郵件、QQ、企業(yè)微信)發(fā)送買賣提醒。

主要功能:

  • 實(shí)時(shí)監(jiān)控多支股票價(jià)格
  • 自定義買入賣出價(jià)格
  • 多種提醒方式(郵件/QQ/企業(yè)微信)
  • 懸浮窗口顯示實(shí)時(shí)行情
  • 完整的日志記錄

2. 系統(tǒng)要求

Python 3.6 或更高版本

需要安裝的依賴包:

pip install efinance requests

3. 配置文件說(shuō)明

配置文件為 stock_config.json,包含以下主要配置項(xiàng):

son
{
"email": {
"enabled": false, // 是否啟用郵件通知
"host": "smtp.163.com", // SMTP服務(wù)器
"user": "xxx@163.com", // 郵箱賬號(hào)
"password": "xxx", // 郵箱授權(quán)碼
"sender": "xxx@163.com", // 發(fā)件人
"receivers": ["xxx@qq.com"],// 收件人列表
"title": "股票監(jiān)控提示" // 郵件主題
},
"qq": {
"enabled": false, // 是否啟用QQ通知
"api_url": "http://127.0.0.1:5700", // go-cqhttp服務(wù)地址
"qq_id": "123456789", // 接收消息的QQ號(hào)
"access_token": "xxx" // 訪問(wèn)令牌
},
"weixin": {
"enabled": false, // 是否啟用企業(yè)微信通知
"corp_id": "xxx", // 企業(yè)ID
"agent_id": "xxx", // 應(yīng)用ID
"corp_secret": "xxx", // 應(yīng)用密鑰
"to_user": "@all" // 接收用戶
},
"stocks": [ // 監(jiān)控的股票列表
{
"code": "000776", // 股票代碼
"name": "廣發(fā)證券", // 股票名稱
"buy_price": 11.3, // 買入價(jià)
"sell_price": 12.6 // 賣出價(jià)
}
],
"check_interval": 60 // 檢查間隔(秒)
}

4. 使用說(shuō)明

4.1 啟動(dòng)程序

運(yùn)行 股票監(jiān)聽(tīng)器.py 文件啟動(dòng)程序。

4.2 股票管理

  • 添加股票:點(diǎn)擊"添加股票"按鈕,輸入股票代碼、名稱、買入價(jià)和賣出價(jià)
  • 修改股票:選中要修改的股票,點(diǎn)擊"修改股票"按鈕
  • 刪除股票:選中要?jiǎng)h除的股票,點(diǎn)擊"刪除股票"按鈕

4.3 通知設(shè)置

郵件設(shè)置:

  • 點(diǎn)擊"郵件設(shè)置"按鈕
  • 勾選"啟用郵件通知"
  • 填寫SMTP服務(wù)器、郵箱賬號(hào)等信息
  • 可點(diǎn)擊"測(cè)試"按鈕測(cè)試設(shè)置

QQ設(shè)置:

  • 需要先配置并運(yùn)行 go-cqhttp
  • 點(diǎn)擊"QQ設(shè)置"按鈕
  • 勾選"啟用QQ通知"
  • 填寫API地址和接收QQ號(hào)
  • 可點(diǎn)擊"測(cè)試"按鈕測(cè)試設(shè)置

企業(yè)微信設(shè)置:

  • 需要有企業(yè)微信管理員權(quán)限
  • 點(diǎn)擊"微信設(shè)置"按鈕
  • 勾選"啟用企業(yè)微信通知"
  • 填寫企業(yè)ID、應(yīng)用ID等信息
  • 可點(diǎn)擊"測(cè)試"按鈕測(cè)試設(shè)置

4.4 監(jiān)控操作

開(kāi)始監(jiān)控:點(diǎn)擊"開(kāi)始監(jiān)控"按鈕

停止監(jiān)控:點(diǎn)擊"停止監(jiān)控"按鈕

最小化:

  • 程序最小化后會(huì)在屏幕右下角顯示懸浮窗
  • 懸浮窗可以拖動(dòng)位置
  • 點(diǎn)擊"□"按鈕可以還原主窗口
  • 點(diǎn)擊"×"按鈕可以關(guān)閉程序

5. 提醒規(guī)則

當(dāng)股票價(jià)格低于或等于設(shè)定的買入價(jià)時(shí),發(fā)送"建議買入"提醒

當(dāng)股票價(jià)格高于或等于設(shè)定的賣出價(jià)時(shí),發(fā)送"建議賣出"提醒

提醒會(huì)同時(shí)通過(guò)所有已啟用的通知方式發(fā)送

6. 注意事項(xiàng)

郵件通知需要使用郵箱的授權(quán)碼,而不是登錄密碼

QQ通知需要正確配置并運(yùn)行 go-cqhttp

企業(yè)微信通知需要管理員在企業(yè)微信后臺(tái)創(chuàng)建應(yīng)用

所有密碼和密鑰信息都保存在本地配置文件中,請(qǐng)注意信息安全

程序會(huì)自動(dòng)保存所有設(shè)置到配置文件

7. 常見(jiàn)問(wèn)題

郵件發(fā)送失敗:

  • 檢查郵箱賬號(hào)和授權(quán)碼是否正確
  • 確認(rèn)SMTP服務(wù)器地址是否正確

QQ消息發(fā)送失?。?/p>

  • 確認(rèn)go-cqhttp是否正常運(yùn)行
  • 檢查API地址是否可以訪問(wèn)

企業(yè)微信消息發(fā)送失?。?/p>

  • 確認(rèn)企業(yè)ID和應(yīng)用密鑰是否正確
  • 檢查應(yīng)用是否有發(fā)送消息權(quán)限

股票數(shù)據(jù)獲取失敗:

  • 檢查網(wǎng)絡(luò)連接
  • 確認(rèn)股票代碼是否正確

到此這篇關(guān)于使用Python簡(jiǎn)單編寫一個(gè)股票監(jiān)控系統(tǒng)的文章就介紹到這了,更多相關(guān)Python股票監(jiān)控系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • calendar在python3時(shí)間中常用函數(shù)舉例詳解

    calendar在python3時(shí)間中常用函數(shù)舉例詳解

    這篇文章主要介紹了calendar在python3時(shí)間中常用函數(shù)的相關(guān)文章,對(duì)此知識(shí)點(diǎn)有興趣的朋友們可以學(xué)習(xí)下。
    2020-11-11
  • PyCharm文件模板配置的完整指南

    PyCharm文件模板配置的完整指南

    這篇文章主要介紹了PyCharm文件模板配置的全流程,涵蓋模板創(chuàng)建、變量使用(如日期、用戶名)、LiveTemplates設(shè)置、團(tuán)隊(duì)共享及最佳實(shí)踐,通過(guò)統(tǒng)一代碼結(jié)構(gòu)提升開(kāi)發(fā)效率,需要的朋友可以參考下
    2025-07-07
  • MacOS使用pyenv和brew優(yōu)雅管理Python多版本環(huán)境

    MacOS使用pyenv和brew優(yōu)雅管理Python多版本環(huán)境

    本文采用「pyenv?+?Homebrew」方案,為?MacOS?搭建干凈、隔離的?Python?多版本環(huán)境,徹底避免污染系統(tǒng)自帶?Python,完美適配不同項(xiàng)目版本需求,有需要的小伙伴可以參考下
    2026-03-03
  • python文本數(shù)據(jù)處理學(xué)習(xí)筆記詳解

    python文本數(shù)據(jù)處理學(xué)習(xí)筆記詳解

    這篇文章主要為大家詳細(xì)介紹了python文本數(shù)據(jù)處理學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • 深入解析Python中的上下文管理器

    深入解析Python中的上下文管理器

    Python中把進(jìn)入代碼塊前調(diào)用__enter__ 方法并在離開(kāi)代碼塊后調(diào)用__exit__方法的對(duì)象作為上下文管理器,本文中我們就來(lái)深入解析Python中的上下文管理器,來(lái)看看上下文管理器的作用及用法:
    2016-06-06
  • pandas中Series運(yùn)算匯總(算術(shù)、比較和邏輯運(yùn)算)

    pandas中Series運(yùn)算匯總(算術(shù)、比較和邏輯運(yùn)算)

    本文主要介紹了pandas中Series運(yùn)算匯總,包括算術(shù)運(yùn)算、比較運(yùn)算和邏輯運(yùn)算等,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • Django基礎(chǔ)知識(shí) URL路由系統(tǒng)詳解

    Django基礎(chǔ)知識(shí) URL路由系統(tǒng)詳解

    這篇文章主要介紹了Django基礎(chǔ)知識(shí) URL路由系統(tǒng)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 使用Pyinstaller打包exe文件詳細(xì)圖文教程

    使用Pyinstaller打包exe文件詳細(xì)圖文教程

    PyInstaller可以用來(lái)打包python應(yīng)用程序,打包完的程序就可以在沒(méi)有安裝Python解釋器的機(jī)器上運(yùn)行了,下面這篇文章主要給大家介紹了關(guān)于使用Pyinstaller打包exe文件的詳細(xì)圖文教程,需要的朋友可以參考下
    2022-08-08
  • python的urllib.parse用法及說(shuō)明

    python的urllib.parse用法及說(shuō)明

    這篇文章主要介紹了python的urllib.parse用法及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • python發(fā)送arp欺騙攻擊代碼分析

    python發(fā)送arp欺騙攻擊代碼分析

    這篇文章主要介紹了python發(fā)送arp欺騙攻擊的方法,大家碰到這樣的事情可以預(yù)防一下
    2014-01-01

最新評(píng)論

安龙县| 洪湖市| 柘城县| 广宁县| 宜君县| 长白| 花莲县| 白城市| 微山县| 安阳市| 亳州市| 平顺县| 拉萨市| 五寨县| 定日县| 鄄城县| 肇州县| 海晏县| 渑池县| 许昌市| 湘乡市| 三都| 开封县| 巩留县| 土默特左旗| 微博| 长岛县| 东明县| 盈江县| 油尖旺区| 五原县| 宝丰县| 通州区| 德江县| 陆川县| 凭祥市| 城固县| 噶尔县| 华阴市| 新兴县| 甘洛县|