1. 程式人生 > 其它 >提取微信聊天記錄詳細教程

提取微信聊天記錄詳細教程

效果展示

匯出內容:文字、圖片、撤回訊息、表情包、拍一拍、回覆

匯出格式:txt,docx,PDF

一、下載模擬器匯入聊天記錄到模擬器裡

這裡以夜神模擬器(支援root的模擬器都行)為例

在模擬器裡安裝微信並登入,然後在電腦上登入微信。

選擇恢復聊天記錄到手機,選擇你匯出的聯絡人到模擬器裡,確保模擬器裡的微信可以檢視到聊天記錄

完成之後開啟夜神模擬器,找到Amaze


選擇根目錄,找到./data/data/com.tencent.mm/MicroMsg

將這個資料夾複製到共享資料夾中

共享資料夾在上面可以看到,按照圖片操作進行復制貼上


然後再將下面這個檔案(auth_info_key_prefs.xml)複製到共享資料夾中(檔案目錄://data/data/com.tencent.mm/shared_prefs)

複製完成之後到電腦的檔案管理器檢視共享資料夾

提取成功,第一步搞定

二、破譯密碼

資料夾裡面會有一個以很長一串數字或者一些字母組成命名的資料夾(也可能有多個。不同的資料夾名代表不同的qq,如果你用不同的qq登陸過微信,每個qq會產生一個新亂碼資料夾,保險起見,可以都備份上)把此資料夾備份出來,資料夾裡還有個systeminfo.cfg檔案可以不用備份

在這個名字很長的資料夾下將這三個檔案提取出來,avatar(儲存了使用者的頭像資料),image2(儲存了聊天的圖片資料)EnMicroMsg.db(儲存了所有的聊天記錄)

微信資料庫EnMicroMsg.db的加密方式,把IMEI和auth_uin組合得到一起md5加密,取加密後的前7位(小寫)

IMEI提取:開啟夜神模擬器,右上角找到設定,進入手機設定,檢視IMEI值

auth_uin提取方式,用記事本開啟上面得到的xml檔案,<int name="_auth_uin" value="-15641**** " value後面的值就是uin(負號保留)


被加密字串就是: 351564524987328-15641****

線上加密網站:MD5線上加密/解密/破解—MD5線上 (sojson.com)

經過MD5加密後輸出的字串取前7位(小寫)

將EnMicroMsg.db用sqlcipher.exe開啟輸入密碼試試能不能開啟

不能的話 用 IMEI = '1234567890ABCDEF' 再試試

開啟之後顯示這個介面,點選Browse Data可以檢視每個資料表的資訊


微信所有聊天記錄都在message表裡,所有聯絡人都在rcontact表裡,userinfo裡儲存個人資訊,把這三個表匯出為csv檔案,分別命名為message.csv和rcontact.csv,userinfo.csv

將匯出的所有表都放在db_tables資料夾裡(自己新建)
直接匯出的csv檔案在python讀寫會出現異常,所以先在Excel裡開啟csv檔案再另存為xlsx檔案(或者用記事本更改編碼方式為utf-8)放到db_tables資料夾裡

三、解析資料

0、模組安裝(不會安裝的話自行百度)

  1. pandas庫,安裝失敗自行百度,網上很多教程

    pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple
    
  2. docx庫

    pip install python-docx -i https://pypi.tuna.tsinghua.edu.cn/simple
    
  3. requests庫

    pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
    
  4. docxcompose庫

    pip install docxcompose  -i https://pypi.tuna.tsinghua.edu.cn/simple
    

1、把三個xlsx檔案解析成新的csv檔案(rcontact.py和message.py)

rcontant.py

#-*- coding : utf-8-*-
# coding:unicode_escape
'''
#! 本檔案功能
#! 1、將rcontact.xlsx轉化成new_rcontact.csv
#! 2、獲取聯絡人的wxid
#! 另外兩個檔案都會使用此模組
'''

import os
import pandas as pd


filename = ''
if isExists := os.path.exists('./db_tables/rcontact.xlsx'):
    isExists = os.path.exists('./db_tables/new_rcontact.csv')
    if not isExists:
        filename = './db_tables/rcontact.xlsx'
        df = pd.read_excel(filename)
        df.to_csv('./db_tables/new_rcontact.csv')
        print("new_rcontact.csv 匯出成功")
    filename = './db_tables/new_rcontact.csv'
else:
    print('rcontact.xlsx not exits')
    print("請將資料庫裡的rcontact表匯出\n命名為:rcontact.csv")
    print("用Excel把檔案匯出為xlsx格式放到此目錄下")

'''獲取指定備註名的wxid'''

def get_one_wxid(conRemark):
    if not filename:
        print("聯絡人csv檔案不存在")
    else:
        df = pd.read_csv(filename)
        for row_index, row in df.iterrows():
            if row['conRemark'] == conRemark :
                wxid = row['username']
                print(conRemark,wxid)
                return wxid
'''獲取自己的wxid'''
def get_self_wxid():
    isExists = os.path.exists('./db_tables/userinfo.xlsx')
    if not isExists:
        print('userinfo.xlsx not exits')
        print("請將資料庫裡的userinfo表匯出\n命名為:userinfo.csv")
        print("用Excel把檔案匯出為同名xlsx格式放到此目錄下")
    else:
        isExists = os.path.exists('./db_tables/new_userinfo.csv')
        if not isExists:
            filename = './db_tables/userinfo.xlsx'
            df = pd.read_excel(filename)
            df.to_csv('./db_tables/new_userinfo.csv')
            print("new_userinfo.csv 匯出成功")
    filename = './db_tables/new_userinfo.csv'
    if isExists := os.path.exists(filename):
        df = pd.read_csv(filename)
        print(df)
        for row_index, row in df.iterrows():
            if 'wxid' in row['value']:
                print("self_wxid =",row['value'])
                return row['value']

    else:
        print("new_userinfo.csv檔案不存在")

if __name__ == '__main__':
    conRemark = '張三'   #!備註名
    filename = './db_tables/rcontact.csv'
    get_one_wxid(conRemark)
    get_self_wxid()

message.py

import pandas as pd
import os
import sys
import io
'''這個是自定義包'''
import rcontact
columns = ['msgId','msgSvrId','type','status','isSend','isShowTimer','createTime','talker','content','imgPath',
            'reserved','lvbuffer','transContent','transBrandWording','talkerId',
            'bizClientMsgId','bizChatId','bizChatUserId','msgSeq','flag','solitaireFoldInfo','historyId'
            ]
'''篩選一下檔案頭,其他好像沒用'''
new_columns = ['createTime','isSend','talker','content','imgPath','reserved','talkerId','type','status']

Type = {
    '1':'文字',
    '3':'圖片',
    '43':'視訊',
    '-1879048185':'微信運動排行榜',
    '5':'',
    '47':'表情包',
    '268445456':'撤回的訊息',
    '34':'語音',
    '419430449':'轉賬',
    '50':'語音電話',
    '10000':'領取紅包',
    '10000':'訊息已發出,但被對方拒收了。',
    '822083633':'回覆訊息',
    '922746929':'拍一拍',
    '1090519089':'傳送檔案',
    '318767153':'付款成功',
    '436207665':'發紅包',
}
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')
'''判斷路徑是否存在,不存在則新建資料夾'''
def mkdir(path):
    path = path.strip()
    path = path.rstrip("\\")
    if os.path.exists(path):
        return False
    os.makedirs(path)
    return True

mkdir('.//db_tables')

'''
# ! 把原表處理一下過濾掉不必要的資訊
# ! 作用不大可以忽略
'''
def read_all_data():
    pdata = pd.read_csv('./db_tables/new_message.csv')
    # del pdata['1']
    print(pdata)
    # pdata.to_csv('./db_tables/5.csv')
    # msgId,msgSvrId,type,status,isSend
    new = pd.DataFrame()
    new.insert(0,'createTime',pdata['createTime'])
    new.insert(1,'isSend',pdata['isSend'])
    new.insert(2,'talker',pdata['talker'])
    new.insert(3,'content',pdata['content'])
    new.insert(4,'imgPath',pdata['imgPath'])
    new.insert(5,'reserved',pdata['reserved'])
    new.insert(6,'talkerId',pdata['talkerId'])
    new.insert(7,'type',pdata['type'])
    new.insert(8,'status',pdata['status'])
    new.to_csv('./db_tables/simple_new_message.csv',index=False)
    print("資料篩選成功!!!")

'''
#! 根據備註匯出某個人的全部聊天資訊
'''
def read_one_data(conRemark):
    isExist = os.path.exists('./db_tables/simple_new_message.csv')
    if not isExist:
        print("simple_new_message.csv不存在\n請先執行上一個函式")
        return
    pdata = pd.read_csv('./db_tables/simple_new_message.csv')
    print(pdata)
    print("漫長的等待!!!")
    wxid = rcontact.get_one_wxid(conRemark)
    new_data = pd.DataFrame(columns=new_columns)
    '''篩選出目標聊天記錄'''
    for row_index,row in pdata.iterrows():
        if(row['talker']==wxid):
            new_data.loc[len(new_data.index)] = list(row)
    # print(new_data)
    '''匯入到新檔案中'''
    new_data.to_csv(f'./db_tables/{conRemark}.csv', index=False)
    print(f"匯出{conRemark}的聊天資料成功!!!")

''' 把時間資料轉化成字串防止資料舍入'''
def data_to_string():
    isExist = os.path.exists('./db_tables/message.xlsx')
    if not isExist:
        print("message.xlsx不存在,請在將資料庫裡的message表匯出成csv檔案")
        print("命名為message.csv,然後用Excel開啟檔案另存為message.xlsx")
        print("放入./db_tables資料夾中")
        return False
    else:
        isExist = os.path.exists('./db_tables/new_message.csv')
        if not isExist:
            df = pd.read_excel('./db_tables/message.xlsx')
            df['createTime'].to_string()
            print(df)
            df.to_csv('./db_tables/new_message.csv')
        else:
            print("new_message.csv已就緒即將進行資料處理")
        return True
if __name__ == '__main__':
    # time_d()
    # read_all_data()
    # data_to_string() 
    status = data_to_string()
    if status:
        '''把message轉化成csv'''
        read_all_data()
        '''輸入備註名匯出聯絡人的聊天資訊'''
        conRemark = '張三'
        read_one_data(conRemark)

2、匯出聊天記錄(原始碼)

to_docx.py

import hashlib
import os
import re
import threading
import time
import docx
import pandas as pd
import requests
from docx import shared
from docx.enum.table import WD_ALIGN_VERTICAL
from docx.enum.text import WD_COLOR_INDEX, WD_PARAGRAPH_ALIGNMENT
from docxcompose.composer import Composer
import rcontact

conRemark = '張三'
self_wxid = rcontact.get_self_wxid()
ta_wxid = rcontact.get_one_wxid(conRemark)

'''
#! 建立emoji目錄,存放emoji檔案
'''


def mkdir(path):
    path = path.strip()
    path = path.rstrip("\\")
    if os.path.exists(path):
        return False
    os.makedirs(path)
    return True


mkdir('.//emoji')
mkdir('.//db_tables')
'''
#! 將wxid使用MD5編碼加密
#! 加密結果是使用者頭像路徑
'''

def avatar_md5(wxid):
    m = hashlib.md5()
    # 引數必須是byte型別,否則報Unicode-objects must be encoded before hashing錯誤
    m.update(bytes(wxid.encode('utf-8')))
    return m.hexdigest()
'''
#! 獲取頭像檔案完整路徑
'''
def get_avator(wxid):
    avatar = avatar_md5(wxid)
    avatar_path = r"./avatar/"`在這裡插入程式碼片`
    path = avatar_path + avatar[:2] + '/' + avatar[2:4]
    for root, dirs, files in os.walk(path):
        for file in files:
            if avatar in file:
                avatar = file
                break
    return path + '/'+avatar

self_avator = get_avator(self_wxid)
ta_avator = get_avator(ta_wxid)
img_self = open(self_avator, 'rb')
img_ta = open(ta_avator, 'rb')

'''
#! 下載emoji檔案
#! 
#! 
'''


def download_emoji(content, img_path):
    try:
        url = content.split('cdnurl = "')[1].split('"')[0]
        url = ':'.join(url.split('*#*'))
        if 'amp;' in url:
            url = ''.join(url.split('amp;'))
            print('emoji downloading!!!')
        resp = requests.get(url)
        with open(f'./emoji/{img_path}', 'wb') as f:
            f.write(resp.content)
    except Exception:
        print("emoji download error")


'''
#! 將字串型別的時間戳轉換成日期
#! 返回格式化的時間字串
#! %Y-%m-%d %H:%M:%S
'''


def time_format(timestamp):
    timestamp = timestamp[:-5]
    timestamp = float(timestamp + '.' + timestamp[-5:2])
    time_tuple = time.localtime(timestamp)
    return time.strftime("%Y-%m-%d %H:%M:%S", time_tuple)


'''
#! 判斷兩次聊天時間是不是大於五分鐘
#! 若大於五分鐘則顯示時間
#! 否則不顯示
'''


def IS_5_min(last_m, now_m):
    last_m = last_m[:-5]
    last_m = float(last_m + '.' + last_m[-5:2])
    now_m = now_m[:-5]
    now_m = float(now_m + '.' + now_m[-5:2])
    '''兩次聊天記錄時間差,單位是秒'''
    time_sub = now_m - last_m
    return time_sub >= 300


def judge_type(Type):
    pass


'''
#! 建立一個1*2表格
#! isSend = 1 (0,0)存聊天內容,(0,1)存頭像
#! isSend = 0 (0,0)存頭像,(0,1)存聊天內容
#! 返回聊天內容的座標
'''
# img_self = open('1.jpg', 'rb')
# img_ta = open('0.jpg', 'rb')


def create_table(doc,isSend):
    table = doc.add_table(rows=1, cols=2, style='Normal Table')
    table.cell(0, 1).height = shared.Inches(0.5)
    table.cell(0, 0).height = shared.Inches(0.5)
    # img_1 = '1.jpg'
    # img_0 = '0.jpg'
    global img_self
    global img_ta
    text_size = 1
    if isSend:
        '''表格右對齊'''
        table.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
        avatar = table.cell(0, 1).paragraphs[0].add_run()
        '''插入頭像,設定頭像寬度'''
        avatar.add_picture(img_self, width=shared.Inches(0.5))
        '''設定單元格寬度跟頭像一致'''
        table.cell(0, 1).width = shared.Inches(0.5)
        content_cell = table.cell(0, 0)
        '''聊天內容右對齊'''
        content_cell.paragraphs[0].paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
    else:
        avatar = table.cell(0, 0).paragraphs[0].add_run()
        avatar.add_picture(img_ta, width=shared.Inches(0.5))
        '''設定單元格寬度'''
        table.cell(0, 0).width = shared.Inches(0.5)
        content_cell = table.cell(0, 1)
    '''聊天內容垂直居中對齊'''
    content_cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
    return content_cell


'''
#! 將文字聊天記錄寫入檔案
#! isSend表示是誰傳送的資訊
#! isSend = 0 表示是對方發的資訊,內容左對齊
#! isSend = 1 表示是自己發的資訊,內容右對齊
'''


def text(doc,isSend, message, status):
    if status == 5:
        message += '(未發出) '
    content_cell = create_table(doc,isSend)
    content_cell.paragraphs[0].add_run(message)
    content_cell.paragraphs[0].font_size = shared.Inches(0.5)
    if isSend:
        p = content_cell.paragraphs[0]
        p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
    doc.add_paragraph()


'''
#! 插入聊天圖片
#! isSend = 1 只有縮圖
#! isSend = 0 有原圖 
'''


def image(doc,isSend, Type, content, imgPath):
    content = create_table(doc,isSend)
    run = content.paragraphs[0].add_run()
    imgPath = imgPath.split('//th_')[-1]
    if Type == 3:
        Path = f'.//image2//{imgPath[:2]}//{imgPath[2:4]}'
    elif Type == 47:
        Path = './emoji'
    for root, dirs, files in os.walk(Path):
        for file in files:
            if isSend:
                if imgPath + 'hd' in file:
                    imgPath = file
                    try:
                        run.add_picture(f'{Path}/{imgPath}', height=shared.Inches(2))
                        doc.add_paragraph()
                    except Exception:
                        print("Error!image")
                    return
            elif imgPath in file:
                imgPath = file
                break
    try:
        run.add_picture(f'{Path}/{imgPath}', height=shared.Inches(2))
        doc.add_paragraph()
    except Exception:
        print("Error!image")

    # run.add_picture(f'{Path}/{imgPath}', height=shared.Inches(2))


'''
#! 新增表情包
'''


def emoji(doc,isSend, content, imgPath):
    try:
        path = f'.//emoji//{imgPath}'
        is_Exist = os.path.exists(path)
        if not is_Exist:
            '''表情包不存在,則下載表情包到emoji資料夾中'''
            download_emoji(content, imgPath)
        image(doc,isSend, Type=47, content=content, imgPath=imgPath)
    except Exception:
        print("can't find emoji!")


'''
#! 新增微信檔案
'''


def wx_file(doc,isSend, content, status):
    pattern = re.compile(r"<title>(.*?)<")
    r = pattern.search(content).group()
    filename = r.lstrip('<title>').rstrip('<')
    text(doc,isSend, filename, status)


'''
#! 顯示撤回訊息
'''


def retract_message(doc,isSend, content, status):
    paragraph = doc.add_paragraph(content)
    paragraph.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER


'''
#! 添加回覆信息
'''


def reply(doc,isSend, content, status):
    pattern1 = re.compile(r"<title>(?P<title>(.*?))</title>")
    title = pattern1.search(content).groupdict()['title']
    pattern2 = re.compile(r"<displayname>(?P<displayname>(.*?))</displayname>")
    displayname = pattern2.search(content).groupdict()['displayname']
    '''匹配回覆的回覆'''
    pattern3 = re.compile(r"\n?title&gt;(?P<content>(.*?))\n?&lt;/title&gt")
    if not pattern3.search(content):
        if isSend == 0:
            '''匹配對方的回覆'''
            pattern3 = re.compile(r"<content>(?P<content>(.*?))</content>")
        else:
            '''匹配自己的回覆'''
            pattern3 = re.compile(r"</msgsource>\n?<content>(?P<content>(.*?))\n?</content>")

    '''這部分程式碼完全可以用if代替'''

    try:
        '''試錯'''
        text = pattern3.search(content).groupdict()['content']
    except Exception:
        try:
            '''試錯'''
            text = pattern3.search(content).groupdict()['content']
        except Exception:
            '''試錯'''
            pattern3 = re.compile(r"\n?<content>(?P<content>(.*?))\n?</content>")
            '''試錯'''
            if pattern3.search(content):
                text = pattern3.search(content).groupdict()['content']
            else:
                text = '圖片'
    if status == 5:
        message = '(未發出) ' + ''
    content_cell = create_table(doc,isSend)
    content_cell.paragraphs[0].add_run(title)
    content_cell.paragraphs[0].font_size = shared.Inches(0.5)
    reply_p = content_cell.add_paragraph()
    run = content_cell.paragraphs[1].add_run(displayname + ':' + text)
    '''設定被回覆內容格式'''
    run.font.color.rgb = shared.RGBColor(121, 121, 121)
    run.font_size = shared.Inches(0.3)
    run.font.highlight_color = WD_COLOR_INDEX.GRAY_25

    if isSend:
        p = content_cell.paragraphs[0]
        p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
        reply_p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
    doc.add_paragraph()


'''
#! 新增拍一拍資訊
#todo 把wxid轉化成暱稱
'''


def pat_a_pat(doc,isSend, content, status):
    '''<template><![CDATA[我${fromusername@textstatusicon}拍了拍自己]]></template>'''
    pattern = re.compile(r"<template><!\[CDATA\[(?P<it>(.*?))]]></template>")
    result = pattern.search(content).groupdict()['it']
    fromusername = '${fromusername@textstatusicon}'
    pattedusername = '${pattedusername@textstatusicon}'
    '''我拍別人'''
    if result[0] == u'我':
        result = ''.join(result.split(fromusername))
        result = ''.join(result.split(pattedusername))
        pat = result
    else:
        '''處理多餘的引號'''
        result = result.split('""') if '""' in result else result.split('"')
        for i in range(len(result)):
            if fromusername in result[i]:
                result[i] = result[i].rstrip(fromusername)
            elif pattedusername in result[i]:
                result[i] = result[i].rstrip(pattedusername)

        if len(result) >= 4:
            '''別人拍別人
            #! ""${s407575157}${fromusername@textstatusicon}"" \
            #! 拍了拍 \
            #! ""${wxid_7rs401fwlaje22}${pattedusername@textstatusicon}"" \
            #! 的豪宅不小心塌了??
            #! [' ', wxid0, '拍了拍', wxid1, '內容']
            '''
            wxid0 = result[1].lstrip('${').rstrip('}')  # ! 第一個人的wxid
            wxid1 = result[3].lstrip('${').rstrip('}')  # ! 第二個人的wxid
            pat = wxid0 + result[2] + wxid1  # todo 留著把wxid轉換成暱稱
            if len(result) == 5:
                pat += result[4]
        else:
            '''#!  ""${wxid_8piw6sb4hvfm22}"" 拍了拍我  '''
            '''
            #! 別人拍我
            #! [' ', wxid0, '拍了拍我']
            '''
            wxid0 = result[1].lstrip('${').rstrip('}')
            pat = wxid0 + result[2]
    print(pat)
    p = doc.add_paragraph()
    run = p.add_run(pat)
    p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    '''設定拍一拍文字格式'''
    run.font.color.rgb = shared.RGBColor(121, 121, 121)
    run.font_size = shared.Inches(0.3)
    # run.font.highlight_color=WD_COLOR_INDEX.GRAY_25


def video(doc,isSend, content, status, img_path):
    print(content, img_path)

def to_docx(user_data,i,conRemark):
    '''建立聯絡人目錄'''
    mkdir(f"./{conRemark}")
    filename = f"./{conRemark}/{conRemark}{i}.docx"
    doc = docx.Document()
    # doc.add_paragraph(str(i))
    now_timestamp = '1600008700000.0'
    for row_index, row in user_data.iterrows():
        Type = row['type']
        content = row['content']
        isSend = row['isSend']
        last_timestamp = now_timestamp
        now_timestamp = row['createTime']
        createTime = time_format(now_timestamp)
        imgPath = row['imgPath']
        status = row['status']
        if IS_5_min(last_timestamp, now_timestamp):
            doc.add_paragraph(createTime).alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
        if Type == 1:
            print(createTime, content)
            text(doc,isSend, content, status)
        elif Type == 3:
            image(doc,isSend, 3, content, imgPath)
        elif Type == 47:
            emoji(doc,isSend, content, imgPath)
        elif Type == 1090519089:
            wx_file(doc,isSend, content, status)
        elif Type == 268445456:
            retract_message(doc,isSend, content, status)
        elif Type == 822083633:
            reply(doc,isSend, content, status)
        elif Type == 922746929:
            pat_a_pat(doc,isSend, content, status)
        elif Type == 43:
            # print(createTime)
            video(doc,isSend, content, status,imgPath)
    # doc.add_paragraph(str(i))
    print(filename)
    doc.save(filename)

def read_csv(conRemark):
    name = conRemark
    user_data = pd.read_csv(f'./db_tables/{name}.csv')
    '''將浮點數轉化成字串型別,否則會舍入影響時間結果'''
    user_data['createTime'] = user_data['createTime'].astype(str)
    # print(user_data)
    return user_data

'''合併word文件到一個檔案裡'''
def merge_docx(conRemark,n):
    origin_docx_path = f"./{conRemark}"
    all_word = os.listdir(origin_docx_path)
    all_file_path = []
    for i in range(n):
        file_name  = f"{conRemark}{i}.docx"
        all_file_path.append(origin_docx_path +'/'+file_name)
    filename = f"{conRemark}.docx"
    # print(all_file_path)
    doc = docx.Document()
    doc.save(origin_docx_path+ '/' +filename)
    master = docx.Document(origin_docx_path+ '/' +filename)
    middle_new_docx = Composer(master)
    num = 0
    for word in all_file_path:
        word_document = docx.Document(word)
        word_document.add_page_break()
        if num != 0:
            middle_new_docx.append(word_document)
        num = num + 1
    middle_new_docx.save(origin_docx_path+ '/' +filename)
'''
#! conRemark:備註名
#! n: 中間生成的檔案個數,50-100比較快
'''
def main(conRemark,n):
    user_data =read_csv(conRemark)
    l = len(user_data)
    print(l)
    n = 50
    threads = []
    start = time.time()
    for i in range(n):
        q = i * (l // n)
        p = (i + 1) * (l // n)
        if i == n - 1:
            p = l
        data = user_data[q:p]
        t = threading.Thread(target=to_docx, args=(data, i, conRemark))
        threads.append(t)

    for thr in threads:
        thr.start()
        thr.join()
    end = time.time()
    t1 = end - start
    print(t1, 's')
    merge_docx(conRemark,n)
    end = time.time()
    t2 = end - start
    print(t2, 's')
    with open('data.txt','a+',encoding='utf-8') as f:
        f.write(f"\nn = {n} t1 = {t1} t2 = {t2}\n")
if __name__ == '__main__':
    start = time.time()
    # conRemark = '張三' #! 微信備註名
    n = 100 #! 分割的檔案個數
    main(conRemark,n)
    img_self.close()
    img_ta.close()
 	threads = []
    start = time.time()
    for i in range(n):
        q = i * (l // n)
        p = (i + 1) * (l // n)
        if i == n - 1:
            p = l
        data = user_data[q:p]
        t = threading.Thread(target=to_docx, args=(data, i, conRemark))
        threads.append(t)

    for thr in threads:
        thr.start()
        thr.join()
    end = time.time()
    t1 = end - start
    print(t1, 's')
    merge_docx(conRemark,n)
    end = time.time()
    t2 = end - start
    print(t2, 's')
    with open('data.txt','a+',encoding='utf-8') as f:
        f.write(f"\nn = {n} t1 = {t1} t2 = {t2}\n")


if __name__ == '__main__':
    start = time.time()
    # conRemark = '張三' #! 微信備註名
    n = 100 #! 分割的檔案個數
    main(conRemark,n)
    img_self.close()
    img_ta.close()

3、原始碼檔案及附件

百度網盤:連結:https://pan.baidu.com/s/1x3aaC2qV-AnvyH-Xky3I4g?pwd=shnc
提取碼:shnc

阿里雲盤:「原始碼分享」https://www.aliyundrive.com/s/WJak6qarnva 點選連結儲存,或者複製本段內容,開啟「阿里雲盤」APP ,無需 下載極速線上檢視,視訊原畫倍速播放。