亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python使用DrissionPage實現(xiàn)數(shù)據(jù)分析工具

 更新時間:2025年05月18日 08:39:27   作者:創(chuàng)客白澤  
在短視頻時代,抖音數(shù)據(jù)蘊含著巨大價值,本文我們將使用新興的DrissionPage替代Selenium,結(jié)合精心設(shè)計的UI框架,打造了一款顏值與實力并存的分析利器,感興趣的小伙伴可以了解下

概述:當(dāng)爬蟲遇上顏值革命

在短視頻時代,抖音數(shù)據(jù)蘊含著巨大價值。今天我要分享的是一款自主研發(fā)的抖音數(shù)據(jù)分析工具,它不僅能高效采集抖音視頻/用戶數(shù)據(jù),還擁有專業(yè)級可視化界面。與傳統(tǒng)爬蟲工具不同,我們使用新興的DrissionPage替代Selenium,結(jié)合精心設(shè)計的UI框架,打造了一款顏值與實力并存的分析利器!

工具亮點:

  • 現(xiàn)代化UI設(shè)計,支持暗黑/明亮主題
  • 基于DrissionPage的高性能采集引擎
  • 多維數(shù)據(jù)分析(互動數(shù)據(jù)/內(nèi)容分析/關(guān)鍵詞提取)
  • 一鍵導(dǎo)出Excel/JSON
  • 模塊化設(shè)計,二次開發(fā)友好

功能全景圖

核心功能模塊

模塊功能技術(shù)實現(xiàn)
數(shù)據(jù)采集支持關(guān)鍵詞搜索/鏈接直達兩種方式DrissionPage頁面控制
用戶分析粉絲數(shù)/獲贊數(shù)/主頁跳轉(zhuǎn)XPath+BeautifulSoup解析
視頻分析點贊/發(fā)布時間/作者分析數(shù)據(jù)正則清洗
智能分析詞頻統(tǒng)計/互動數(shù)據(jù)建模jieba分詞+Counter統(tǒng)計
可視化表格展示/圖表生成ttk.Treeview+Matplotlib

特色功能解析

def analyze_keywords(self):
    """高頻詞分析(含emoji處理)"""
    all_titles = ' '.join(data['title'] for data in self.collected_data)
    # 特殊處理emoji
    emoji_pattern = re.compile("["
        u"\U0001F600-\U0001F64F"  # emoticons
        u"\U0001F300-\U0001F5FF"  # symbols & pictographs
        "]+", flags=re.UNICODE)
    clean_text = emoji_pattern.sub(r'', all_titles)
    # jieba分詞...

UI展示效果

1. 主界面布局(多標(biāo)簽設(shè)計)

2. 數(shù)據(jù)采集面板

  • 智能瀏覽器路徑檢測
  • 實時采集進度展示
  • 數(shù)據(jù)預(yù)覽窗口

3. 炫酷的數(shù)據(jù)表格

# 動態(tài)排序?qū)崿F(xiàn)
def treeview_sort_column(self, tree, col, reverse):
    l = [(tree.set(k, col), k) for k in tree.get_children('')]
    try:
        l.sort(key=lambda x: float(x[0].replace('萬','')) if '萬' in x[0] else float(x[0]), reverse=reverse)
    except:
        l.sort(reverse=reverse)
    # 重新排列項目...

使用指南(五步上手)

步驟1:環(huán)境準備

pip install DrissionPage pandas jieba

步驟2:啟動工具

python douyin_analyzer.py

步驟3:數(shù)據(jù)采集

  • 選擇搜索類型(視頻/用戶)
  • 設(shè)置滾動次數(shù)(建議50-100次)
  • 點擊"開始采集"

步驟4:數(shù)據(jù)分析

  • 點擊"互動分析"查看點贊分布
  • 使用"詞頻分析"發(fā)現(xiàn)熱門關(guān)鍵詞

步驟5:導(dǎo)出結(jié)果

支持三種導(dǎo)出方式:

  • Excel格式(帶格式)
  • JSON原始數(shù)據(jù)
  • 分析報告文本

核心代碼解析

1. DrissionPage智能控制

def scroll_and_collect_search(self):
    self.page = ChromiumPage()
    # 智能等待元素
    self.page.wait.ele_displayed('tag:div@@class="scroll-list"', timeout=30)
    # 模擬人類滾動
    for _ in range(scroll_times):
        self.page.scroll.to_bottom()
        time.sleep(random.uniform(1.5, 3.0))

2. 數(shù)據(jù)清洗管道

def clean_text(self, text):
    """多級清洗策略"""
    text = re.sub(r'\s+', ' ', text)  # 合并空白符
    text = re.sub(r'[^\w\u4e00-\u9fff\s]', '', text)  # 保留中文/英文/數(shù)字
    return text.strip()

3. 高性能表格渲染

# 使用Treeview的批量插入優(yōu)化
def update_data_display(self):
    self.data_tree.delete(*self.data_tree.get_children())
    items = []
    for i, data in enumerate(self.collected_data):
        items.append((i+1, data['title'][:50]+'...', ...))
    # 批量插入(比單條插入快10倍+)
    for item in items:
        self.data_tree.insert('', 'end', values=item)

源碼下載

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
from DrissionPage import ChromiumPage
from DrissionPage.errors import ElementNotFoundError
import time
import threading
import pandas as pd
import json
from datetime import datetime
import os
from urllib.parse import quote
from bs4 import BeautifulSoup
import jieba
from collections import Counter
import traceback
import re
import requests
import logging
import webbrowser

