1. 程式人生 > 其它 >批量獲取百度網盤檔案目錄

批量獲取百度網盤檔案目錄

目錄

當網盤檔案超過100G的時候,找檔案就有點苦惱了,不記得放在什麼資料夾,也不記得名字,就想著從目錄著手。
現在百度網盤還未推出目錄功能,這裡就套用網上推薦的查詢目錄的方式。後面附有程式碼。

整體思路

檢視網盤快取資料庫檔案

百度網盤在本地有個資料庫檔案BaiduYunCacheFileV0.db,裡面存放著檔案路徑和檔名等資訊,兩者結合提取出目錄資訊。該檔案可以用Navicat Premium 15開啟。

程式碼分析

#!/usr/bin/env python3  
# -*- coding:utf-8 -*-  
from tkinter import *  
from tkinter.filedialog import askopenfilename  
from tkinter.filedialog import asksaveasfilename  
from tkinter.ttk import *  
import sqlite3

這裡用到了用於GUI圖形介面開發的庫,Tkinter 模組(Tk 介面),其中Tkinter filedialog是檔案對話方塊控制元件。由於tkinter模組下的元件,整體風格較老較醜,同時也匯入了元件更加美觀、功能更加強大的ttk 元件。ttk新增了 LabeledScale( 帶標籤的Scale)、Notebook( 多文件視窗)、Progressbar(進度條)、Treeview(數)等元件。

def select_db_file():  
    db_file = askopenfilename(title="請選擇BaiduYunCacheFileV0.db檔案",filetypes=[('db', '*.db')])  
    db.set(db_file)  
    
def select_save_file():  
    save_file = asksaveasfilename(filetypes=[('檔案', '*.txt')])  
    f.set(save_file+".txt")  

StringVar的作用,我們在使用介面程式設計的時候,有些時候是需要跟蹤變數的值的變化,以保證值的變更隨時可以顯示在介面上。由於python無法做到這一點,所以使用了tcl的相應的物件,也就是StringVar、BooleanVar、DoubleVar、IntVar

  • StringVar型別需要通過StringVar.set()寫入string字串內容。
  • StringVar型別需要通過StringVar.get()讀取內容,返回一個string字串

askopenfilename返回檔名,是string字串型別
select_db_file()函式巧妙的是,它把StringVar變數的宣告寫在了函式的外面且後面出現,而不是函式內部,呀呀,就是不能寫在函式內部,在函式外面才是全域性變數。
當然也可以理解為回撥函式,當按鈕被點選時,變數就存在了,不用擔心它宣告在後面

核心函式

def write_file(file_dict,f,item,gap=""):  
    if item=="/":  
        f.write("━" + "/" + "\n")  
        for i in file_dict["/"]:  
            f.write("┣" + "━" + i + "\n")  
            i = item + i + "/"  
            if i in file_dict:  
                write_file(file_dict,f,i, gap="┣━")  
    else:  
        gap = "┃  " + gap  
        for i in file_dict[item]:  
            f.write(gap + i + "\n")  
            i = item + i + "/"  
            if i in file_dict:  
                  write_file(file_dict,f,i,gap)  

遞迴函式write_file(file_dict,f,item,gap=""),引數分別是存放路徑和對應檔案的字典file_dict,f是待寫入內容的txt檔案,item是路徑,gap是間隙

函式主體分析:如果路徑item是最外層的路徑,就將最外層路徑對應的檔名,寫入到f檔案中,然後根據檔名重新賦值一個新路徑,判斷這個新路徑是否在字典中,如果在,就遞迴呼叫該函式,檢查檔名是否是資料夾(也就是檔名包裝後的新路徑在字典中)

如果路徑不是根路徑,每次呼叫函式gap會變化,將新路徑對應的檔名,寫入到f檔案中,然後在檔名前面加上上一級路徑後面加上/,賦值一個新路徑,在字典中檢查,也就是判斷該檔名變成路徑後,是否還有下一級路徑,如果字典中有它
就表示有下一級路徑,然後繼續呼叫該函式。

