百度文库复制破解 | 宁静致远

百度文库复制破解

正在加载一言...


最近老婆告诉我,百度文库突然不能复制了,我记得之前都是好好的啊,除非它改版了,这不看了一下,还真的是改版了。使命必达,下面就和我一起找找破解之法吧。

Greasy Fork相关信息:


 
 
 
 

更新日志:


20220210:

  1. 美化显示格式
  2. 增加第一获取失败提示
  3. 图片可以显示

20220215:

  1. 提交脚本到Greasy Fork脚本安装地址在这里
  2. 增加Greasy Fork相关信息展示

0.思路与过程


从下图可以看到,现在的文章是写在canvas里的,感觉他应该是在前端渲染的,所以肯定有相关文章数据,接下来就开始找渲染的数据。
文章节点定位
看了一下下图请求的数据,发现下面这几个请求比较符合。里面是数据也能匹配上文章内容。
有用的数据
但是这些请求链接有点过分的长,参数也很多,想要把参数弄齐不是件简单的事情,所以想想是不是有别的地方有这个数据。这不看了一下页面数据,找到了一个pageData这个变量,看名字是页面数据,拿出来看看数据是啥样的。下图是格式化后的数据。
页面数据
发现这个变量里面是有相关数据的,这不就可以开始撸代码了。

1.编码


这边使用的是油猴,英文名是Tampermonkey来开发脚本的。之前一直用,但是没有开发过它的脚本,好在是JavaScript的,所以搞起来很快。

Tampermonkey 是一款免费的浏览器扩展和最为流行的用户脚本管理器,它适用于 Chrome, Microsoft Edge, Safari, Opera Next, 和 Firefox。
虽然有些受支持的浏览器拥有原生的用户脚本支持,但 Tampermonkey 将在您的用户脚本管理方面提供更多的便利。 它提供了诸如便捷脚本安装、自动更新检查、标签中的脚本运行状况速览、内置的编辑器等众多功能, 同时Tampermonkey还有可能正常运行原本并不兼容的脚本。

有了前面的铺垫,编码其实很简单了,就不着重介绍了,代码贴出来,可以自己试试,写的仓促,弹窗和按钮用的别人脚本里的,有功夫的话可以自己画画写写。功能可以使用,后面在慢慢优化。油猴的安装方法和相关的API大家可以自行查找,还是很多的。