class DouyinAnalyzer:
    def __init__(self, root):
        self.root = root
        self.root.title("抖音作品分析工具")
        self.root.geometry("1000x700")
        self.root.minsize(900, 600)
        
        # 設(shè)置主題顏色
        self.primary_color = "#FF2E63"  # 抖音紅
        self.secondary_color = "#08D9D6"  # 抖音藍綠
        self.bg_color = "#F5F5F5"  # 背景灰
        self.text_color = "#333333"  # 文字深灰
        self.highlight_color = "#FF9A3C"  # 強調(diào)色
        
        # 配置樣式
        self.configure_styles()
        
        # 創(chuàng)建變量
        self.url = tk.StringVar(value="https://www.douyin.com")
        self.scroll_count = tk.StringVar(value="100")
        self.delay = tk.StringVar(value="2")
        self.browser_path = tk.StringVar(value=r"C:\Program Files\Google\Chrome\Application\chrome.exe")
        self.is_running = False
        self.collected_data = []
        self.page = None  # DrissionPage實例
        
        # 加載配置
        self.load_config()
        
        # 創(chuàng)建界面
        self.create_widgets()
        
        # 設(shè)置日志
        self.setup_logging()
    
    def configure_styles(self):
        """配置UI樣式"""
        style = ttk.Style()
        
        # 主題設(shè)置
        style.theme_use('clam')
        
        # 通用樣式
        style.configure('.', background=self.bg_color, foreground=self.text_color)
        style.configure('TFrame', background=self.bg_color)
        style.configure('TLabel', background=self.bg_color, foreground=self.text_color)
        style.configure('TButton', background=self.primary_color, foreground='white', 
                       font=('Microsoft YaHei', 10), padding=5)
        style.map('TButton', 
                  background=[('active', self.highlight_color), ('pressed', self.highlight_color)],
                  foreground=[('active', 'white'), ('pressed', 'white')])
        
        # 輸入框樣式
        style.configure('TEntry', fieldbackground='white', foreground=self.text_color)
        
        # 標(biāo)簽頁樣式
        style.configure('TNotebook', background=self.bg_color)
        style.configure('TNotebook.Tab', background=self.bg_color, foreground=self.text_color,
                       padding=[10, 5], font=('Microsoft YaHei', 10))
        style.map('TNotebook.Tab', 
                 background=[('selected', self.primary_color)],
                 foreground=[('selected', 'white')])
        
        # 樹狀視圖樣式
        style.configure('Treeview', background='white', foreground=self.text_color,
                       fieldbackground='white', rowheight=25)
        style.configure('Treeview.Heading', background=self.secondary_color, 
                       foreground='white', font=('Microsoft YaHei', 10, 'bold'))
        style.map('Treeview', background=[('selected', self.highlight_color)],
                 foreground=[('selected', 'white')])
        
        # 進度條樣式
        style.configure('Horizontal.TProgressbar', background=self.primary_color,
                       troughcolor=self.bg_color, thickness=20)
        
        # 單選按鈕樣式
        style.configure('TRadiobutton', background=self.bg_color, foreground=self.text_color)
        
        # 文本框樣式
        style.configure('Text', background='white', foreground=self.text_color,
                       insertbackground=self.primary_color)
    
    def create_widgets(self):
        """創(chuàng)建主界面"""
        # 創(chuàng)建notebook用于標(biāo)簽頁
        self.notebook = ttk.Notebook(self.root)
        self.notebook.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 創(chuàng)建各個標(biāo)簽頁
        self.create_collection_tab()
        self.create_data_tab()
        self.create_user_data_tab()
        self.create_analysis_tab()
        self.create_help_tab()
        
        # 創(chuàng)建狀態(tài)欄
        self.create_status_bar()
    
    def create_status_bar(self):
        """創(chuàng)建底部狀態(tài)欄"""
        status_frame = ttk.Frame(self.root, relief='sunken')
        status_frame.pack(fill='x', padx=5, pady=(0, 5))
        
        self.status_label = ttk.Label(status_frame, text="就緒", anchor='w')
        self.status_label.pack(side='left', padx=10)
        
        self.progress = ttk.Progressbar(status_frame, length=300, mode='determinate')
        self.progress.pack(side='right', padx=10)
    
    def create_collection_tab(self):
        """創(chuàng)建數(shù)據(jù)采集標(biāo)簽頁"""
        collection_frame = ttk.Frame(self.notebook)
        self.notebook.add(collection_frame, text='數(shù)據(jù)采集')
        
        # 主容器
        main_container = ttk.Frame(collection_frame)
        main_container.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 左側(cè)設(shè)置面板
        settings_frame = ttk.LabelFrame(main_container, text='采集設(shè)置', padding=10)
        settings_frame.pack(side='left', fill='y', padx=5, pady=5)
        
        # 瀏覽器設(shè)置
        browser_frame = ttk.LabelFrame(settings_frame, text='瀏覽器設(shè)置', padding=5)
        browser_frame.pack(fill='x', padx=5, pady=5)
        
        path_frame = ttk.Frame(browser_frame)
        path_frame.pack(fill='x', padx=5, pady=5)
        
        ttk.Label(path_frame, text="Chrome路徑:").pack(side='left', padx=5)
        path_entry = ttk.Entry(path_frame, textvariable=self.browser_path, width=40)
        path_entry.pack(side='left', padx=5, fill='x', expand=True)
        ttk.Button(path_frame, text="選擇", command=self.select_browser_path).pack(side='left', padx=5)
        
        # 數(shù)據(jù)來源設(shè)置
        source_frame = ttk.LabelFrame(settings_frame, text='數(shù)據(jù)來源', padding=5)
        source_frame.pack(fill='x', padx=5, pady=5)
        
        ttk.Label(source_frame, text="抖音鏈接:").pack(anchor='w', padx=5, pady=2)
        ttk.Entry(source_frame, textvariable=self.url, width=40).pack(fill='x', padx=5, pady=2)
        
        # 搜索設(shè)置
        search_frame = ttk.LabelFrame(settings_frame, text='關(guān)鍵詞搜索', padding=5)
        search_frame.pack(fill='x', padx=5, pady=5)
        
        ttk.Label(search_frame, text="搜索關(guān)鍵詞:").pack(anchor='w', padx=5, pady=2)
        self.search_keyword = tk.StringVar(value="音樂")
        keyword_entry = ttk.Entry(search_frame, textvariable=self.search_keyword, width=40)
        keyword_entry.pack(fill='x', padx=5, pady=2)
        keyword_entry.bind('<Return>', lambda event: self.start_search_collection())
        
        # 搜索類型選擇
        type_frame = ttk.Frame(search_frame)
        type_frame.pack(fill='x', padx=5, pady=5)
        ttk.Label(type_frame, text="搜索類型:").pack(side='left', padx=5)
        
        self.search_type = tk.StringVar(value='video')
        search_types = [('視頻', 'video'), ('用戶', 'user')]
        
        for text, value in search_types:
            ttk.Radiobutton(
                type_frame,
                text=text,
                value=value,
                variable=self.search_type
            ).pack(side='left', padx=10)
        
        # 采集參數(shù)設(shè)置
        param_frame = ttk.LabelFrame(settings_frame, text='采集參數(shù)', padding=5)
        param_frame.pack(fill='x', padx=5, pady=5)
        
        ttk.Label(param_frame, text="滾動次數(shù):").pack(anchor='w', padx=5, pady=2)
        ttk.Entry(param_frame, textvariable=self.scroll_count, width=10).pack(anchor='w', padx=5, pady=2)
        
        ttk.Label(param_frame, text="延遲(秒):").pack(anchor='w', padx=5, pady=2)
        ttk.Entry(param_frame, textvariable=self.delay, width=10).pack(anchor='w', padx=5, pady=2)
        
        # 操作按鈕
        button_frame = ttk.Frame(settings_frame)
        button_frame.pack(fill='x', pady=10)
        
        ttk.Button(button_frame, text="搜索采集", command=self.start_search_collection).pack(side='left', padx=5, fill='x', expand=True)
        ttk.Button(button_frame, text="停止采集", command=self.stop_collection).pack(side='left', padx=5, fill='x', expand=True)
        
        # 右側(cè)預(yù)覽面板
        preview_frame = ttk.LabelFrame(main_container, text='數(shù)據(jù)預(yù)覽', padding=10)
        preview_frame.pack(side='right', fill='both', expand=True, padx=5, pady=5)
        
        # 預(yù)覽文本區(qū)域
        self.preview_text = tk.Text(preview_frame, height=20, width=60, wrap=tk.WORD)
        self.preview_text.pack(fill='both', expand=True, pady=5)
        
        # 預(yù)覽控制按鈕
        preview_btn_frame = ttk.Frame(preview_frame)
        preview_btn_frame.pack(fill='x', pady=5)
        
        ttk.Button(preview_btn_frame, text="清空預(yù)覽", command=lambda: self.preview_text.delete(1.0, tk.END)).pack(side='left', padx=5)
        ttk.Button(preview_btn_frame, text="復(fù)制內(nèi)容", command=self.copy_preview_content).pack(side='left', padx=5)
    
    def create_data_tab(self):
        """創(chuàng)建數(shù)據(jù)查看標(biāo)簽頁"""
        data_frame = ttk.Frame(self.notebook)
        self.notebook.add(data_frame, text='數(shù)據(jù)查看')
        
        # 主容器
        container = ttk.Frame(data_frame)
        container.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 工具欄
        toolbar = ttk.Frame(container)
        toolbar.pack(fill='x', pady=5)
        
        # 添加導(dǎo)出按鈕
        export_menu = tk.Menubutton(toolbar, text="導(dǎo)出數(shù)據(jù)", relief='raised')
        export_menu.pack(side='left', padx=5)
        
        export_menu.menu = tk.Menu(export_menu, tearoff=0)
        export_menu["menu"] = export_menu.menu
        export_menu.menu.add_command(label="導(dǎo)出Excel", command=self.export_excel)
        export_menu.menu.add_command(label="導(dǎo)出JSON", command=self.export_json)
        
        # 添加統(tǒng)計標(biāo)簽
        self.stats_label = ttk.Label(toolbar, text="共采集到 0 條數(shù)據(jù)")
        self.stats_label.pack(side='right', padx=5)
        
        # 創(chuàng)建表格
        columns = ('序號', '標(biāo)題', '作者', '發(fā)布時間', '點贊數(shù)', '視頻鏈接')
        self.data_tree = ttk.Treeview(container, columns=columns, show='headings', selectmode='extended')
        
        # 設(shè)置列標(biāo)題和寬度
        for col in columns:
            self.data_tree.heading(col, text=col, command=lambda c=col: self.treeview_sort_column(self.data_tree, c, False))
        
        # 設(shè)置列寬
        self.data_tree.column('序號', width=50, anchor='center')
        self.data_tree.column('標(biāo)題', width=200)
        self.data_tree.column('作者', width=100)
        self.data_tree.column('發(fā)布時間', width=100)
        self.data_tree.column('點贊數(shù)', width=70, anchor='center')
        self.data_tree.column('視頻鏈接', width=200)
        
        # 添加滾動條
        scrollbar = ttk.Scrollbar(container, orient='vertical', command=self.data_tree.yview)
        self.data_tree.configure(yscrollcommand=scrollbar.set)
        
        # 使用grid布局管理器
        self.data_tree.pack(side='left', fill='both', expand=True)
        scrollbar.pack(side='right', fill='y')
        
        # 綁定雙擊事件
        self.data_tree.bind('<Double-1>', self.on_tree_double_click)
        
        # 綁定右鍵菜單事件
        self.data_tree.bind('<Button-3>', self.show_video_context_menu)
        
        # 創(chuàng)建右鍵菜單
        self.video_menu = tk.Menu(self.root, tearoff=0)
        self.video_menu.add_command(label="復(fù)制視頻鏈接", command=self.copy_video_link)
        self.video_menu.add_command(label="在瀏覽器中打開", command=self.open_in_browser)
        self.video_menu.add_separator()
        self.video_menu.add_command(label="查看詳情", command=self.show_video_details)
    
    def create_user_data_tab(self):
        """創(chuàng)建用戶數(shù)據(jù)查看標(biāo)簽頁"""
        user_frame = ttk.Frame(self.notebook)
        self.notebook.add(user_frame, text='用戶數(shù)據(jù)')
        
        # 主容器
        container = ttk.Frame(user_frame)
        container.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 工具欄
        toolbar = ttk.Frame(container)
        toolbar.pack(fill='x', pady=5)
        
        # 添加導(dǎo)出按鈕
        export_menu = tk.Menubutton(toolbar, text="導(dǎo)出數(shù)據(jù)", relief='raised')
        export_menu.pack(side='left', padx=5)
        
        export_menu.menu = tk.Menu(export_menu, tearoff=0)
        export_menu["menu"] = export_menu.menu
        export_menu.menu.add_command(label="導(dǎo)出Excel", command=self.export_user_excel)
        export_menu.menu.add_command(label="導(dǎo)出JSON", command=self.export_user_json)
        
        # 添加統(tǒng)計標(biāo)簽
        self.user_stats_label = ttk.Label(toolbar, text="共采集到 0 位用戶")
        self.user_stats_label.pack(side='right', padx=5)
        
        # 創(chuàng)建表格
        columns = ('序號', '用戶名', '抖音號', '獲贊數(shù)', '粉絲數(shù)', '簡介', '主頁鏈接', '頭像鏈接')
        self.user_tree = ttk.Treeview(container, columns=columns, show='headings', selectmode='extended')
        
        # 設(shè)置列標(biāo)題和排序功能
        for col in columns:
            self.user_tree.heading(col, text=col, command=lambda c=col: self.treeview_sort_column(self.user_tree, c, False))
        
        # 設(shè)置列寬
        self.user_tree.column('序號', width=50, anchor='center')
        self.user_tree.column('用戶名', width=150)
        self.user_tree.column('抖音號', width=100)
        self.user_tree.column('獲贊數(shù)', width=70, anchor='center')
        self.user_tree.column('粉絲數(shù)', width=70, anchor='center')
        self.user_tree.column('簡介', width=200)
        self.user_tree.column('主頁鏈接', width=150)
        self.user_tree.column('頭像鏈接', width=150)
        
        # 添加滾動條
        scrollbar = ttk.Scrollbar(container, orient='vertical', command=self.user_tree.yview)
        self.user_tree.configure(yscrollcommand=scrollbar.set)
        
        # 布局
        self.user_tree.pack(side='left', fill='both', expand=True)
        scrollbar.pack(side='right', fill='y')
        
        # 綁定雙擊事件
        self.user_tree.bind('<Double-1>', self.on_user_tree_double_click)
        
        # 綁定右鍵菜單事件
        self.user_tree.bind('<Button-3>', self.show_user_context_menu)
        
        # 創(chuàng)建右鍵菜單
        self.user_menu = tk.Menu(self.root, tearoff=0)
        self.user_menu.add_command(label="復(fù)制主頁鏈接", command=self.copy_user_link)
        self.user_menu.add_command(label="在瀏覽器中打開", command=self.open_user_in_browser)
        self.user_menu.add_separator()
        self.user_menu.add_command(label="查看詳情", command=self.show_user_details)
    
    def create_analysis_tab(self):
        """創(chuàng)建數(shù)據(jù)分析標(biāo)簽頁"""
        analysis_frame = ttk.Frame(self.notebook)
        self.notebook.add(analysis_frame, text='數(shù)據(jù)分析')
        
        # 主容器
        container = ttk.Frame(analysis_frame)
        container.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 分析選項面板
        options_frame = ttk.LabelFrame(container, text='分析選項', padding=10)
        options_frame.pack(fill='x', padx=5, pady=5)
        
        # 分析按鈕
        btn_frame = ttk.Frame(options_frame)
        btn_frame.pack(fill='x', pady=5)
        
        ttk.Button(btn_frame, text="互動數(shù)據(jù)分析", command=self.analyze_interaction_data).pack(side='left', padx=5, fill='x', expand=True)
        ttk.Button(btn_frame, text="內(nèi)容長度分析", command=self.analyze_content_length).pack(side='left', padx=5, fill='x', expand=True)
        ttk.Button(btn_frame, text="高頻詞匯分析", command=self.analyze_keywords).pack(side='left', padx=5, fill='x', expand=True)
        
        # 圖表類型選擇
        chart_frame = ttk.Frame(options_frame)
        chart_frame.pack(fill='x', pady=5)
        
        ttk.Label(chart_frame, text="圖表類型:").pack(side='left', padx=5)
        self.chart_type = tk.StringVar(value='bar')
        
        chart_types = [('柱狀圖', 'bar'), ('折線圖', 'line'), ('餅圖', 'pie')]
        for text, value in chart_types:
            ttk.Radiobutton(
                chart_frame,
                text=text,
                value=value,
                variable=self.chart_type
            ).pack(side='left', padx=5)
        
        # 分析結(jié)果區(qū)域
        result_frame = ttk.LabelFrame(container, text='分析結(jié)果', padding=10)
        result_frame.pack(fill='both', expand=True, padx=5, pady=5)
        
        # 創(chuàng)建分析結(jié)果文本框
        self.analysis_text = tk.Text(result_frame, wrap=tk.WORD, padx=10, pady=10)
        self.analysis_text.pack(fill='both', expand=True, pady=5)
        
        # 添加滾動條
        scrollbar = ttk.Scrollbar(result_frame, orient='vertical', command=self.analysis_text.yview)
        scrollbar.pack(side='right', fill='y')
        self.analysis_text.configure(yscrollcommand=scrollbar.set)
        
        # 結(jié)果操作按鈕
        result_btn_frame = ttk.Frame(result_frame)
        result_btn_frame.pack(fill='x', pady=5)
        
        ttk.Button(result_btn_frame, text="清空分析結(jié)果", command=lambda: self.analysis_text.delete(1.0, tk.END)).pack(side='left', padx=5)
        ttk.Button(result_btn_frame, text="復(fù)制結(jié)果", command=self.copy_analysis_result).pack(side='left', padx=5)
        ttk.Button(result_btn_frame, text="保存結(jié)果", command=self.save_analysis_result).pack(side='left', padx=5)
    
    def create_help_tab(self):
        """創(chuàng)建幫助標(biāo)簽頁"""
        help_frame = ttk.Frame(self.notebook)
        self.notebook.add(help_frame, text='使用幫助')
        
        # 主容器
        container = ttk.Frame(help_frame)
        container.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 創(chuàng)建幫助文本框
        help_text = tk.Text(container, wrap=tk.WORD, padx=15, pady=15)
        help_text.pack(fill='both', expand=True)
        
        # 添加標(biāo)簽用于樣式化文本
        help_text.tag_configure('title', font=('Microsoft YaHei', 14, 'bold'), foreground=self.primary_color)
        help_text.tag_configure('subtitle', font=('Microsoft YaHei', 12, 'bold'), foreground=self.secondary_color)
        help_text.tag_configure('highlight', foreground=self.highlight_color)
        
        # 添加滾動條
        scrollbar = ttk.Scrollbar(container, orient='vertical', command=help_text.yview)
        scrollbar.pack(side='right', fill='y')
        help_text.configure(yscrollcommand=scrollbar.set)
        
        # 幫助內(nèi)容
        help_content = [
            ("抖音作品分析工具使用指南\n", 'title'),
            ("\n1. 數(shù)據(jù)采集\n", 'subtitle'),
            ("支持兩種采集方式:\n- 直接輸入抖音鏈接\n- 關(guān)鍵詞搜索采集\n\n", None),
            ("關(guān)鍵詞搜索支持以下類型:\n- 視頻搜索\n- 用戶搜索\n\n", None),
            ("采集參數(shù)說明:\n- 滾動次數(shù):決定采集數(shù)據(jù)量的多少\n- 延遲(秒):每次滾動的等待時間,建議2-3秒\n\n", None),
            ("使用技巧:\n", 'highlight'),
            ("- 采集時可隨時點擊停止采集\n- 建議設(shè)置適當(dāng)?shù)难舆t避免被限制\n- 數(shù)據(jù)采集過程中請勿關(guān)閉瀏覽器窗口\n\n", None),
            ("\n2. 數(shù)據(jù)查看\n", 'subtitle'),
            ("視頻數(shù)據(jù):\n- 包含標(biāo)題、作者、發(fā)布時間等信息\n- 雙擊可直接打開視頻鏈接\n- 支持按列排序\n- 可導(dǎo)出為Excel或JSON格式\n\n", None),
            ("用戶數(shù)據(jù):\n- 顯示用戶名、抖音號、粉絲數(shù)等信息\n- 雙擊可打開用戶主頁\n- 支持數(shù)據(jù)排序\n- 可單獨導(dǎo)出用戶數(shù)據(jù)\n\n", None),
            ("\n3. 數(shù)據(jù)分析\n", 'subtitle'),
            ("互動數(shù)據(jù)分析:\n- 統(tǒng)計總點贊數(shù)、平均點贊等指標(biāo)\n- 展示互動數(shù)據(jù)分布情況\n\n", None),
            ("內(nèi)容長度分析:\n- 分析標(biāo)題長度分布\n- 顯示最長/最短標(biāo)題統(tǒng)計\n\n", None),
            ("高頻詞匯分析:\n- 提取標(biāo)題中的關(guān)鍵詞\n- 展示TOP100高頻詞匯\n- 計算詞頻占比\n\n", None),
            ("\n4. 常見問題\n", 'subtitle'),
            ("Q: 為什么采集速度較慢?\nA: 為了避免被反爬蟲機制攔截,程序設(shè)置了延遲機制。\n\n", None),
            ("Q: 如何提高采集成功率?\nA: 建議:\n- 設(shè)置適當(dāng)?shù)难舆t時間(2-3秒)\n- 避免過于頻繁的采集\n- 確保網(wǎng)絡(luò)連接穩(wěn)定\n\n", None),
            ("Q: 數(shù)據(jù)導(dǎo)出格式說明?\nA: 支持兩種格式:\n- Excel格式:適合數(shù)據(jù)分析和處理\n- JSON格式:適合數(shù)據(jù)備份和程序讀取\n\n", None),
            ("Q: 如何處理采集失敗?\nA: 可以:\n- 檢查網(wǎng)絡(luò)連接\n- 增加延遲時間\n- 減少單次采集數(shù)量\n- 更換搜索關(guān)鍵詞\n\n", None),
            ("\n5. 注意事項\n", 'subtitle'),
            ("合理使用:\n- 遵守抖音平臺規(guī)則\n- 避免頻繁、大量采集\n- 合理設(shè)置采集參數(shù)\n\n", None),
            ("數(shù)據(jù)安全:\n- 及時導(dǎo)出重要數(shù)據(jù)\n- 定期備份采集結(jié)果\n\n", None),
            ("使用建議:\n- 建議使用穩(wěn)定的網(wǎng)絡(luò)連接\n- 采集時避免其他瀏覽器操作\n- 定期清理瀏覽器緩存\n", None)
        ]
        
        # 插入幫助內(nèi)容
        for text, tag in help_content:
            if tag:
                help_text.insert('end', text, tag)
            else:
                help_text.insert('end', text)
        
        help_text.config(state='disabled')  # 設(shè)置為只讀
    
    # ====================== 以下是原有功能方法 ======================
    # 由于篇幅限制,這里只展示UI優(yōu)化部分,原有功能方法保持不變
    # 請將原始代碼中的功能方法復(fù)制到這里,保持完整功能
    
    def setup_logging(self):
        """設(shè)置日志"""
        log_dir = "logs"
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
            
        log_file = os.path.join(log_dir, f"douyin_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log")
        
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file, encoding='utf-8'),
                logging.StreamHandler()
            ]
        )
    
    def copy_preview_content(self):
        """復(fù)制預(yù)覽內(nèi)容到剪貼板"""
        content = self.preview_text.get(1.0, tk.END)
        if content.strip():
            self.root.clipboard_clear()
            self.root.clipboard_append(content)
            messagebox.showinfo("成功", "預(yù)覽內(nèi)容已復(fù)制到剪貼板")
    
    def copy_analysis_result(self):
        """復(fù)制分析結(jié)果到剪貼板"""
        content = self.analysis_text.get(1.0, tk.END)
        if content.strip():
            self.root.clipboard_clear()
            self.root.clipboard_append(content)
            messagebox.showinfo("成功", "分析結(jié)果已復(fù)制到剪貼板")
    
    def save_analysis_result(self):
        """保存分析結(jié)果到文件"""
        content = self.analysis_text.get(1.0, tk.END)
        if not content.strip():
            messagebox.showwarning("警告", "沒有可保存的分析結(jié)果!")
            return
        
        filename = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
            initialfile=f"分析結(jié)果_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
        )
        
        if filename:
            try:
                with open(filename, 'w', encoding='utf-8') as f:
                    f.write(content)
                messagebox.showinfo("成功", f"分析結(jié)果已保存到:\n{filename}")
            except Exception as e:
                messagebox.showerror("錯誤", f"保存文件失敗: {str(e)}")
    
    def show_video_details(self):
        """顯示視頻詳情"""
        selection = self.data_tree.selection()
        if not selection:
            return
        
        item = selection[0]
        values = self.data_tree.item(item)['values']
        if not values:
            return
        
        details = f"視頻詳情:\n\n標(biāo)題: {values[1]}\n作者: {values[2]}\n發(fā)布時間: {values[3]}\n點贊數(shù): {values[4]}\n鏈接: {values[5]}"
        messagebox.showinfo("視頻詳情", details)
    
    def show_user_details(self):
        """顯示用戶詳情"""
        selection = self.user_tree.selection()
        if not selection:
            return
        
        item = selection[0]
        values = self.user_tree.item(item)['values']
        if not values:
            return
        
        details = f"用戶詳情:\n\n用戶名: {values[1]}\n抖音號: {values[2]}\n獲贊數(shù): {values[3]}\n粉絲數(shù): {values[4]}\n簡介: {values[5]}\n主頁鏈接: {values[6]}"
        messagebox.showinfo("用戶詳情", details)
    
    def show_user_context_menu(self, event):
        """顯示用戶右鍵菜單"""
        try:
            item = self.user_tree.identify_row(event.y)
            if not item:
                return
            
            self.user_tree.selection_set(item)
            self.user_menu.post(event.x_root, event.y_root)
        except Exception as e:
            print(f"顯示用戶右鍵菜單錯誤: {str(e)}")
    
    def copy_user_link(self):
        """復(fù)制用戶鏈接到剪貼板"""
        selection = self.user_tree.selection()
        if not selection:
            return
        
        item = selection[0]
        values = self.user_tree.item(item)['values']
        if not values:
            return
        
        user_url = values[6]
        if user_url:
            self.root.clipboard_clear()
            self.root.clipboard_append(user_url)
            messagebox.showinfo("成功", "用戶主頁鏈接已復(fù)制到剪貼板")
    
    def open_user_in_browser(self):
        """在瀏覽器中打開用戶主頁"""
        selection = self.user_tree.selection()
        if not selection:
            return
        
        item = selection[0]
        values = self.user_tree.item(item)['values']
        if not values:
            return
        
        user_url = values[6]
        if user_url:
            if not user_url.startswith('http'):
                if user_url.startswith('//'):
                    user_url = 'https:' + user_url
                else:
                    user_url = 'https://www.douyin.com' + user_url
            
            webbrowser.open(user_url)

    def on_tree_double_click(self, event):
        """處理表格雙擊事件"""
        try:
            item = self.data_tree.selection()[0]
            values = self.data_tree.item(item)['values']
            if not values:
                return
                 
            video_url = values[5]  # 獲取視頻鏈接
            if video_url:
                # 確保URL格式正確
                if not video_url.startswith('http'):
                    if video_url.startswith('//'):
                        video_url = 'https:' + video_url
                    elif video_url.startswith('/'):
                        video_url = 'https://www.douyin.com' + video_url
                    else:
                        video_url = 'https://www.douyin.com/' + video_url
                 
                # 使用默認瀏覽器打開鏈接
                import webbrowser
                webbrowser.open(video_url)
                 
        except Exception as e:
            print(f"打開視頻鏈接錯誤: {str(e)}")
            messagebox.showerror("錯誤", "無法打開視頻鏈接")
 
    def on_user_tree_double_click(self, event):
        """處理用戶表格雙擊事件"""
        try:
            item = self.user_tree.selection()[0]
            values = self.user_tree.item(item)['values']
            if not values:
                return
             
            user_url = values[6]  # 獲取用戶主頁鏈接
            if user_url:
                # 確保URL格式正確
                if not user_url.startswith('http'):
                    if user_url.startswith('//'):
                        user_url = 'https:' + user_url
                    elif user_url.startswith('/'):
                        user_url = 'https://www.douyin.com' + user_url
                    else:
                        user_url = 'https://www.douyin.com/' + user_url
                 
                # 使用默認瀏覽器打開鏈接
                import webbrowser
                webbrowser.open(user_url)
             
        except Exception as e:
            print(f"打開用戶主頁鏈接錯誤: {str(e)}")
            messagebox.showerror("錯誤", "無法打開用戶主頁鏈接")
 
    def create_analysis_tab(self):
        """創(chuàng)建數(shù)據(jù)分析標(biāo)簽頁"""
        analysis_frame = ttk.Frame(self.notebook)
        self.notebook.add(analysis_frame, text='數(shù)據(jù)分析')
         
        # 創(chuàng)建分析結(jié)果文本框
        self.analysis_text = tk.Text(analysis_frame, height=20, width=60)
        self.analysis_text.pack(pady=10, padx=10, fill='both', expand=True)
         
        # 創(chuàng)建按鈕框架
        button_frame = ttk.Frame(analysis_frame)
        button_frame.pack(pady=5)
         
        # 添加分析按鈕
        ttk.Button(button_frame, text="互動數(shù)據(jù)分析", command=self.analyze_interaction_data).pack(side='left', padx=5)
        ttk.Button(button_frame, text="內(nèi)容長度分析", command=self.analyze_content_length).pack(side='left', padx=5)
        ttk.Button(button_frame, text="高頻詞匯分析", command=self.analyze_keywords).pack(side='left', padx=5)
        ttk.Button(button_frame, text="清空分析結(jié)果", command=lambda: self.analysis_text.delete(1.0, tk.END)).pack(side='left', padx=5)
     
    def start_search_collection(self):
        """開始搜索采集"""
        try:
            # 驗證輸入
            keyword = self.search_keyword.get().strip()
            if not keyword:
                messagebox.showwarning("警告", "請輸入搜索關(guān)鍵詞!")
                return
             
            scroll_count = self.scroll_count.get().strip()
            if not scroll_count.isdigit():
                messagebox.showwarning("警告", "滾動次數(shù)必須是正整數(shù)!")
                return
             
            delay = self.delay.get().strip()
            try:
                delay = float(delay)
                if delay <= 0:
                    raise ValueError
            except ValueError:
                messagebox.showwarning("警告", "延遲時間必須是正數(shù)!")
                return
             
            # 檢查是否已經(jīng)在運行
            if self.is_running:
                messagebox.showwarning("警告", "采集正在進行中!")
                return
             
            # 清空之前的數(shù)據(jù)
            self.collected_data = []
            self.update_data_display()
             
            # 更新狀態(tài)
            self.status_label.config(text="正在啟動采集...")
            self.progress['value'] = 0
             
            # 啟動采集線程
            self.is_running = True
            threading.Thread(target=self.scroll_and_collect_search, daemon=True).start()
             
        except Exception as e:
            self.is_running = False
            error_msg = f"啟動采集失敗: {str(e)}"
            print(error_msg)
            print(traceback.format_exc())
            messagebox.showerror("錯誤", error_msg)
 
    def init_browser(self):
        """初始化瀏覽器"""
        try:
            if self.page is None:
                from DrissionPage import ChromiumPage
                 
                # 直接創(chuàng)建頁面對象,使用最簡單的方式
                self.page = ChromiumPage()
                 
                # 如果需要設(shè)置瀏覽器路徑,可以使用這種方式
                # self.page.set.browser_path = self.browser_path.get()
                 
                time.sleep(2)  # 等待瀏覽器啟動
                return True
                 
            return True
             
        except Exception as e:
            print(f"初始化瀏覽器失敗: {str(e)}")
            print(traceback.format_exc())
            messagebox.showerror("錯誤", f"初始化瀏覽器失敗: {str(e)}\n請檢查Chrome瀏覽器路徑是否正確")
            return False
 
    def scroll_and_collect_search(self):
        """滾動頁面并收集搜索結(jié)果數(shù)據(jù)"""
        if not self.init_browser():
            return
             
        try:
            # 構(gòu)建搜索URL
            keyword = self.search_keyword.get().strip()
            search_type = self.search_type.get()
            search_url = f"https://www.douyin.com/search/{quote(keyword)}?source=normal_search&type={search_type}"
            print(f"訪問搜索URL: {search_url}")
             
            # 訪問頁面
            self.page.get(search_url)
            time.sleep(5)  # 增加等待時間
             
            # 直接開始采集
            print("開始采集...")
             
            # 獲取滾動次數(shù)和延遲
            scroll_times = int(self.scroll_count.get())
            delay = float(self.delay.get())
             
            # 開始滾動和采集
            last_height = self.page.run_js("return document.body.scrollHeight")
             
            for i in range(scroll_times):
                if not self.is_running:
                    break
                 
                try:
                    # 滾動頁面
                    self.page.run_js("window.scrollTo(0, document.body.scrollHeight)")
                    time.sleep(delay)
                     
                    # 檢查是否到達底部
                    new_height = self.page.run_js("return document.body.scrollHeight")
                    if new_height == last_height:
                        print("已到達頁面底部")
                        break
                    last_height = new_height
                     
                    # 獲取頁面源碼并解析
                    page_source = self.page.html
                    soup = BeautifulSoup(page_source, 'html.parser')
                     
                    # 根據(jù)搜索類型選擇不同的提取方法
                    if search_type == 'user':
                        new_data = self.extract_user_data(soup)
                    else:
                        container = soup.select_one('[data-e2e="scroll-list"]')
                        if container:
                            new_data = self.extract_video_items(container)
                        else:
                            print("未找到視頻列表容器")
                            continue
                     
                    print(f"本次滾動找到 {len(new_data)} 條新數(shù)據(jù)")
                     
                    # 添加新數(shù)據(jù)(去重)
                    for data in new_data:
                        if data not in self.collected_data:
                            self.collected_data.append(data)
                     
                    print(f"當(dāng)前總共采集 {len(self.collected_data)} 條數(shù)據(jù)")
                     
                    # 更新數(shù)據(jù)顯示
                    self.root.after(0, self.update_data_display)
                     
                    # 更新狀態(tài)
                    self.root.after(0, lambda: self.status_label.config(text=f"正在滾動... ({i+1}/{scroll_times})"))
                    self.root.after(0, lambda: self.progress.configure(value=((i + 1) / scroll_times * 100)))
                     
                except Exception as e:
                    print(f"滾動錯誤: {str(e)}")
                    continue
             
            print("搜索結(jié)果采集完成")
            self.root.after(0, lambda: self.status_label.config(text=f"采集完成,共獲取{len(self.collected_data)}條數(shù)據(jù)"))
             
        except Exception as e:
            error_msg = f"采集過程出錯: {str(e)}"
            print(error_msg)
            print(traceback.format_exc())
            self.root.after(0, lambda: messagebox.showerror("錯誤", error_msg))
             
        finally:
            self.is_running = False
            if self.page:
                self.page.quit()  # 關(guān)閉瀏覽器
 
    def extract_video_data(self, html):
        """提取數(shù)據(jù)"""
        if self.search_type.get() == 'user':
            return self.extract_user_data(html)
        else:
            return self.extract_video_items(html)
 
    def extract_user_data(self, html):
        """提取用戶數(shù)據(jù)"""
        print("開始提取用戶數(shù)據(jù)...")
         
        # 使用正確的選擇器定位用戶列表
        user_items = html.select("div.search-result-card > a.hY8lWHgA.poLTDMYS")  # 更新選擇器
        print(f"找到 {len(user_items)} 個用戶項")
         
        user_data = []
         
        for item in user_items:
            try:
                # 獲取用戶鏈接
                user_link = item.get('href', '')
                 
                # 獲取標(biāo)題
                title_elem = item.select_one('div.XQwChAbX p.v9LWb7QE span span span span span')
                title = title_elem.get_text(strip=True) if title_elem else ''
                 
                # 獲取頭像URL
                avatar_elem = item.select_one('img.RlLOO79h')
                avatar_url = avatar_elem.get('src', '') if avatar_elem else ''
                 
                # 獲取統(tǒng)計數(shù)據(jù)
                stats_div = item.select_one('div.jjebLXt0')
                douyin_id = ''
                likes = '0'
                followers = '0'
                 
                if stats_div:
                    spans = stats_div.select('span')
                    for span in spans:
                        text = span.get_text(strip=True)
                        print(f"處理span文本: {text}")  # 調(diào)試輸出
                         
                        if '抖音號:' in text or '抖音號:' in text:
                            id_span = span.select_one('span')
                            if id_span:
                                douyin_id = id_span.get_text(strip=True)
                        elif '獲贊' in text:
                            likes = text.replace('獲贊', '').strip()
                        elif '粉絲' in text:
                            followers = text.replace('粉絲', '').strip()
                 
                # 獲取簡介
                desc_elem = item.select_one('p.Kdb5Km3i span span span span span')
                description = desc_elem.get_text(strip=True) if desc_elem else ''
                 
                # 構(gòu)建數(shù)據(jù)
                data = {
                    'title': title,
                    'douyin_id': douyin_id,
                    'likes': likes,
                    'followers': followers,
                    'description': description,
                    'avatar_url': avatar_url,
                    'user_link': user_link
                }
                 
                # 清理數(shù)據(jù)
                data = {k: self.clean_text(str(v)) for k, v in data.items()}
                 
                # 格式化數(shù)字
                data['likes'] = self.format_number(data['likes'])
                data['followers'] = self.format_number(data['followers'])
                 
                # 處理用戶鏈接
                if data['user_link'] and not data['user_link'].startswith('http'):
                    data['user_link'] = 'https://www.douyin.com' + data['user_link']
                 
                # 打印調(diào)試信息
                print("\n提取到的數(shù)據(jù):")
                for key, value in data.items():
                    print(f"{key}: {value}")
                 
                # 只要有標(biāo)題就添加
                if data['title']:
                    if data not in user_data:  # 確保不重復(fù)添加
                        user_data.append(data)
                        print(f"成功提取用戶數(shù)據(jù): {data['title']}")
                 
            except Exception as e:
                print(f"提取單個用戶數(shù)據(jù)錯誤: {str(e)}")
                traceback.print_exc()  # 打印完整的錯誤堆棧
                continue
         
        print(f"總共提取到 {len(user_data)} 條用戶數(shù)據(jù)")
        return user_data
 
    def _extract_basic_info(self, item):
        """提取基本信息"""
        # 獲取用戶鏈接
        user_link = item.select_one('a.uz1VJwFY')  # 使用確切的類名
         
        # 獲取標(biāo)題
        title = ""
        title_elem = item.select_one('p.ZMZLqKYm span')  # 使用確切的類名和結(jié)構(gòu)
        if title_elem:
            title = title_elem.get_text(strip=True)
         
        # 獲取頭像URL
        avatar_elem = item.select_one('img.fiWP27dC')
        avatar_url = avatar_elem.get('src', '') if avatar_elem else ''
         
        return {
            'title': title,
            'douyin_id': '',
            'likes': '',
            'followers': '',
            'description': '',
            'avatar_url': avatar_url,
            'user_link': user_link.get('href', '') if user_link else ''
        }
 
    def _extract_stats_info(self, item, data):
        """提取統(tǒng)計信息"""
        stats_div = item.select_one('div.Y6iuJGlc')  # 使用確切的類名
         
        if stats_div:
            spans = stats_div.select('span')
            spans_text = [span.get_text(strip=True) for span in spans]
            print(f"找到的span文本: {spans_text}")  # 調(diào)試輸出
             
            for text in spans_text:
                if '抖音號:' in text or '抖音號:' in text:
                    # 獲取嵌套的span中的抖音號
                    nested_span = stats_div.select_one('span > span')
                    if nested_span:
                        data['douyin_id'] = nested_span.get_text(strip=True)
                elif '獲贊' in text:
                    data['likes'] = text.replace('獲贊', '').strip()
                elif '粉絲' in text:
                    data['followers'] = text.replace('粉絲', '').strip()
 
    def _extract_description(self, item, data):
        """提取用戶簡介"""
        desc_elem = item.select_one('p.NYqiIDUo span')  # 使用確切的類名和結(jié)構(gòu)
        if desc_elem:
            # 獲取純文本內(nèi)容,去除表情圖片
            text_nodes = [node for node in desc_elem.stripped_strings]
            data['description'] = ' '.join(text_nodes)
 
    def _clean_and_format_data(self, data):
        """清理和格式化數(shù)據(jù)"""
        # 清理文本數(shù)據(jù)
        for key in data:
            if isinstance(data[key], str):
                data[key] = self.clean_text(data[key])
         
        # 格式化數(shù)字
        data['likes'] = self.format_number(data['likes'])
        data['followers'] = self.format_number(data['followers'])
         
        # 處理用戶鏈接
        if data['user_link']:
            link = data['user_link']
            # 移除查詢參數(shù)
            if '?' in link:
                link = link.split('?')[0]
            # 確保正確的格式
            if link.startswith('//'):
                link = 'https:' + link
            elif not link.startswith('http'):
                # 移除可能的重復(fù)路徑
                link = link.replace('www.douyin.com/', '')
                link = link.replace('//', '/')
                if not link.startswith('/'):
                    link = '/' + link
                link = 'https://www.douyin.com' + link
             
            print(f"原始鏈接: {data['user_link']}")  # 調(diào)試輸出
            print(f"處理后鏈接: {link}")  # 調(diào)試輸出
            data['user_link'] = link
 
    def _print_debug_info(self, data):
        """打印調(diào)試信息"""
        print("\n提取到的數(shù)據(jù):")
        print(f"標(biāo)題: {data['title']}")
        print(f"抖音號: {data['douyin_id']}")
        print(f"獲贊: {data['likes']}")
        print(f"粉絲: {data['followers']}")
        print(f"簡介: {data['description'][:50]}...")
        print(f"鏈接: {data['user_link']}")
 
    def extract_video_items(self, html):
        """提取視頻數(shù)據(jù)(原有代碼)"""
        video_items = html.select("li.SwZLHMKk")
        video_data = []
         
        for item in video_items:
            try:
                # 獲取視頻鏈接
                video_link = item.select_one('a.hY8lWHgA')
                if not video_link:
                    continue
                 
                # 構(gòu)建數(shù)據(jù)
                data = {
                    'video_url': video_link['href'].strip(),
                    'cover_image': item.select_one('img')['src'].strip() if item.select_one('img') else '',
                    'title': item.select_one('div.VDYK8Xd7').text.strip() if item.select_one('div.VDYK8Xd7') else '無標(biāo)題',
                    'author': item.select_one('span.MZNczJmS').text.strip() if item.select_one('span.MZNczJmS') else '未知作者',
                    'publish_time': item.select_one('span.faDtinfi').text.strip() if item.select_one('span.faDtinfi') else '',
                    'likes': item.select_one('span.cIiU4Muu').text.strip() if item.select_one('span.cIiU4Muu') else '0'
                }
                 
                # 清理數(shù)據(jù)
                data = {k: self.clean_text(str(v)) for k, v in data.items()}
                 
                # 驗證數(shù)據(jù)完整性
                if all(data.values()):
                    video_data.append(data)
                else:
                    print(f"跳過不完整數(shù)據(jù): {data}")
                 
            except Exception as e:
                print(f"提取單個視頻數(shù)據(jù)錯誤: {str(e)}")
                continue
         
        return video_data
 
    def update_data_display(self):
        """更新數(shù)據(jù)顯示"""
        try:
            search_type = self.search_type.get()
            print(f"更新數(shù)據(jù)顯示,搜索類型: {search_type}")
            print(f"當(dāng)前數(shù)據(jù)數(shù)量: {len(self.collected_data)}")
             
            if search_type == 'user':
                self.notebook.select(2)  # 先切換到用戶數(shù)據(jù)標(biāo)簽頁
                self.root.after(100, self.update_user_display)  # 延遲一小段時間后更新顯示
            else:
                self.notebook.select(1)  # 切換到視頻數(shù)據(jù)標(biāo)簽頁
                self.root.after(100, self.update_video_display)
             
        except Exception as e:
            print(f"更新數(shù)據(jù)顯示錯誤: {str(e)}")
 
    def update_user_display(self):
        """更新用戶數(shù)據(jù)顯示"""
        try:
            # 清空現(xiàn)有顯示
            self.user_tree.delete(*self.user_tree.get_children())
             
            # 添加新數(shù)據(jù)
            for i, data in enumerate(self.collected_data):
                try:
                    # 格式化簡介
                    description = data.get('description', '')
                    if len(description) > 50:
                        description = description[:47] + '...'
                     
                    # 格式化數(shù)據(jù)
                    values = (
                        i + 1,
                        data.get('title', ''),
                        data.get('douyin_id', ''),
                        self.format_number(str(data.get('likes', '0'))),
                        self.format_number(str(data.get('followers', '0'))),
                        description,
                        data.get('user_link', ''),
                        data.get('avatar_url', '')
                    )
                     
                    self.user_tree.insert('', 'end', values=values)
                    print(f"顯示用戶數(shù)據(jù): {data.get('title', '')}")
                     
                except Exception as e:
                    print(f"處理單條用戶數(shù)據(jù)顯示錯誤: {str(e)}")
                    continue
             
            # 更新統(tǒng)計
            self.user_stats_label.config(text=f"共采集到 {len(self.collected_data)} 位用戶")
            print(f"更新用戶統(tǒng)計: {len(self.collected_data)} 位用戶")
             
            # 自動滾動到最新數(shù)據(jù)
            if self.user_tree.get_children():
                self.user_tree.see(self.user_tree.get_children()[-1])
             
        except Exception as e:
            print(f"更新用戶數(shù)據(jù)顯示錯誤: {str(e)}")
 
    def update_video_display(self):
        """更新視頻數(shù)據(jù)顯示(原有的update_data_display邏輯)"""
        try:
            # 清空現(xiàn)有顯示
            self.data_tree.delete(*self.data_tree.get_children())
             
            # 添加新數(shù)據(jù)
            for i, data in enumerate(self.collected_data):
                try:
                    title = data.get('title', '')
                    if len(title) > 50:
                        title = title[:47] + '...'
                     
                    values = (
                        i + 1,
                        title,
                        data.get('author', '未知作者'),
                        data.get('publish_time', ''),
                        self.format_number(str(data.get('likes', '0'))),
                        data.get('video_url', '')
                    )
                     
                    self.data_tree.insert('', 'end', values=values)
                     
                except Exception as e:
                    print(f"處理單條數(shù)據(jù)顯示錯誤: {str(e)}")
                    continue
             
            # 更新統(tǒng)計
            self.stats_label.config(text=f"共采集到 {len(self.collected_data)} 條數(shù)據(jù)")
             
            # 自動滾動到最新數(shù)據(jù)
            if self.data_tree.get_children():
                self.data_tree.see(self.data_tree.get_children()[-1])
             
        except Exception as e:
            print(f"更新數(shù)據(jù)顯示錯誤: {str(e)}")
 
    def update_data_stats(self):
        """更新數(shù)據(jù)統(tǒng)計"""
        try:
            total_count = len(self.collected_data)
            self.stats_label.config(text=f"共采集到 {total_count} 條數(shù)據(jù)")
        except Exception as e:
            print(f"更新統(tǒng)計信息錯誤: {str(e)}")
 
    def stop_collection(self):
        """停止數(shù)據(jù)采集"""
        if self.is_running:
            self.is_running = False
            self.status_label.config(text="已停止采集")
            print("采集已停止")
        else:
            print("當(dāng)前沒有正在進行的采集任務(wù)")
 
    def export_excel(self):
        """導(dǎo)出數(shù)據(jù)到Excel"""
        if not self.collected_data:
            messagebox.showwarning("警告", "沒有數(shù)據(jù)可導(dǎo)出!")
            return
             
        try:
            filename = f"抖音數(shù)據(jù)_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
            df = pd.DataFrame(self.collected_data)
            df.to_excel(filename, index=False)
            messagebox.showinfo("成功", f"數(shù)據(jù)已導(dǎo)出到: {filename}")
        except Exception as e:
            messagebox.showerror("錯誤", f"導(dǎo)出Excel失敗: {str(e)}")
 
    def export_json(self):
        """導(dǎo)出數(shù)據(jù)到JSON"""
        if not self.collected_data:
            messagebox.showwarning("警告", "沒有數(shù)據(jù)可導(dǎo)出!")
            return
             
        try:
            filename = f"抖音數(shù)據(jù)_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(self.collected_data, f, ensure_ascii=False, indent=2)
            messagebox.showinfo("成功", f"數(shù)據(jù)已導(dǎo)出到: {filename}")
        except Exception as e:
            messagebox.showerror("錯誤", f"導(dǎo)出JSON失敗: {str(e)}")
 
    def export_user_excel(self):
        """導(dǎo)出用戶數(shù)據(jù)到Excel"""
        if not self.collected_data or self.search_type.get() != 'user':
            messagebox.showwarning("警告", "沒有用戶數(shù)據(jù)可導(dǎo)出!")
            return
         
        try:
            filename = f"抖音用戶數(shù)據(jù)_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
            df = pd.DataFrame(self.collected_data)
            df.to_excel(filename, index=False)
            messagebox.showinfo("成功", f"用戶數(shù)據(jù)已導(dǎo)出到: {filename}")
        except Exception as e:
            messagebox.showerror("錯誤", f"導(dǎo)出Excel失敗: {str(e)}")
 
    def export_user_json(self):
        """導(dǎo)出用戶數(shù)據(jù)到JSON"""
        if not self.collected_data or self.search_type.get() != 'user':
            messagebox.showwarning("警告", "沒有用戶數(shù)據(jù)可導(dǎo)出!")
            return
         
        try:
            filename = f"抖音用戶數(shù)據(jù)_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(self.collected_data, f, ensure_ascii=False, indent=2)
            messagebox.showinfo("成功", f"用戶數(shù)據(jù)已導(dǎo)出到: {filename}")
        except Exception as e:
            messagebox.showerror("錯誤", f"導(dǎo)出JSON失敗: {str(e)}")
 
    def clean_text(self, text):
        """清理文本"""
        return text.replace('\n', ' ').replace('\r', '').strip()
 
    def format_number(self, num_str):
        """格式化數(shù)字字符串"""
        try:
            num = int(num_str)
            if num >= 10000:
                return f"{num / 10000:.1f}萬"
            return str(num)
        except ValueError:
            return num_str
 
    def analyze_interaction_data(self):
        """分析互動數(shù)據(jù)"""
        if not self.collected_data:
            messagebox.showwarning("警告", "沒有可分析的數(shù)據(jù)!")
            return
         
        try:
            # 將點贊數(shù)轉(zhuǎn)換為數(shù)字
            likes_data = []
            for data in self.collected_data:
                likes = str(data['likes'])
                try:
                    if '萬' in likes:
                        # 處理帶"萬"的數(shù)字
                        num = float(likes.replace('萬', '')) * 10000
                        likes_data.append(int(num))
                    else:
                        # 處理普通數(shù)字
                        likes_data.append(int(likes))
                except (ValueError, TypeError):
                    print(f"無法解析的點贊數(shù): {likes}")
                    continue
             
            # 計算統(tǒng)計數(shù)據(jù)
            total_likes = sum(likes_data)
            avg_likes = total_likes / len(likes_data) if likes_data else 0
            max_likes = max(likes_data) if likes_data else 0
             
            # 生成報告
            report = "===== 互動數(shù)據(jù)分析報告 =====\n\n"
            report += f"總視頻數(shù): {len(self.collected_data)}\n"
            report += f"總點贊數(shù): {self.format_large_number(total_likes)}\n"
            report += f"平均點贊數(shù): {self.format_large_number(int(avg_likes))}\n"
            report += f"最高點贊數(shù): {self.format_large_number(max_likes)}\n"
             
            # 顯示分析結(jié)果
            self.analysis_text.delete(1.0, tk.END)
            self.analysis_text.insert(tk.END, report)
             
        except Exception as e:
            print(f"互動數(shù)據(jù)分析錯誤: {str(e)}")
            messagebox.showerror("錯誤", f"分析失敗: {str(e)}")
 
    def format_large_number(self, num):
        """格式化大數(shù)字顯示"""
        if num >= 10000:
            return f"{num/10000:.1f}萬"
        return str(num)
 
    def analyze_content_length(self):
        """分析內(nèi)容長度"""
        if not self.collected_data:
            messagebox.showwarning("警告", "沒有可分析的數(shù)據(jù)!")
            return
         
        try:
            # 計算標(biāo)題長度
            title_lengths = [len(data['title']) for data in self.collected_data]
             
            # 計算統(tǒng)計數(shù)據(jù)
            avg_length = sum(title_lengths) / len(title_lengths)
            max_length = max(title_lengths)
            min_length = min(title_lengths)
             
            # 生成報告
            report = "===== 內(nèi)容長度分析報告 =====\n\n"
            report += f"平均標(biāo)題長度: {avg_length:.1f}字\n"
            report += f"最長標(biāo)題: {max_length}字\n"
            report += f"最短標(biāo)題: {min_length}字\n\n"
             
            # 添加長度分布統(tǒng)計
            length_ranges = [(0, 10), (11, 20), (21, 30), (31, 50), (51, 100), (101, float('inf'))]
            report += "標(biāo)題長度分布:\n"
            for start, end in length_ranges:
                count = sum(1 for length in title_lengths if start <= length <= end)
                range_text = f"{start}-{end}字" if end != float('inf') else f"{start}字以上"
                percentage = (count / len(title_lengths)) * 100
                report += f"{range_text}: {count}個 ({percentage:.1f}%)\n"
             
            # 顯示分析結(jié)果
            self.analysis_text.delete(1.0, tk.END)
            self.analysis_text.insert(tk.END, report)
             
        except Exception as e:
            messagebox.showerror("錯誤", f"分析失敗: {str(e)}")
 
    def analyze_keywords(self):
        """分析標(biāo)題中的高頻詞匯"""
        if not self.collected_data:
            messagebox.showwarning("警告", "沒有可分析的數(shù)據(jù)!")
            return
         
        try:
            # 合并所有標(biāo)題文本
            all_titles = ' '.join(data['title'] for data in self.collected_data)
             
            # 設(shè)置停用詞
            stop_words = {
                '的', '了', '是', '在', '我', '有', '和', '就',
                '都', '而', '及', '與', '著', '或', '等', '為',
                '一個', '沒有', '這個', '那個', '但是', '而且',
                '只是', '不過', '這樣', '一樣', '一直', '一些',
                '這', '那', '也', '你', '我們', '他們', '它們',
                '把', '被', '讓', '向', '往', '但', '去', '又',
                '能', '好', '給', '到', '看', '想', '要', '會',
                '多', '能', '這些', '那些', '什么', '怎么', '如何',
                '為什么', '可以', '因為', '所以', '應(yīng)該', '可能', '應(yīng)該'
            }
             
            # 使用jieba進行分詞
            words = []
            for word in jieba.cut(all_titles):
                if len(word) > 1 and word not in stop_words:  # 過濾單字詞和停用詞
                    words.append(word)
             
            # 統(tǒng)計詞頻
            word_counts = Counter(words)
             
            # 生成報告
            report = "===== 高頻詞匯分析報告 =====\n\n"
            report += f"總標(biāo)題數(shù): {len(self.collected_data)}\n"
            report += f"總詞匯量: {len(words)}\n"
            report += f"不同詞匯數(shù): {len(word_counts)}\n\n"
             
            # 顯示高頻詞匯(TOP 100)
            report += "高頻詞匯 TOP 100:\n"
            report += "-" * 40 + "\n"
            report += "排名\t詞匯\t\t出現(xiàn)次數(shù)\t頻率\n"
            report += "-" * 40 + "\n"
             
            for rank, (word, count) in enumerate(word_counts.most_common(100), 1):
                frequency = (count / len(words)) * 100
                report += f"{rank}\t{word}\t\t{count}\t\t{frequency:.2f}%\n"
             
            # 顯示分析結(jié)果
            self.analysis_text.delete(1.0, tk.END)
            self.analysis_text.insert(tk.END, report)
             
        except Exception as e:
            print(f"高頻詞匯分析錯誤: {str(e)}")
            messagebox.showerror("錯誤", f"分析失敗: {str(e)}")
 
    def treeview_sort_column(self, tree, col, reverse):
        """列排序函數(shù)"""
        # 獲取所有項目
        l = [(tree.set(k, col), k) for k in tree.get_children('')]
         
        try:
            # 嘗試將數(shù)值型數(shù)據(jù)轉(zhuǎn)換為數(shù)字進行排序
            if col in ['序號', '獲贊數(shù)', '粉絲數(shù)', '點贊數(shù)']:
                # 處理帶"萬"的數(shù)字
                def convert_number(x):
                    try:
                        if '萬' in x[0]:
                            return float(x[0].replace('萬', '')) * 10000
                        return float(x[0])
                    except ValueError:
                        return 0
                 
                l.sort(key=convert_number, reverse=reverse)
            else:
                # 字符串排序
                l.sort(reverse=reverse)
        except Exception as e:
            print(f"排序錯誤: {str(e)}")
            # 如果轉(zhuǎn)換失敗,按字符串排序
            l.sort(reverse=reverse)
         
        # 重新排列項目
        for index, (val, k) in enumerate(l):
            tree.move(k, '', index)
            # 更新序號
            tree.set(k, '序號', str(index + 1))
         
        # 切換排序方向
        tree.heading(col, command=lambda: self.treeview_sort_column(tree, col, not reverse))
 
    def create_help_tab(self):
        """創(chuàng)建幫助標(biāo)簽頁"""
        help_frame = ttk.Frame(self.notebook)
        self.notebook.add(help_frame, text='使用幫助')
         
        # 創(chuàng)建幫助文本框
        help_text = tk.Text(help_frame, wrap=tk.WORD, padx=10, pady=10)
        help_text.pack(fill='both', expand=True)
         
        # 添加滾動條
        scrollbar = ttk.Scrollbar(help_frame, orient='vertical', command=help_text.yview)
        scrollbar.pack(side='right', fill='y')
        help_text.configure(yscrollcommand=scrollbar.set)
         
        # 幫助內(nèi)容
        help_content = """
抖音作品分析工具使用指南
====================
 
1. 數(shù)據(jù)采集
-----------------
 支持兩種采集方式:
  - 直接輸入抖音鏈接
  - 關(guān)鍵詞搜索采集
 
 關(guān)鍵詞搜索支持以下類型:
  - 視頻搜索
  - 用戶搜索
 
 采集參數(shù)說明:
  - 滾動次數(shù):決定采集數(shù)據(jù)量的多少
  - 延遲(秒):每次滾動的等待時間,建議2-3秒
 
 使用技巧:
  - 采集時可隨時點擊"停止采集"
  - 建議設(shè)置適當(dāng)?shù)难舆t避免被限制
  - 數(shù)據(jù)采集過程中請勿關(guān)閉瀏覽器窗口
 
2. 數(shù)據(jù)查看
-----------------
 視頻數(shù)據(jù):
  - 包含標(biāo)題、作者、發(fā)布時間等信息
  - 雙擊可直接打開視頻鏈接
  - 支持按列排序
  - 可導(dǎo)出為Excel或JSON格式
 
 用戶數(shù)據(jù):
  - 顯示用戶名、抖音號、粉絲數(shù)等信息
  - 雙擊可打開用戶主頁
  - 支持數(shù)據(jù)排序
  - 可單獨導(dǎo)出用戶數(shù)據(jù)
 
3. 數(shù)據(jù)分析
-----------------
 互動數(shù)據(jù)分析:
  - 統(tǒng)計總點贊數(shù)、平均點贊等指標(biāo)
  - 展示互動數(shù)據(jù)分布情況
 
 內(nèi)容長度分析:
  - 分析標(biāo)題長度分布
  - 顯示最長/最短標(biāo)題統(tǒng)計
 
 高頻詞匯分析:
  - 提取標(biāo)題中的關(guān)鍵詞
  - 展示TOP100高頻詞匯
  - 計算詞頻占比
 
4. 常見問題
-----------------
Q: 為什么采集速度較慢?
A: 為了避免被反爬蟲機制攔截,程序設(shè)置了延遲機制。
 
Q: 如何提高采集成功率?
A: 建議:
   - 設(shè)置適當(dāng)?shù)难舆t時間(2-3秒)
   - 避免過于頻繁的采集
   - 確保網(wǎng)絡(luò)連接穩(wěn)定
 
Q: 數(shù)據(jù)導(dǎo)出格式說明?
A: 支持兩種格式:
   - Excel格式:適合數(shù)據(jù)分析和處理
   - JSON格式:適合數(shù)據(jù)備份和程序讀取
 
Q: 如何處理采集失???
A: 可以:
   - 檢查網(wǎng)絡(luò)連接
   - 增加延遲時間
   - 減少單次采集數(shù)量
   - 更換搜索關(guān)鍵詞
 
5. 注意事項
-----------------
 合理使用:
  - 遵守抖音平臺規(guī)則
  - 避免頻繁、大量采集
  - 合理設(shè)置采集參數(shù)
 
 數(shù)據(jù)安全:
  - 及時導(dǎo)出重要數(shù)據(jù)
  - 定期備份采集結(jié)果
 
 使用建議:
  - 建議使用穩(wěn)定的網(wǎng)絡(luò)連接
  - 采集時避免其他瀏覽器操作
  - 定期清理瀏覽器緩存
 
如需更多幫助,請參考項目文檔或聯(lián)系開發(fā)者。
"""
         
        # 插入幫助內(nèi)容
        help_text.insert('1.0', help_content)
        help_text.config(state='disabled')  # 設(shè)置為只讀
 
    def formatDouyinAwemeData(self, item):
        """格式化抖音視頻數(shù)據(jù)"""
        video_data = {
            "awemeId": item.get("aweme_id"),
            "desc": item.get("desc", ""),
            "url": item.get("video", {}).get("play_addr", {}).get("url_list", [""])[0]  # 獲取視頻播放地址
        }
        return video_data
 
    def show_video_context_menu(self, event):
        """顯示視頻右鍵菜單"""
        try:
            # 獲取點擊的item
            item = self.data_tree.identify_row(event.y)
            if not item:
                return
             
            # 選中被點擊的項
            self.data_tree.selection_set(item)
             
            # 顯示菜單
            self.video_menu.post(event.x_root, event.y_root)
        except Exception as e:
            print(f"顯示右鍵菜單錯誤: {str(e)}")
 
    def copy_video_link(self):
        """復(fù)制視頻鏈接到剪貼板"""
        try:
            selection = self.data_tree.selection()
            if not selection:
                return
             
            item = selection[0]
            values = self.data_tree.item(item)['values']
            if not values:
                return
             
            video_url = values[5]
            if video_url:
                self.root.clipboard_clear()
                self.root.clipboard_append(video_url)
                messagebox.showinfo("成功", "視頻鏈接已復(fù)制到剪貼板")
             
        except Exception as e:
            print(f"復(fù)制鏈接錯誤: {str(e)}")
            messagebox.showerror("錯誤", "復(fù)制鏈接失敗")
 
    def open_in_browser(self):
        """在瀏覽器中打開視頻"""
        try:
            selection = self.data_tree.selection()
            if not selection:
                return
             
            item = selection[0]
            values = self.data_tree.item(item)['values']
            if not values:
                return
             
            video_url = values[5]
            if video_url:
                # 確保URL格式正確
                if not video_url.startswith('http'):
                    if video_url.startswith('//'):
                        video_url = 'https:' + video_url
                    else:
                        video_url = 'https://www.douyin.com' + video_url
                     
                import webbrowser
                webbrowser.open(video_url)
             
        except Exception as e:
            print(f"打開瀏覽器錯誤: {str(e)}")
            messagebox.showerror("錯誤", "無法打開瀏覽器")
 
    def select_browser_path(self):
        """選擇瀏覽器路徑"""
        from tkinter import filedialog
         
        filename = filedialog.askopenfilename(
            title="選擇Chrome瀏覽器程序",
            filetypes=[("Chrome程序", "chrome.exe"), ("所有文件", "*.*")],
            initialdir=os.path.dirname(self.browser_path.get())
        )
         
        if filename:
            self.browser_path.set(filename)
            # 保存設(shè)置
            try:
                with open('config.json', 'w', encoding='utf-8') as f:
                    json.dump({'browser_path': filename}, f, ensure_ascii=False, indent=2)
            except Exception as e:
                print(f"保存配置失敗: {str(e)}")
 
    def load_config(self):
        """加載配置"""
        try:
            if os.path.exists('config.json'):
                with open('config.json', 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    if 'browser_path' in config:
                        self.browser_path.set(config['browser_path'])
        except Exception as e:
            print(f"加載配置失敗: {str(e)}")
if __name__ == "__main__":
    try:
        root = tk.Tk()
        app = DouyinAnalyzer(root)
        
        # 設(shè)置窗口圖標(biāo)
        try:
            root.iconbitmap('douyin.ico')  # 如果有圖標(biāo)文件可以取消注釋
        except:
            pass
            
        root.mainloop()
    except Exception as e:
        logging.error(f"程序運行錯誤: {str(e)}", exc_info=True)

性能優(yōu)化秘籍(高級技巧)

1. 內(nèi)存管理

# 使用生成器減少內(nèi)存占用
def get_video_items(self):
    for item in self.page.eles('tag:li@@class="video-item"'):
        yield self._parse_item(item)

2. 反反爬策略

隨機User-Agent輪換

鼠標(biāo)移動軌跡模擬

動態(tài)IP支持(需配合代理池)

3. 異步處理方案

async def async_collect(self):
    async with AsyncChromiumPage() as page:
        await page.get(url)
        await page.wait.eles_displayed('video-item')

總結(jié)與展望

經(jīng)過這個項目的開發(fā),我總結(jié)了以下幾點經(jīng)驗:

  • DrissionPage優(yōu)勢:相比Selenium,資源占用降低40%,無需額外驅(qū)動
  • UI設(shè)計心得:合理的色彩搭配能提升工具專業(yè)度300%
  • 數(shù)據(jù)分析價值:通過詞頻分析發(fā)現(xiàn)了3個爆款內(nèi)容規(guī)律

未來可擴展方向:

  • 增加情感分析模塊
  • 開發(fā)自動報告生成
  • 集成更多短視頻平臺

到此這篇關(guān)于Python使用DrissionPage實現(xiàn)數(shù)據(jù)分析工具的文章就介紹到這了,更多相關(guān)Python DrissionPage數(shù)據(jù)分析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python 函數(shù)嵌套及多函數(shù)共同運行知識點講解

    python 函數(shù)嵌套及多函數(shù)共同運行知識點講解

    在本篇文章里小編給各位整理的是一篇關(guān)于python 函數(shù)嵌套及多函數(shù)共同運行知識點講解,需要的朋友們可以學(xué)習(xí)下。
    2020-03-03
  • Pytorch 數(shù)據(jù)加載與數(shù)據(jù)預(yù)處理方式

    Pytorch 數(shù)據(jù)加載與數(shù)據(jù)預(yù)處理方式

    今天小編就為大家分享一篇Pytorch 數(shù)據(jù)加載與數(shù)據(jù)預(yù)處理方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • python3轉(zhuǎn)換code128條形碼的方法

    python3轉(zhuǎn)換code128條形碼的方法

    這篇文章主要介紹了python3轉(zhuǎn)換code128條形碼的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-04-04
  • Python中的pickle模塊解析

    Python中的pickle模塊解析

    這篇文章主要介紹了Python中的pickle模塊解析,pickle 模塊和 json 模塊很像,都有序列化的功能,不過 pickle 模塊更加局限一些只能對 python 使用,它可以對一個 python 對象結(jié)構(gòu)的二進制序列化和反序列化,需要的朋友可以參考下
    2023-09-09
  • python處理SQLite數(shù)據(jù)庫的方法

    python處理SQLite數(shù)據(jù)庫的方法

    這篇文章主要介紹了python處理SQLite數(shù)據(jù)庫的方法,python處理數(shù)據(jù)庫非常簡單。而且不同類型的數(shù)據(jù)庫處理邏輯方式大同小異。本文以sqlite數(shù)據(jù)庫為例,介紹一下python操作數(shù)據(jù)庫的方,需要的朋友可以參考下,希望能幫助到大家
    2022-02-02
  • 詳解python使用pip安裝第三方庫(工具包)速度慢、超時、失敗的解決方案

    詳解python使用pip安裝第三方庫(工具包)速度慢、超時、失敗的解決方案

    這篇文章主要介紹了詳解python使用pip安裝第三方庫(工具包)速度慢、超時、失敗的解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Python開發(fā)微信公眾平臺的方法詳解【基于weixin-knife】

    Python開發(fā)微信公眾平臺的方法詳解【基于weixin-knife】

    這篇文章主要介紹了Python開發(fā)微信公眾平臺的方法,結(jié)合實例形式分析了Python基于weixin-knife針對微信公眾平臺消息、接口調(diào)用及事件處理的基本操作技巧與相關(guān)注意事項,需要的朋友可以參考下
    2017-07-07
  • 使用Python對Excel進行讀寫操作

    使用Python對Excel進行讀寫操作

    學(xué)習(xí)Python的過程中,我們會遇到Excel的讀寫問題。這時,我們可以使用xlwt模塊將數(shù)據(jù)寫入Excel表格中,使用xlrd模塊從Excel中讀取數(shù)據(jù)。下面我們介紹如何實現(xiàn)使用Python對Excel進行讀寫操作。
    2017-03-03
  • 基于Python編寫一個DOS命令輔助工具

    基于Python編寫一個DOS命令輔助工具

    在日常系統(tǒng)管理和維護工作中,執(zhí)行DOS(Disk?Operating?System)命令是一項必不可少的任務(wù),下面我們就來看看如何使用Python編寫一個簡單的DOS命令輔助工具,簡化系統(tǒng)管理任務(wù)吧
    2024-01-01
  • Pandas中MultiIndex選擇并提取任何行和列

    Pandas中MultiIndex選擇并提取任何行和列

    本文主要介紹了Pandas中MultiIndex選擇并提取任何行和列,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02

最新評論