連線資料庫提取內容

def create_baiduyun_filelist():  
    file_dict = {}  
    conn = sqlite3.connect(db.get()) 
    cursor = conn.cursor()  
    cursor.execute("select * from cache_file")  
    while True:  
        value = cursor.fetchone()  
        if not value:  
            break  
        path = value[2]  
        name = value[3]  
        size = value[4]  
        isdir = value[6]  
        if path not in file_dict:  
            file_dict[path] = []  
            file_dict[path].append(name)  
        else:  
            file_dict[path].append(name)  
    with open(f.get(),"w",encoding='utf-8') as fp:  
        write_file(file_dict,fp,"/")  
    conn.close()

conn = sqlite3.connect(db.get())連線資料庫,db是StringVar型別,需要通過db.get()讀取db裡的內容,返回string型別的字串,這裡是地址+資料庫檔名
cursor = conn.cursor() 使用 cursor() 方法建立一個遊標物件,遊標物件用於執行查詢和獲取結果
cursor.execute("select * from cache_file") 使用 execute() 方法執行 SQL 查詢,SQL語句和BaiduYunCacheFileV0.db裡的表格結構有關係,它裡面有張叫cache_file的表
value = cursor.fetchone() fetchone() 獲取下一個查詢結果集。結果集是一個物件
conn.close()關閉資料庫連線

主函式

root = Tk()  
root.title('百度雲檔案列表生成工具')  
db_select = Button(root, text=' 選擇DB檔案 ',command=select_db_file)  
db_select.grid(row=1,column=1,sticky=W,padx=(2,0),pady=(2,0))  
db = StringVar()  
db_path = Entry(root,width=80,textvariable = db)  
db_path['state'] = 'readonly'  
db_path.grid(row=1,column=2,padx=3,pady=3,sticky=W+E)  
save_path = Button(root, text='選擇儲存地址',command=select_save_file)  
save_path.grid(row=2,column=1,sticky=W,padx=(2,0),pady=(2,0))  
f = StringVar()  
file_path = Entry(root,width=80,textvariable = f)  
file_path['state'] = 'readonly'  
file_path.grid(row=2, column=2,padx=3,pady=3,sticky=W+E)  
create_btn = Button(root, text='生成檔案列表',command=create_baiduyun_filelist)  
create_btn.grid(row=3,column=1,columnspan=2,pady=(0,2))  
root.columnconfigure(2, weight=1) 
root.mainloop()

root = Tk() 呼叫視窗函式,例項化一個視窗物件
root.title('百度雲檔案列表生成工具') 視窗最頂部顯示的文字
db_select = Button(root, text=' 選擇DB檔案 ',command=select_db_file) 在視窗上建立一個button,呼叫一個按鈕,command代表點選按鈕發生的事件
padx,pady:與之並列的元件之間的間隔,x方向和y方向,預設單位是畫素
db_select.grid(row=1,column=1,sticky=W,padx=(2,0),pady=(2,0)) 設定按鈕的位置,在第一行第一列,padx=(2,0) ,與之並列的元件之間的間隔,水平方向上,button與左邊的元件,距離是2個畫素,與右邊的元件,距離是0畫素。

如果不呼叫Button的grid函式,它將不會顯示。sticky=W靠左邊。
sticky:有點類似於 pack() 方法的 anchor 選項,同樣支援 N(北,代表上)、E(東,代表右)、S(南,代表下)、W(西,代表左)、NW(西北,代表左上)、NE(東北,代表右上)、SW(西南,代表左下)、SE(東南,代表右下)、CENTER(中,預設值)這些值。

db = StringVar()StringVar是Tk庫內部定義的字串變數型別,改變StringVar,按鈕上的文字也隨之改變。
db_path = Entry(root,width=80,textvariable = db) TKinter輸入類(TKinter文字框)獲取使用者輸入,TKinter Entry類建立文字框,把變數db繫結到Entry
db_path['state'] = 'readonly' 變數db繫結Entry後,Entry狀態變為只讀
root.columnconfigure(2, weight=1) 列屬性設定
root.mainloop()此函式呼叫視窗的無限迴圈,因此視窗將等待任何使用者互動,直到我們將其關閉。

