// ==UserScript== // @name 企业信息要素摘录(风鸟)@极客律师 // @namespace corp-info-extract-fengniao // @version 0.15 // @description 风鸟:提取公司名称/统一社会信用代码/地址/法定代表人,默认复制格式化文字;Alt 复制JSON。 // @match https://www.riskbird.com/ent/* // @match https://www.riskbird.com/company/* // @run-at document-end // @grant GM_setClipboard // @grant GM_notification // ==/UserScript== (function () { 'use strict'; /** ========================= * Utils * =========================*/ const sleep = (ms) => new Promise(r => setTimeout(r, ms)); function normText(s) { return (s ?? '') .toString() .replace(/\u00A0/g, ' ') .replace(/\s+/g, ' ') .trim(); } // 基础清理 logic function cleanPersonName(raw) { const s = normText(raw); // 去除可能的 "关联10家企业>" 等后缀 return s.replace(/关联\d+家企业.*/, '').trim(); } function notify(text, title = '风鸟信息摘录') { try { if (typeof GM_notification === 'function') { GM_notification({ title, text, timeout: 2000 }); } } catch (e) {} console.info(`[${title}] ${text}`); } async function copyToClipboard(text) { try { if (typeof GM_setClipboard === 'function') { GM_setClipboard(text, 'text'); return true; } } catch (e) { } try { await navigator.clipboard.writeText(text); return true; } catch (e) { return false; } } /** ========================= * FengNiao Logic * =========================*/ // 获取公司名称 function getFengNiaoCompanyName() { const nameEl = document.querySelector('.info-basic-name'); if (nameEl) { const clone = nameEl.cloneNode(true); const tags = clone.querySelectorAll('.popover-box, .new-clip-btn, .toast-wrap'); tags.forEach(t => t.remove()); return normText(clone.textContent); } return ''; } function getValueByLabelFengNiao(labelPart) { const rows = Array.from(document.querySelectorAll('.info-basic-grow')); for (const row of rows) { const rowText = normText(row.textContent); if (!rowText.includes(labelPart)) continue; let valEl = row.querySelector('.xs-clip-text') || row.querySelector('.frname-box'); if (valEl) { const clone = valEl.cloneNode(true); clone.querySelectorAll('.new-clip-btn, .toast-wrap, .popover-box, .fr-entcount').forEach(e => e.remove()); return normText(clone.textContent); } } return ''; } async function buildPayloadFengNiao() { const company_name = getFengNiaoCompanyName(); const uscc = getValueByLabelFengNiao('统一社会信用代码'); const address = getValueByLabelFengNiao('地址'); const phone = getValueByLabelFengNiao('电话'); let legalRepName = getValueByLabelFengNiao('法定代表人'); legalRepName = cleanPersonName(legalRepName); // Try to find positions from the "Senior Executives" table ONLY let positions = []; if (legalRepName) { // Locate the "Senior Executives" (高级职员) module specifically const modules = Array.from(document.querySelectorAll('.xs-data-module-box')); const execModule = modules.find(m => m.textContent.includes('高级职员')); if (execModule) { const tableRows = Array.from(execModule.querySelectorAll('tr.tr-box')); for (const row of tableRows) { const text = normText(row.textContent); if (text.includes(legalRepName)) { const cells = Array.from(row.querySelectorAll('td')); for (const cell of cells) { let cellText = normText(cell.textContent); if (cellText === legalRepName) continue; if (cellText.includes('董事长') || cellText.includes('经理') || cellText.includes('董事') || cellText.includes('监事') || cellText.includes('总裁')) { let pos = cellText .replace(/法定代表人/g, '') .replace(/[;;。.,,、\s]+/g, ' ') .trim() .replace(/ /g, '、'); if (pos) positions.push(pos); } } } } } } positions = [...new Set(positions)]; return { company_name, uscc, address, phone, legal_representative: { name: legalRepName, positions }, source: { site: 'fengniao', url: location.href, captured_at: new Date().toISOString() } }; } /** ========================= * Output format * =========================*/ function positionsToPhrase(positions) { if (!positions || positions.length === 0) return ''; return `系该公司${positions.join('、')}`; } function formatResultText(payload) { const name = payload.company_name || ''; const addr = payload.address || ''; const uscc = payload.uscc || ''; const lrName = payload.legal_representative?.name || ''; const posArr = payload.legal_representative?.positions || []; const line1 = `${name},住所地:${addr},统一社会信用代码:${uscc}。`; const phrase = positionsToPhrase(posArr); const line2 = phrase ? `法定代表人:${lrName},${phrase}。` : `法定代表人:${lrName}。`; return `${line1}\n${line2}`; } function formatElementStyleText(payload) { const name = payload.company_name || ''; const addr = payload.address || ''; const uscc = payload.uscc || ''; const lrName = payload.legal_representative?.name || ''; const pos = (payload.legal_representative?.positions || []).join('、'); const phone = payload.phone || ''; return [ `名称:${name}`, `住所地(主要办事机构所在地):${addr}`, `注册地/登记地:${addr}`, `法定代表人/主要负责人:${lrName} 职务:${pos} 联系电话:${phone}`, `统一社会信用代码:${uscc}` ].join('\n'); } function warnIfMissing(payload) { const missing = []; if (!payload.company_name) missing.push('公司名称'); if (!payload.uscc) missing.push('统一社会信用代码'); if (!payload.address) missing.push('地址'); if (!payload.legal_representative?.name) missing.push('法定代表人'); if (missing.length) notify(`部分字段为空:${missing.join('、')}`); } /** ========================= * UI + Hotkeys * =========================*/ function addFloatingButton(run) { const container = document.createElement('div'); container.style.cssText = 'position:fixed;right:16px;bottom:16px;z-index:999999;display:flex;flex-direction:column;gap:10px;'; const createBtn = (text, mode) => { const btn = document.createElement('button'); btn.textContent = text; btn.setAttribute('type', 'button'); btn.dataset.originalText = text; btn.style.cssText = [ 'padding:10px 12px', 'border-radius:10px', 'border:1px solid rgba(0,0,0,.15)', 'background:#fff', 'box-shadow:0 8px 20px rgba(0,0,0,.12)', 'cursor:pointer', 'font-size:14px', 'line-height:1', 'color: #333', 'transition: all 0.3s' ].join(';'); btn.addEventListener('click', () => run({ mode, btn })); return btn; }; container.appendChild(createBtn('复制信息(要素式)', 'element')); container.appendChild(createBtn('复制信息', 'text')); document.body.appendChild(container); } function addHotkeys(run) { window.addEventListener('keydown', (e) => { if (!(e.altKey && e.shiftKey)) return; if (e.key === 'C' || e.key === 'c') { e.preventDefault(); run({ mode: 'text' }); } if (e.key === 'E' || e.key === 'e') { e.preventDefault(); run({ mode: 'element' }); } if (e.key === 'J' || e.key === 'j') { e.preventDefault(); run({ mode: 'json' }); } }, true); } async function runCopy({ mode = 'text', btn = null } = {}) { try { const payload = await buildPayloadFengNiao(); warnIfMissing(payload); let toCopy = ''; if (mode === 'json') toCopy = JSON.stringify(payload, null, 2); else if (mode === 'element') toCopy = formatElementStyleText(payload); else toCopy = formatResultText(payload); const ok = await copyToClipboard(toCopy); if (ok && btn) { const oldText = btn.dataset.originalText; btn.textContent = '已复制!'; btn.style.color = '#1c58e5'; btn.style.fontWeight = 'bold'; setTimeout(() => { btn.textContent = oldText; btn.style.color = '#333'; btn.style.fontWeight = 'normal'; }, 2000); } else if (ok) { notify('已复制'); } } catch (e) { console.error('[FengNiao] error', e); notify('提取失败'); } } setTimeout(() => { addFloatingButton(runCopy); addHotkeys(runCopy); }, 1000); })();