【问题标题】:Export Microsoft Teams chat to file for archiving将 Microsoft Teams 聊天导出到文件以进行归档
【发布时间】:2021-02-18 16:49:40
【问题描述】:

是否有人设法以任何文件格式(包括聊天图像,例如屏幕截图、用户头像等)保存来自 Microsoft Teams 的整个聊天记录

我已经在所有浏览器中以所有可以想到的方式进行了尝试。

问题似乎在于,Teams 会从内存中删除所有未包含在当前视口中的文本,甚至更多的是图像。

这看起来像 lazy loading,但显然不是,因为无法通过禁用浏览器中的延迟加载选项来阻止它(在基于浏览器的 Teams 版本的 Chrome 和 Firefox 中尝试过)。

仅显示和加载当前视口的内容。滚动时会立即卸载所有其他向上和向下的内容。因此,无法以任何方式分别选择和保存或导出整个聊天记录,甚至无法复制到剪贴板:

Contents outside the viewport are unloaded immediately when scrolling

【问题讨论】:

    标签: lazy-loading microsoft-teams archiving microsoft-exchange


    【解决方案1】:

    这是我在 Chrome 控制台中提出的一些意大利面条 - 它会滚动到您选择的任何聊天的顶部,然后逐条向下移动,创建可打印/可保存的副本。甚至加载所有的内嵌图片。

    唯一的问题是,很长的聊天记录需要一段时间才能滚动到开头。

    是的,要使用,只需打开Chrome console window (Ctrl+Shift+J) 复制并粘贴,然后按 Enter。然后等待它施展魔法。

    let xxx = 0;
    let ddd = 0;
    let fullpage1 = '' 
    
    fullpage1 = '<h1 id="chat-header-title2">'+jQuery('#chat-header-title').html()+'</h1>';
    
    //**********************************************
    //Go to top of page
    
    jj234 = function() {
    
    
    jQuery("virtual-repeat").scrollTop(-2000);
    
    
    
    if (xxx < 50) {setTimeout(jj234, 50); } else {setTimeout(ScrollDownTakeNote, 1000); }
    
    if (jQuery("virtual-repeat").hasClass("not-at-top")) {xxx = 0;} else {xxx += 1;} 
    
    }
    
    jj234();
    
    
    //Create a place to hold a copy of the content
    jQuery("body").append('<div id="thebigdiv" style="z-index: 10000; overflow: auto; background: white;"></div>');
    
    
    //*************************************************
    //Scroll down the chat, once things load, copy it to the temp location, removing some dynamic content
    
    ScrollDownTakeNote = function() {
    
    if (jQuery('.disable-event').length==0 && jQuery('.ts-image .loading').length==0) {
    ddd += 1;
    
    jQuery("#thebigdiv").append('<div id="boxdiv'+ddd+'"></div>');
    
    jQuery("virtual-repeat div.clearfix").each( function () {
    jQuery("#boxdiv"+ddd).append('<div class="messageClip" id="'+jQuery(this).attr('id')+'">' + jQuery(this).html() + '</div>');
    });
    
    jQuery("#boxdiv"+ddd+" [data-tid]").attr("data-tid","");
    
    jQuery("#boxdiv"+ddd+" [ng-if]").attr("ng-if","");
    
    jQuery("#boxdiv"+ddd+" [ng-class]").attr("ng-class","");
    
    jQuery("#boxdiv"+ddd+" [ng-source]").attr("ng-source","");
    
    jQuery("#boxdiv"+ddd+" [ng-class]").attr("ng-class","");
    
    jQuery("#boxdiv"+ddd+" [simple-mouseenter]").attr("simple-mouseenter","");
    
    jQuery("#boxdiv"+ddd+" [ng-mouseleave]").attr("ng-mouseleave","");
    
    jQuery("#boxdiv"+ddd+" [message-view-model]").attr("message-view-model","");
    
    jQuery("#boxdiv"+ddd+" [message-vm]").attr("message-vm","");
    
    jQuery("#boxdiv"+ddd+" [is-enabled]").attr("is-enabled","");
    
    jQuery("#boxdiv"+ddd+" [host-tenant-id]").attr("host-tenant-id","");
    
    
    jQuery("#boxdiv"+ddd+" [scroll-item-tracker]").attr("scroll-item-tracker","");
    jQuery("#boxdiv"+ddd+" [scroll-item-id]").attr("scroll-item-id","");
    jQuery("#boxdiv"+ddd+" [scroll-item-event-name]").attr("scroll-item-event-name","");
    jQuery("#boxdiv"+ddd+" [is-above-view-callback]").attr("is-above-view-callback","");
    jQuery("#boxdiv"+ddd+" [is-in-view-callback]").attr("is-in-view-callback","");
    jQuery("#boxdiv"+ddd+" [scroll-container]").attr("scroll-container","");
    jQuery("#boxdiv"+ddd+" [check-above-viewport]").attr("check-above-viewport","");
    jQuery("#boxdiv"+ddd+" [delay-scroll-tracker-init]").attr("delay-scroll-tracker-init","");
    jQuery("#boxdiv"+ddd+" [deferred-render-ready]").attr("deferred-render-ready","");
    
    jQuery("#boxdiv"+ddd+" img[target-src]").each(function () {$(this).attr("lazy-load","false"); $(this).attr("src",$(this).attr("target-src"));});
    
    jQuery("#boxdiv"+ddd+" skype-status").remove();
    
    fullpage1 += jQuery("#thebigdiv").html();
    jQuery("#thebigdiv").html(".");
    
    jQuery("virtual-repeat.simple-scrollbar").scrollTop(jQuery("virtual-repeat.simple-scrollbar").scrollTop()+2000);
    
    }
    
    if  (jQuery('[data-scroll-pos="1"').length==0 || jQuery("virtual-repeat").hasClass("not-at-bottom") || jQuery('.disable-event').length>0 || jQuery('.ts-image .loading').length>0 ) {setTimeout(ScrollDownTakeNote, 500);
    } else {printdiv("#thebigdiv")}
    
    };
    
    //**********************************
    //Open a Save File dialog for the HTML source and open the print window for a Print-to-PDF
    //(Why not both?)
    
    function printdiv(printdivname) {
            jQuery(printdivname).html(fullpage1);
        jQuery('#outer-shell').remove();
        jQuery('body').css({"overflow":"scroll"});
        
        $('div.messageClip[id]').each(function () {
                $('div.messageClip[id="' + this.id + '"]:gt(0)').remove();
        });
        jQuery(printdivname).css({"margin-left":"15px"});
        jQuery('body').append("<style>@media print { * { overflow: visible !important; } .page { page-break-after:always; }}");
        jQuery('head').append('<link rel="stylesheet" href="https://statics.teams.cdn.office.net/hashed/stylesheets.theme-defaultV2.min-86505e7.css" />');
        
        fullpage2 = new XMLSerializer().serializeToString(document);
        //fullpage2 = fullpage2.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
        //  return '&#'+i.charCodeAt(0)+';'; 
        //});
    
        saveTextAsFile(fullpage2);  
    
        waitonimages();
        
    }
    
    let xasd = 0;
    function waitonimages() {
        xasd = 0;
        jQuery("img").each(function () {if (!this.complete) { xasd+=1 }});
        if (xasd == 0) {window.print()} else {setTimeout(waitonimages,1000);}   
    }
    
    function saveTextAsFile(text1)
    {
        //inputTextToSave--> the text area from which the text to save is
        //taken from
        var textToSave = text1;
        var textToSaveAsBlob = new Blob([textToSave], {type:"text/html"});
        var textToSaveAsURL = window.URL.createObjectURL(textToSaveAsBlob);
        //inputFileNameToSaveAs-->The text field in which the user input for 
        //the desired file name is input into.
        var fileNameToSaveAs = jQuery('#chat-header-title2').html() + "-source.htm";
    
        var downloadLink = document.createElement("a");
        downloadLink.download = fileNameToSaveAs;
        downloadLink.innerHTML = "Download File";
        downloadLink.href = textToSaveAsURL;
        downloadLink.onclick = destroyClickedElement;
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    
        downloadLink.click();
    }
    
    function destroyClickedElement(event)
    {
        document.body.removeChild(event.target);
    }
    

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题。我无法使用图形 API,因为我的用户没有权限(只是普通的 Teams 用户)。

      我还注意到您提到的那种“延迟加载”,因此我找到的解决方案是扩展视图,以便所有内容都可见(并已加载)。

      我使用建议的 Firefox 控制台命令 here

      1. 确保您滚动到要保存的聊天对话的顶部和底部
      2. 按 F12 打开开发者工具
      3. 在开发者工具中选择“控制台”标签
      4. 在控制台中粘贴下面的代码,它应该会缩小页面
      const zoomFactor = (document.querySelector(".ts-main-flex").offsetHeight / document.querySelector(".list-wrap").offsetHeight);
      document.documentElement.style.setProperty("transform", "scale(" + zoomFactor + ")");
      document.documentElement.style.setProperty("transform-origin", "top");
      document.documentElement.style.setProperty("min-height", (100 / zoomFactor) + "vh");
      
      1. 页面完全加载后,将以下代码粘贴到控制台中,它应该会展开所有分组聊天。
      document.querySelectorAll(".expand-collapse").forEach(link => link.click());
      document.querySelectorAll(".ts-see-more-button.ts-see-more-fold").forEach(link => link.click());
      
      1. 在控制台中粘贴下面的代码,它应该调整缩放级别
      const newZoomFactor = (document.querySelector(".ts-main-flex").offsetHeight / document.querySelector(".list-wrap").offsetHeight);
      document.documentElement.style.setProperty("transform", "scale(" + newZoomFactor + ")");
      document.documentElement.style.setProperty("min-height", (100 / newZoomFactor) + "vh");
      
      1. 页面完全加载后,粘贴下面的代码以重置缩放并添加滚动条
      document.documentElement.style.removeProperty("transform");
      document.documentElement.style.removeProperty("transform-origin");
      document.documentElement.style.setProperty("overflow", "auto");
      
      1. 使用 SingleFile 保存页面
      2. 喝杯咖啡,享受时光的流逝,为你的CPU祈祷
      3. 瞧!您保存的页面应该没问题

      使用 SingleFile 保存页面对我来说非常有用。

      对于很长的聊天,我使用 SingleFileZ,它是 SingleFile 的一个分支,它增加了压缩并生成一个自动提取文件。在这些情况下,一些步骤需要我几个小时才能完成。

      【讨论】:

      • 这看起来很棒。下次我需要保存很长的 Teams 线程时,我一定会尝试它。对于不长的线程,我最近一直在使用 Opera 并取得了很好的成功。在那里,您可以将缩放设置得如此之小,以便理想情况下整个线程都可以在浏览器窗口中看到。然后,您可以使用 Opera 独特的 PDF 截图功能将整个线程保存为一个 PDF 页面(矢量,带有真实字体等)。此外,任何内嵌图像都包含一个非常有用的分辨率。
      【解决方案3】:

      您可以使用graph API 和图像进行团队聊天,但仅限于 20 天的数据。您最多可以获取团队聊天 20 天。还有一个功能请求可以将团队聊天导出到外部。目前您无法导出团队聊天。您能否在未来为团队chat history export feature to available 投票。您可以联系Product support channels 了解更多信息

      【讨论】:

      • 谢谢。不幸的是,我相信图形 API 解决方案超出了我的想象。同时,我一定已经阅读了有关此功能请求的所有论坛主题。可悲的是,目前唯一可用的选项似乎是将聊天保存为一系列屏幕截图。由于 Teams 所做的延迟加载操作,这也不是一件容易的事。幸运的是,有一个 Chrome extension 可以完成繁重的工作。
      • 但是,包含的图像只有预览分辨率和大小,附件根本不保存。因此,将 Teams 聊天导出到例如 Outlook MSG or EML 文件(可以包括图像、附件等)的解决方案将是理想的。不管怎样,我给Uservoice thread投了票。
      【解决方案4】:

      我发现在浏览器中打开 Teams 聊天可让您在对话中选择并复制粘贴多条消息和图像。

      下一步:在目标(MS Word)文件中使用 regex-replace 删除所有元信息(时间戳 + 名称)。

      替换'[?????????????????????????'用''

      【讨论】:

        【解决方案5】:

        在不太长的聊天中对我来说最简单和最好的方法是在 Opera 浏览器中打开聊天,然后尽可能缩小直到整个聊天以很小的尺寸可见,然后将页面保存为 PDF。

        这样,您可以获得包含高质量矢量文本和图像的 PDF 聊天。

        【讨论】:

          猜你喜欢
          • 2020-02-04
          • 2022-01-23
          • 1970-01-01
          • 1970-01-01
          • 2020-01-21
          • 1970-01-01
          • 2018-04-07
          • 2021-03-02
          • 2021-04-06
          相关资源
          最近更新 更多