grid()方法相關引數

選項 說明 取值範圍
column 單元格的列號 從0開始的正整數column
columnspan 跨列,跨越的列數 正整數
row 單元格的行號 從0開始的正整數
rowspan 跨行,跨越的行數 正整數
ipadx, ipady 設定子元件之間的間隔,x方向或者y方向,預設單位為畫素 非負浮點數,預設0.0
padx,pady 與之並列的元件之間的間隔,x方向或者y方向,預設單位是畫素 非負浮點數,預設0.0
sticky 元件緊貼所在單元格的某一角,對應於東南西北中以及4個角 N/S/W/E, NW/SW/SE/NE, CENTER(預設)

整體程式碼

#!/usr/bin/env python3  
# -*- coding:utf-8 -*-  
from tkinter import *  
from tkinter.filedialog import askopenfilename  
from tkinter.filedialog import asksaveasfilename  
from tkinter.ttk import *  
import sqlite3

def select_db_file():  
    db_file = askopenfilename(title="請選擇BaiduYunCacheFileV0.db檔案",filetypes=[('db', '*.db')])  
    db.set(db_file)  

def select_save_file():  
    save_file = asksaveasfilename(filetypes=[('檔案', '*.txt')])  
    f.set(save_file+".txt")  

def write_file(file_dict,f,item,gap=""):  
    if item=="/":  
        f.write("━" + "/" + "\n")  
        for i in file_dict["/"]:  
            f.write("┣" + "━" + i + "\n")  
            i = item + i + "/"  
            if i in file_dict:  
                write_file(file_dict,f,i, gap="┣━")  
    else:  
        gap = "┃  " + gap  
        for i in file_dict[item]:  
            f.write(gap + i + "\n")  
            i = item + i + "/"  
            if i in file_dict:  
                  write_file(file_dict,f,i,gap)  

def create_baiduyun_filelist():  
    file_dict = {}  
    conn = sqlite3.connect(db.get())  
    cursor = conn.cursor()  
    cursor.execute("select * from cache_file")  
    while True:  
        value = cursor.fetchone() 
        if not value:  
            break  
        path = value[2]  
        name = value[3]  
        size = value[4]  
        isdir = value[6]  
        if path not in file_dict:  
            file_dict[path] = []  
            file_dict[path].append(name)  
        else:  
            file_dict[path].append(name)  
    with open(f.get(),"w",encoding='utf-8') as fp:  
        write_file(file_dict,fp,"/")  
    conn.close()

root = Tk()  
root.title('百度雲檔案列表生成工具')  
db_select = Button(root, text=' 選擇DB檔案 ',command=select_db_file)  
db_select.grid(row=1,column=1,sticky=W,padx=(2,0),pady=(2,0))  
db = StringVar() 
db_path = Entry(root,width=80,textvariable = db)  
db_path['state'] = 'readonly' 
db_path.grid(row=1,column=2,padx=3,pady=3,sticky=W+E)  
save_path = Button(root, text='選擇儲存地址',command=select_save_file)  
save_path.grid(row=2,column=1,sticky=W,padx=(2,0),pady=(2,0))  
f = StringVar()  
file_path = Entry(root,width=80,textvariable = f)  
file_path['state'] = 'readonly'  
file_path.grid(row=2, column=2,padx=3,pady=3,sticky=W+E)  
create_btn = Button(root, text='生成檔案列表',command=create_baiduyun_filelist)  
create_btn.grid(row=3,column=1,columnspan=2,pady=(0,2))  
root.columnconfigure(2, weight=1) 
root.mainloop()

執行結果

參考資料:
Python官方手冊:https://docs.python.org/zh-cn/3.8/library/tkinter.ttk.html