// ==UserScript==
// @name         百度文库拷贝
// @namespace    http://tampermonkey.net/
// @homepage     https://www.wangxingyang.com/baiduwenku.html
// @version      0.2
// @description  破解百度文库复制限制
// @author       freefitter
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAABpElEQVR4nO3Vv2uUQRDG8c/ebSMWqay0trATAxrUSi1S2AiWFoJYpNCgoBjURsHWJKeNRfAvsDgFixQqKdPZ2ViEiCJYBOQu8f1hEXO59713j7MUfLZ6d2a/O8vMO0OzDnin9Ku2Mjvuaw07xgSAYEVXe2indMhj92zpKJLnBhF8MDeye9hn6zbN70eRiqCw02Bra3up8BBLu1FEBxsBucXqW4csz0ULe4jorSCMuPU89boRELDMHiI6Y8V65bbCUTccc70RkaOwKLOg0IkyXa9qTjOu2LAs6NZuD86hrdTyxRNTkUqqdhXlHrngGRVEZsMpJwex9DxIZSHYclesIb65LCoHgIs66UJq6btDBZHZrPh8V6YBOX66LbOkTGckBYimBW2FVTNeuOZNyrFJ236Yl4NSy5SbVm1PDvhodqgyMledTdRlAtDzqfL9tfkwUtyaRkv9LwFj9B/w7wPycXOhqlJ0yZHKPChMi5MCiM47XhsopbVJAUHfrYbmN/EToN+02eLPfz9OYyZhFJzW1Jn3lTsxaKQjCkp52jy45r1ZvSbTb9M0d4PBozGZAAAAAElFTkSuQmCC
// @include      *://wenku.baidu.com/*
// @run-at       document-end
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_listValues
// @grant        GM_deleteValue
// @grant        unsafeWindow
// @require      https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js
// ==/UserScript==
(function() {
    'use strict';
    var url = window.location.href;
    var host = window.location.host;
    console.log(url);
    if((url.indexOf("wenku.baidu.com/view")==-1 && url.indexOf("wenku.baidu.com/link")==-1) || host!="wenku.baidu.com"){
			return;
		}
    var allContent = "";
    var $ = $ || window.$; //获得jquery的$标识符
    var pageNum = 0,loadPageNum =0 ,docid = "";
    // 添加相关按钮
    var copyBtn = "<div style='position:fixed;z-index:999;background-color:#ccc;cursor:pointer;top:120px;left:0px;'>"+
        "<div id='copyBtn' style='font-size:12px;padding:8px 2px;color:#FFF;background-color:#FE8A23;'>复制</div>"+
        "</div>";
    $("body").append(copyBtn);

    function getCopyData(indexpagedata){
        //debugger;
        allContent = "";
        if(null == indexpagedata || undefined == indexpagedata || "" == indexpagedata)
        {
            console.log("页面数据没取到啊");
            return;
        }else{
            //解析出文章路径
            if(!indexpagedata.hasOwnProperty("readerInfo")){
                console.log("这个文章还不能解析.....");
                return;
            }
            var htmlUrls= indexpagedata.readerInfo.htmlUrls;
            if(!htmlUrls.hasOwnProperty("json")){
                console.log("PPT 解析成图片.....");
                for(let i in htmlUrls){
                    allContent += "<img src='" + htmlUrls[i] + "'/>";
                }
            }else{
                //console.log(GM_listValues())
                var pageinfos = htmlUrls.json;
                var pnginfos = htmlUrls.png;
                // 总页数
                pageNum = indexpagedata.readerInfo.page;
                docid = indexpagedata.readerInfo.docId;
                // 返回的数据页数
                loadPageNum = pageinfos.length;
                for(var ii in pageinfos){
                    let pageLoadUrl = pageinfos[ii].pageLoadUrl;
                    GM_xmlhttpRequest({
                        url: pageLoadUrl,
                        method: 'GET',
                        onload: obj => {
                            let data=obj.response;
                            //console.log(data)
                            // 1、将数据拆分成key和value
                            let key = data.substr(0,data.indexOf("("));
                            let val = data.substr(data.indexOf("(")+1,data.lastIndexOf(")")-data.indexOf("(")-1);
                            // 2、解析文章数据
                            let retJson = JSON.parse(val);
                            let articleInfos = retJson.body;
                            let content = "";
                            //console.log(articleInfos);
                            // 组成完整的章节文章
                            var lineY = 0;
                            for(let i in articleInfos){
                                if("word" == articleInfos[i].t){
                                    // 增加换行
                                    let y = articleInfos[i].p.y
                                    if(lineY == 0){
                                        content += articleInfos[i].c
                                        lineY = y;
                                    }else if(y == lineY){
                                        content += articleInfos[i].c
                                    }else{
                                        if("" != articleInfos[i].c.trim()){
                                            content += "<br/>" + articleInfos[i].c;
                                        }else{
                                            if(" " == articleInfos[i].c){
                                                content += "<br/>" + articleInfos[i].c;
                                            }else{
                                                console.log("未处理的字符:["+ articleInfos[i].c +"]");
                                            }
                                        }
                                        lineY = y;
                                    }
                                }else if("pic" == articleInfos[i].t){
                                    //style="position: absolute;clip: rect(0px,250px,200px,50px);width: 300px;height: 200px">
                                    if(null == articleInfos[i].s || "" == articleInfos[i].s || undefined ==articleInfos[i].s){
                                        //content += "=****pic"+ i +"*****=";
                                        // 文章中包含图片,不处理
                                        content += "";
                                    }else{
                                        content = "PIC"
                                    }
                                    //content += '<img src="' + pnginfos[0].pageLoadUrl + '" style="position: absolute;clip: rect('+ articleInfos[i].c.ix +'px,'+ articleInfos[i].c.iy +'px,'+ articleInfos[i].c.iw +'px,'+ articleInfos[i].c.ih +'px);"/>'
                                }
                            }
                            GM_setValue(docid+key, content);
                        },onerror: err => {
                            console.log(err)
                        }
                    });/**/

                }
                // 按序输出结果
                for(let j=1; j<= loadPageNum ;j++){
                    let tmp = GM_getValue(docid+"wenku_"+j,"");
                    if(tmp == "PIC"){
                        //allContent = allContent.replace("=****pic"+ (j - 1 )+"*****=","<img src='" + pnginfos[j-1].pageLoadUrl + "'/>");
                        allContent += "<img src='" + pnginfos[j-1].pageLoadUrl + "'/>";
                    }else{
                        allContent += tmp;
                    }
                    // 移除相关Key
                    GM_deleteValue(docid+"wenku_"+j);
                }
                //console.log(GM_listValues())
            }
        }
    }

    // 点击拷贝
    $("body").on("click","#copyBtn",function(){
        let indexpagedata = unsafeWindow.pageData;
        getCopyData(indexpagedata);
        let ua = navigator.userAgent;
        let opacity = '0.95';
        if (ua.indexOf("Edge") >= 0) {
            opacity = '0.6';
        } else{
            opacity = '0.95';
        }
        let str = "";
        if(loadPageNum != pageNum){
            str = "当前加载了[" + loadPageNum +"]页,总共[" + pageNum + "]页,登录会加载更多页。"
        }
        let copyTextBox = '<div id="copy_text_box" style="width:100%;height:100%;position: fixed;z-index: 99;display: block;top: 0px;left: 0px;background:rgba(255,255,255,' + opacity + ');-webkit-backdrop-filter: blur(20px);display: flex;justify-content:center;align-items:center;">'+
            '<div id="copy_box_close" style="width:100%;height:100%;position:fixed;top:0px;left:0px;"><div style="font-size:16px;margin-top:20px;text-align:center;"><b>点击文本外关闭弹框</b><div><b style="color:red">' + str +'</b></div></div></div>'+
            '<pre id="copy_text_content" style="padding:20px;border:1px solid #CCC;border-radius:4px;width:60%;font-size:16px;line-height:22px;z-index:10000;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;word-break:break-all;max-height:70%;overflow:auto;"></pre>'+
            '</div>"';
        $('#copy_text_box').remove();
        if("" == allContent){
            allContent = "未获取成功,请再次点击复制按钮!"
        }
        $('body').append(copyTextBox);
        $('#copy_text_content').html(allContent);
        $('#copy_box_close').click(function() {
            $('#copy_text_box').remove();
        });

    });

})();

2.成果展示


点击旁边的复制就可以愉快的复制相关内容啦。
原始文档

可复制的

3.说在最后


到此功能完成了,后续可以优化一下,加上图片啥的。这个数据都是有的,就是花时间弄就完事了。这个仅做学习交流使用哈。


文章作者: 彤爸比
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 彤爸比 !
评论
  目录