Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
cookjohn avatar

Wos Parse Results

  • 40 installs
  • 105 repo stars
  • Updated March 13, 2026
  • cookjohn/wos-skills

Parses Web of Science search results from the current results page or API response to extract structured data.

About

An internal skill that extracts structured data from WoS via API response or DOM scraping. Other skills use it to parse results.

  • Prefers API-response parsing over DOM scraping fallback
  • Used internally by other WoS skills

Wos Parse Results by the numbers

  • 40 all-time installs (skills.sh)
  • Ranked #1,142 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
  • Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cookjohn/wos-skills --skill wos-parse-results

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs40
repo stars105
Last updatedMarch 13, 2026
Repositorycookjohn/wos-skills

What it does

Parses Web of Science search results from the current results page or API response to extract structured data.

Files

SKILL.mdMarkdownGitHub ↗

WoS Parse Results

Internal skill for extracting structured data from WoS. Two modes: API response parsing (preferred) or DOM scraping (fallback).

Mode A: API Response Parsing (preferred)

When using the runQuerySearch API, the response is NDJSON. Parse records from the records payload:

// Parse NDJSON response text
const lines = text.trim().split('\n').map(l => { try { return JSON.parse(l); } catch(e) { return null; } }).filter(Boolean);
const searchInfo = lines.find(l => l.key === 'searchInfo')?.payload;
const recordsData = lines.find(l => l.key === 'records')?.payload;

const records = Object.entries(recordsData).map(([idx, rec]) => ({
  idx: parseInt(idx),
  wosId: rec.colluid,
  title: rec.titles?.item?.en?.[0]?.title || '',
  authors: rec.names?.author?.en?.filter(Boolean).map(a => a.wos_standard).join('; ') || '',
  source: rec.titles?.source?.en?.[0]?.title || '',
  year: rec.pub_info?.pubyear || '',
  vol: rec.pub_info?.vol || '',
  issue: rec.pub_info?.issue || '',
  pages: rec.pub_info?.page_no || '',
  doi: rec.doi || '',
  citations: rec.citation_related?.counts?.WOSCC || 0,
  citationsAll: rec.citation_related?.counts?.ALLDB || 0,
  refCount: rec.ref_count || 0,
  abstract: rec.abstract?.basic?.en?.abstract?.replace(/<[^>]*>/g, '') || '',
  docType: rec.doctypes?.[0] || '',
  oa: rec.oa || false
}));

Mode B: DOM Scraping (fallback)

When the browser is on a results page and API is not available:

async () => {
  for (let i = 0; i < 20; i++) {
    if (document.querySelector('app-record')) break;
    await new Promise(r => setTimeout(r, 500));
  }

  const records = [...document.querySelectorAll('app-record')].map((rec, idx) => {
    const titleEl = rec.querySelector('a[data-ta="summary-record-title-link"]');
    const title = titleEl?.textContent?.trim() || '';
    const href = titleEl?.href || '';
    const wosId = href.match(/WOS:\w+/)?.[0] || '';
    const authorEls = rec.querySelectorAll('a[data-ta*="DisplayName-author"]');
    const authors = [...authorEls].map(a => a.textContent?.trim()).join('; ');
    const sourceEl = rec.querySelector('a[data-ta="jcr-link-menu"]');
    const source = sourceEl?.textContent?.trim()?.replace('arrow_drop_down', '') || '';
    const citedEl = rec.querySelector('a[data-ta="stat-number-citation-related-count"]');
    const citations = citedEl?.textContent?.trim() || '0';
    return { idx: idx + 1, title, wosId, authors, source, citations };
  });

  return { status: 'ok', recordCount: records.length, records };
}

Notes

  • Mode A is always preferred — structured JSON, no selector fragility
  • Mode B is fallback when already on a results page without API access
  • DOM selectors may miss records due to lazy loading or dynamic rendering

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.