NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @namespace https://tampermonkey.myso.kr/ // @name 네이버 검색결과 데이터랩 검색어 트렌드 // @description 네이버 검색결과에서 데이터랩의 검색어 트렌드 정보를 확인할 수 있습니다. // @copyright 2021, myso (https://tampermonkey.myso.kr) // @license Apache-2.0 // @version 1.1.1 // @updateURL https://github.com/myso-kr/kr.myso.tampermonkey/raw/master/service/com.naver.search-trend.analysis.user.js // @downloadURL https://github.com/myso-kr/kr.myso.tampermonkey/raw/master/service/com.naver.search-trend.analysis.user.js // @author Won Choi // @match *://search.naver.com/search.naver?* // @match *://m.search.naver.com/search.naver?* // @connect naver.com // @connect ryo.co.kr // @grant GM_addStyle // @grant GM_xmlhttpRequest // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.49/assets/vendor/gm-app.js // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.49/assets/vendor/gm-add-style.js // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.49/assets/vendor/gm-add-script.js // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.49/assets/vendor/gm-xmlhttp-request-async.js // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.49/assets/donation.js // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.49/assets/lib/naver-datalab.js // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.49/assets/lib/naver-search-ad.js // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.49/assets/lib/naver-search-nx.js // @require https://cdn.jsdelivr.net/npm/chart.js // @require https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.7.2/bluebird.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js // ==/UserScript== // ==OpenUserJS== // @author myso // ==/OpenUserJS== GM_App(async function main() { function format_number(number) { return number.toString().split( /(?=(?:\d{3})+(?:\.|$))/g ).join( "," ); } function parsed_number(number) { return /^[\d\.]+$/.test(String(number)) ? parseFloat(number) : 0; } GM_donation('#container', 0); const range = _.range(32).map(o=>moment().subtract(o + 1, 'days').format('YYYYMMDD')).sort(); const keyword = (new URL(location.href)).searchParams.get('query'); if(!keyword) return; const keyword_search = await Promise.resolve().then(async()=>{ const stat = await NA_search(keyword); const data = await ND_trend(keyword); const sums = data.reduce((r, o)=>r+o.value, 0); const tick = stat ? (stat.monthlyQcCnt / sums) : 1; const items = range.map((period)=>Object.assign({ period, value: 0 }, _.find(data, { period }))).map((item)=>(item.value = (item.value * tick), item)); return { items, rval: !!stat }; }); const keyword_create = await Promise.map(range, async (period)=>{ const props = await Promise.props({ blog_count: NX_count(keyword, 'blog', 'normal', { api_type: 1, nso: `so:r,p:from${period}to${period},a:all` }), view_count: NX_count(keyword, 'view', 'normal', { api_type: 11, nso: `so:r,p:from${period}to${period},a:all` }), cafe_count: NX_count(keyword, 'article', 'normal', { prmore: 1, nso: `so:r,p:from${period}to${period},a:all` }), }); return { period, ...props }; }); const pack = document.querySelector('#main_pack, #snb'); const wrap = pack.querySelector('.section.trend') || document.createElement('section'); wrap.classList.add('section', 'trend'); pack.prepend(wrap); const canv = wrap.querySelector('canvas') || document.createElement('canvas'); canv.style.width = '100%'; canv.style.height = '120px'; wrap.append(canv); const config = { type: 'line', data: { labels: range, datasets: [ { yAxisID: 'y1', viewtype:'search_cnt', backgroundColor: '#74d2e7', borderColor: '#48a9c5', data: _.map(keyword_search.items, o=>o.value), }, { yAxisID: 'y2', viewtype:'view_count', backgroundColor: '#52565e', borderColor: '#caccd1', data: _.map(keyword_create, o=>o.view_count), }, { yAxisID: 'y3', viewtype:'blog_count', backgroundColor: '#279b37', borderColor: '#34bf49', data: _.map(keyword_create, o=>o.blog_count), }, { yAxisID: 'y3', viewtype:'cafe_count', backgroundColor: '#f48924', borderColor: '#ffc845', data: _.map(keyword_create, o=>o.cafe_count), }, ], }, options: { scales: { x: { display: false, }, y1: { type: 'linear', display: true, position: 'left', }, y2: { type: 'linear', display: false, position: 'left', grid: { drawOnChartArea: false, }, }, y3: { type: 'linear', display: false, position: 'right', grid: { drawOnChartArea: false, }, }, }, plugins: { title: { display: true, text(context) { return '검색어 검색/생산/노출 트렌드'; } }, legend: { display: false }, tooltip: { mode: 'index', intersect: false, callbacks: { label(context) { if(context.dataset.viewtype == 'search_cnt') return (keyword_search.rval) ? `검색량: ${format_number(context.parsed.y.toFixed(0))}회` : `검색율: ${format_number(context.parsed.y.toFixed(2))}%`; if(context.dataset.viewtype == 'view_count') return `노출량: ${format_number(context.parsed.y.toFixed(0))}건 노출 됨`; if(context.dataset.viewtype == 'blog_count') return `블로그: ${format_number(context.parsed.y.toFixed(0))}건 생산 됨`; if(context.dataset.viewtype == 'cafe_count') return `카페: ${format_number(context.parsed.y.toFixed(0))}건 생산 됨`; return ''; } } } }, } }; const chart = new Chart(canv, config); })