您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
获取知乎某用户下的文章数据
当前为
// ==UserScript== // @name 获取知乎用户文章、回答等数据 // @namespace http://tampermonkey.net/ // @version 1.3.0 // @description 获取知乎某用户下的文章数据 // @author Jazzu Lu //----------------------------------------------------------- // @require https://code.jquery.com/jquery-1.9.1.min.js // @require https://cdn.bootcdn.net/ajax/libs/xlsx/0.17.0/xlsx.full.min.js //----------------------------------------------------------- // @require // @resource css //----------------------------------------------------------- // @include *.zhihu.com/people/* //----------------------------------------------------------- // @run-at document-idle // @original-author Jazzu Lu // @original-license GPL License // @charset UTF-8 // ==/UserScript== /** * 有关导出 xslx 详见 https://github.com/sheetjs/sheetjs * **/ /** 工具函数 **/ Date.prototype.format = function (fmt="YYYY-mm-dd HH:MM") { let date = this; let ret; const opt = { "Y+": date.getFullYear().toString(), // 年 "m+": (date.getMonth() + 1).toString(), // 月 "d+": date.getDate().toString(), // 日 "H+": date.getHours().toString(), // 时 "M+": date.getMinutes().toString(), // 分 "S+": date.getSeconds().toString() // 秒 // 有其他格式化字符需求可以继续添加,必须转化成字符串 }; for (let k in opt) { ret = new RegExp("(" + k + ")").exec(fmt); if (ret) { fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0"))) }; }; return fmt; } window.$ = $; window.sleep = (time)=>new Promise(resolve=>{ setTimeout(()=>{ resolve(); },time) }) function toCSV(header,jsonData,fileName){ //列标题,逗号隔开,每一个逗号就是隔开一个单元格, 类似 `姓名,电话,邮箱` let str = header+='\n'; //增加\t为了不让表格显示科学计数法或者其他格式 for(let i = 0 ; i < jsonData.length ; i++ ){ for(let item in jsonData[i]){ str+=`${jsonData[i][item]},`; } str+='\n'; } //encodeURIComponent解决中文乱码 let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str); //通过创建a标签实现 let link = document.createElement("a"); link.href = uri; //对下载的文件命名 link.download = `${fileName}.csv`; document.body.appendChild(link); link.click(); document.body.removeChild(link); } function toXSL(JSONData, FileName, worksheet) { worksheet = worksheet || FileName; let th = `<thead>${JSONData.headers.map(h=>`<th>${h.text}</th>`).join('')}</thead>`; let tbody = JSONData.data.map(d=> `<tr>${JSONData.headers.map(h=>`<td>${h.type=='link' ? `<a href="${d[h.value]}">${d[h.value]}</a>` : d[h.value]}</td>`).join('')}</tr>`).join(''); tbody = `<tbody>${tbody}</tbody>` let excel = `<table>${th}${tbody}</table>`; let excelFile = `<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8"><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>${worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>${excel}</body></html>`; let uri = 'data:application/vnd.ms-excel;charset=utf-8,' + encodeURIComponent(excelFile); let link = document.createElement("a"); link.href = uri; link.style = "visibility:hidden"; link.download = FileName + ".xls"; document.body.appendChild(link); link.click(); document.body.removeChild(link); } /** 显示右上方的提示信息, 类型有 normal success warning error **/ async function showToast({type = "normal", title = "", content = "", timing = 8*1000}){ if(!$('.jl_toast_list').length){ $("body").append("<div class='jl_toast_list'></div>") } let toastIdx = `jl-${new Date().getTime()}`; let curToast = `<div class="jl_toast ${type} ${toastIdx}"><div class="jl_title">${title}</div><div class="jl_content">${content}</div></div>`; $('.jl_toast_list').append(curToast); $(`.${toastIdx}`).addClass('show'); setTimeout(async ()=>{ $(`.${toastIdx}`).removeClass("show"); await window.sleep(800); $(`.${toastIdx}`).remove(); },timing) } function jlLoading(show=true){ let html = `<div class="jl_loading"> <div class="wrapper"> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="shadow"></div> <div class="shadow"></div> <div class="shadow"></div> </div> <style> .jl_loading{width: 100vw;height: 100vh;position: fixed;top: 0;background: #070f1be3;z-index:10000;display: flex;align-items: center;justify-items: center;} .jl_loading .wrapper{ width:200px; height:60px; position: absolute; left:50%; top:50%; transform: translate(-50%, -50%); } .jl_loading .circle{ width:20px; height:20px; position: absolute; border-radius: 50%; background-color: #fff; left:15%; transform-origin: 50%; animation: jl_circle .5s alternate infinite ease; } .jl_loading .circle:nth-child(2){ left:45%; animation-delay: .2s; } .jl_loading .circle:nth-child(3){ left:auto; right:15%; animation-delay: .3s; } @keyframes jl_circle{ 0% { top:60px; height:5px; border-radius: 50px 50px 25px 25px; transform: scaleX(1.7); } 40%{ height:20px; border-radius: 50%; transform: scaleX(1); } 100%{ top:0%; } } .jl_loading .shadow{ width:20px; height:4px; border-radius: 50%; background-color: rgba(0,0,0,.5); position: absolute; top:62px; transform-origin: 50%; z-index: -1; left:15%; filter: blur(1px); animation: jl_shadow .5s alternate infinite ease; } .jl_loading .shadow:nth-child(4){ left: 45%;animation-delay: .2s } .jl_loading .shadow:nth-child(5){ left:auto; right:15%; animation-delay: .3s; } @keyframes jl_shadow{ 0%{ transform: scaleX(1.5); } 40%{ transform: scaleX(1); opacity: .7; } 100%{ transform: scaleX(.2); opacity: .4; } } </style> </div>`; if(show){ !$('.jl_loading').length ? $('body').append(html) : ''; }else { $('.jl_loading').remove(); } } /** ----------------- 入口 ------------------- **/ (function() { createCss(); /** 创建 css **/ let floatWidget = (`<div id='jl_float_container'><div class="jl_export_single">导出本页</div><div class="jl_export_all">导出全部</div></div>`); /** 左侧小组件 **/ $("body").append(floatWidget); renderBtn(); })(); /** ----------------- 事件 ------------------- **/ async function fetchSingle({scrollTiming = 2000, awaitTiming = 2000}){ let rows = []; $('html, body').animate({ scrollTop: $(document).height() }, scrollTiming); await window.sleep(awaitTiming); $('.ListShortcut .List-item').each((idx,item)=>{ rows.push({ title: $(item).find('.ContentItem-title a').text(), link: 'https:' + $(item).find('.ContentItem-title a').attr('href'), des: $(item).find('.RichContent-inner .RichText').text(), voteUp: $(item).find('.ContentItem-actions .VoteButton--up').text()?.split(' ')[1] || 0, }) }) return rows; } async function writeData(timing){ let JL_DATA = await fetchSingle(timing); let oldData = localStorage.getItem('JL_DATA') || '[]'; oldData = JSON.parse(oldData); oldData.push(...JL_DATA); localStorage.setItem('JL_DATA',JSON.stringify(oldData)); } function exportFile(data){ let sheetName = $('.ProfileMain-header .Tabs-link.is-active').eq(0).text(); let fileName = $('.ProfileHeader-name').text() + sheetName; data.unshift({title:'标题',link:'链接',des:'描述',voteUp:'赞同'}) let ws = XLSX.utils.json_to_sheet(data, {header:["title","link","des","voteUp"],skipHeader:true}); for (const wsKey in ws) { if(ws[wsKey]?.v?.indexOf('http')!=-1){ ws[wsKey].l = {Target:ws[wsKey].v,Tooltip:ws[wsKey].v} } } ws['!cols'] = [ {wpx: 200}, {wpx: 280}, {wpx: 200}, {wpx: 60}, ]; let wb = { Sheets: {[sheetName]:ws}, SheetNames:[sheetName] } console.log('wb=========',ws) XLSX.writeFile(wb, `${fileName}.xlsx`); } async function exportSingle(){ jlLoading(true); let PL_ROWS = await fetchSingle({}); exportFile(PL_ROWS); jlLoading(false); showToast({type:"success",content:'导出成功 0.0'}) } async function exportAll(){ localStorage.setItem('JL_DATA',[]); /** 清空数据 **/ jlLoading(true); let allPage = $('.ListShortcut .Pagination .PaginationButton-next').prev().text() || 1; allPage = Number(allPage); for (let i = 0; i < allPage; i++) { await window.sleep(1000); $('html, body').animate({ scrollTop: 0 }, 1000); /** 滑动到上面 **/ await writeData({awaitTiming:3500}); /** 滑动到底部记录数据 **/ let $nextPage = $('.ListShortcut .Pagination .PaginationButton-next'); if($nextPage.length){ $nextPage.trigger('click') }else break; } jlLoading(false); /** 导出数据 **/ let JL_DATA = localStorage.getItem('JL_DATA') || '[]'; JL_DATA = JSON.parse(JL_DATA); exportFile(JL_DATA); showToast({type:"success",content:'导出成功 0.0'}) } /** ----------------- 渲染 DOM ------------------- **/ /** 渲染 Button **/ function renderBtn(){ $("#jl_float_container .jl_export_single").on("click",exportSingle); $("#jl_float_container .jl_export_all").on("click",exportAll); } /** ----------------- 渲染 Style ------------------- **/ function createCss(){ let css = (` <style> /* toast 样式 */ .jl_toast{position: fixed;right: -245px;top: 2vh;border-radius:5px;box-shadow: 0 1px 3px rgb(18 18 18 / 10%);padding: 15px 20px;width: 200px;z-index: 10000;transition: .8s ease all;color:#fff;} .jl_toast.show{right: 5px;} .jl_toast.normal{background: #009fdc;} .jl_toast.success{background: #25d028;} .jl_toast.warning{background: #fd5b1f;} .jl_toast.error{background: #fe3737;} .jl_toast .jl_title{font-size: 16px;} .jl_toast .jl_content{font-size: 14px;} /* toast 样式 */ #jl_snapshot{position: fixed;right: 0;top: 5vh;border: 2px #333 solid;padding: 0;display: none;} #jl_float_container{position: fixed;left: -0px;top: 20vh;z-index: 10000;padding: 10px;border: 1px #ddd solid;border-radius:5px;transition: .8s all ease;background: #fff;} #jl_float_container:hover{left: 0;} #jl_float_container .ma{margin: 10px;} #jl_float_container .ml{margin-left: 10px;} #jl_float_container .mr{margin-right: 10px;} #jl_float_container .mt{margin-top: 10px;} #jl_float_container .mb{margin-bottom: 10px;} /* 按钮样式 */ #jl_float_container div{ margin: 5px;border: 1px solid #8b8b8d;padding: 5px 10px;color:#0f1d34;border-radius: 4px;cursor: pointer; } </style> `) $("body").append(css); }