vibes-plug 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/BLUEPRINT.md +125 -0
- package/CHANGELOG.md +195 -0
- package/CONTRIBUTING.md +199 -0
- package/LICENSE +21 -0
- package/README.md +263 -0
- package/SECURITY.md +21 -0
- package/banner.png +0 -0
- package/package.json +25 -0
- package/plugin.json +8 -0
- package/scripts/update_skills.js +75 -0
- package/skills/ai-llm-integration-expert/SKILL.md +162 -0
- package/skills/api-design-expert/SKILL.md +310 -0
- package/skills/app-analyzer-optimizer/SKILL.md +189 -0
- package/skills/asisten_ramah/SKILL.md +41 -0
- package/skills/authentication-identity-expert/SKILL.md +45 -0
- package/skills/auto-doc-updater/SKILL.md +204 -0
- package/skills/bootstrap-to-modern/SKILL.md +87 -0
- package/skills/brainstorming/SKILL.md +353 -0
- package/skills/bun-runtime-expert/SKILL.md +211 -0
- package/skills/ci-cd-devops-architect/SKILL.md +45 -0
- package/skills/cloud-hosting-expert/SKILL.md +244 -0
- package/skills/coderabbit/SKILL.md +192 -0
- package/skills/data-telemetry-expert/SKILL.md +213 -0
- package/skills/database-orm-expert/SKILL.md +294 -0
- package/skills/design-system-architect/SKILL.md +243 -0
- package/skills/e2e-testing-expert/SKILL.md +315 -0
- package/skills/event-driven-architect/SKILL.md +81 -0
- package/skills/firebase-security-expert/SKILL.md +195 -0
- package/skills/fullstack-expert/SKILL.md +202 -0
- package/skills/fullstack-expert/references/api_design_guide.md +466 -0
- package/skills/fullstack-expert/references/devops_infrastructure.md +477 -0
- package/skills/fullstack-expert/references/multi_language_backend.md +528 -0
- package/skills/fullstack-expert/references/system_design_patterns.md +358 -0
- package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -0
- package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -0
- package/skills/gemini-agent-booster/SKILL.md +135 -0
- package/skills/global-a11y-i18n-expert/SKILL.md +81 -0
- package/skills/go-programming-expert/SKILL.md +295 -0
- package/skills/hig/SKILL.md +188 -0
- package/skills/js-backend-expert/SKILL.md +192 -0
- package/skills/mcp-server-architect/SKILL.md +194 -0
- package/skills/mobile-expo-expert/SKILL.md +186 -0
- package/skills/monday-design-aesthetic/SKILL.md +67 -0
- package/skills/monorepo-architect/SKILL.md +227 -0
- package/skills/mpa-orchestrator/SKILL.md +101 -0
- package/skills/multi-agent-orchestration/SKILL.md +234 -0
- package/skills/multiple-entry-points/SKILL.md +55 -0
- package/skills/mvc-expert/SKILL.md +231 -0
- package/skills/payment-gateway-expert/SKILL.md +45 -0
- package/skills/performance-web-vitals/SKILL.md +332 -0
- package/skills/prd-architect/SKILL.md +191 -0
- package/skills/production-ready-hardener/SKILL.md +469 -0
- package/skills/production-ready-hardener/references/performance_optimization.md +441 -0
- package/skills/production-ready-hardener/references/production_checklist.md +161 -0
- package/skills/production-ready-hardener/references/security_hardening_guide.md +379 -0
- package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +875 -0
- package/skills/python-programming-expert/SKILL.md +271 -0
- package/skills/realtime-collaboration-expert/SKILL.md +45 -0
- package/skills/rust-programming-expert/SKILL.md +235 -0
- package/skills/saas-billing/SKILL.md +377 -0
- package/skills/saas-multi-tenant/SKILL.md +237 -0
- package/skills/saas-mvp-launcher/SKILL.md +231 -0
- package/skills/saas-transformer/SKILL.md +446 -0
- package/skills/saas-transformer/references/billing_integration_guide.md +401 -0
- package/skills/saas-transformer/references/feature_gating_patterns.md +137 -0
- package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -0
- package/skills/saas-transformer/scripts/saas_transformation_scanner.py +254 -0
- package/skills/scalability-clean-code/SKILL.md +229 -0
- package/skills/secure-fuzz-testing/SKILL.md +201 -0
- package/skills/senior-frontend/SKILL.md +161 -0
- package/skills/senior-frontend/references/frontend_best_practices.md +806 -0
- package/skills/senior-frontend/references/nextjs_optimization_guide.md +724 -0
- package/skills/senior-frontend/references/react_patterns.md +746 -0
- package/skills/senior-frontend/scripts/bundle_analyzer.py +407 -0
- package/skills/senior-frontend/scripts/component_generator.py +329 -0
- package/skills/senior-frontend/scripts/frontend_scaffolder.py +1005 -0
- package/skills/senior-fullstack/SKILL.md +167 -0
- package/skills/senior-fullstack/references/architecture_patterns.md +160 -0
- package/skills/senior-fullstack/references/development_workflows.md +222 -0
- package/skills/senior-fullstack/references/tech_stack_guide.md +190 -0
- package/skills/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
- package/skills/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
- package/skills/senior-fullstack/scripts/project_scaffolder.py +114 -0
- package/skills/seo/SKILL.md +225 -0
- package/skills/seo/references/cwv-thresholds.md +108 -0
- package/skills/seo/references/eeat-framework.md +214 -0
- package/skills/seo/references/quality-gates.md +155 -0
- package/skills/seo/references/schema-types.md +118 -0
- package/skills/seo-aeo-landing-page-writer/SKILL.md +97 -0
- package/skills/seo-geo/SKILL.md +188 -0
- package/skills/session-handoff-resume/SKILL.md +158 -0
- package/skills/skill_baru/SKILL.md +147 -0
- package/skills/spa-orchestrator/SKILL.md +288 -0
- package/skills/state-management-expert/SKILL.md +272 -0
- package/skills/supabase-migration/SKILL.md +45 -0
- package/skills/supabase-security-expert/SKILL.md +243 -0
- package/skills/tailwind-expert/SKILL.md +188 -0
- package/skills/tanstack-query-expert/SKILL.md +199 -0
- package/skills/tauri-expert/SKILL.md +97 -0
- package/skills/token-saver/SKILL.md +111 -0
- package/skills/typescript-expert/SKILL.md +279 -0
- package/skills/ui-components-expert/SKILL.md +63 -0
- package/skills/ui-ux-pro-max/SKILL.md +201 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/prompts.csv +24 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +59 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-312.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-312.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/core.py +257 -0
- package/skills/ui-ux-pro-max/scripts/design_system.py +493 -0
- package/skills/ui-ux-pro-max/scripts/search.py +81 -0
- package/skills/ui_ux_expert/SKILL.md +114 -0
- package/skills/vibe-code-gardener/SKILL.md +173 -0
- package/skills/web-scraper/SKILL.md +205 -0
- package/skills/web-scraper/references/data-transforms.md +397 -0
- package/skills/web-scraper/references/extraction-patterns.md +475 -0
- package/skills/web-scraper/references/output-templates.md +481 -0
- package/skills/zero-to-prod-orchestrator/SKILL.md +180 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
# Extraction Patterns Reference
|
|
2
|
+
|
|
3
|
+
CSS selectors, JavaScript snippets, and domain-specific tips for
|
|
4
|
+
common web scraping scenarios.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## CSS Selector Patterns
|
|
9
|
+
|
|
10
|
+
### Tables
|
|
11
|
+
|
|
12
|
+
```css
|
|
13
|
+
/* Standard HTML tables */
|
|
14
|
+
table /* All tables */
|
|
15
|
+
table.data-table /* Class-based */
|
|
16
|
+
table[id*="result"] /* ID contains "result" */
|
|
17
|
+
table thead th /* Header cells */
|
|
18
|
+
table tbody tr /* Data rows */
|
|
19
|
+
table tbody tr td /* Data cells */
|
|
20
|
+
table tbody tr td:nth-child(2) /* Specific column (2nd) */
|
|
21
|
+
|
|
22
|
+
/* Grid layouts acting as tables */
|
|
23
|
+
[role="table"] /* ARIA table role */
|
|
24
|
+
[role="row"] /* ARIA row */
|
|
25
|
+
[role="gridcell"] /* ARIA grid cell */
|
|
26
|
+
.table-responsive table /* Bootstrap responsive wrapper */
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Product Listings
|
|
30
|
+
|
|
31
|
+
```css
|
|
32
|
+
/* E-commerce product grids */
|
|
33
|
+
.product-card, .product-item, .product-tile
|
|
34
|
+
[data-product-id] /* Data attribute markers */
|
|
35
|
+
.product-name, .product-title, h2.title
|
|
36
|
+
.price, .product-price, [data-price]
|
|
37
|
+
.price--sale, .price--original /* Sale vs original price */
|
|
38
|
+
.rating, .stars, [data-rating]
|
|
39
|
+
.availability, .stock-status
|
|
40
|
+
.product-image img, .product-thumb img
|
|
41
|
+
|
|
42
|
+
/* Common e-commerce patterns */
|
|
43
|
+
.search-results .result-item
|
|
44
|
+
.catalog-grid .catalog-item
|
|
45
|
+
.listing .listing-item
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Search Results
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
/* Generic search result patterns */
|
|
52
|
+
.search-result, .result-item, .search-entry
|
|
53
|
+
.result-title a, .result-link
|
|
54
|
+
.result-snippet, .result-description
|
|
55
|
+
.result-url, .result-source
|
|
56
|
+
.result-date, .result-timestamp
|
|
57
|
+
.pagination a, .page-numbers a, [aria-label="Next"]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Contact / Directory
|
|
61
|
+
|
|
62
|
+
```css
|
|
63
|
+
/* People and contact cards */
|
|
64
|
+
.team-member, .staff-card, .person, .contact-card
|
|
65
|
+
.member-name, .person-name, h3.name
|
|
66
|
+
.member-title, .job-title, .role
|
|
67
|
+
.member-email a[href^="mailto:"]
|
|
68
|
+
.member-phone a[href^="tel:"]
|
|
69
|
+
.member-bio, .person-description
|
|
70
|
+
.vcard /* hCard microformat */
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### FAQ / Accordion
|
|
74
|
+
|
|
75
|
+
```css
|
|
76
|
+
/* FAQ and accordion patterns */
|
|
77
|
+
.faq-item, .accordion-item, [itemtype*="FAQPage"] [itemprop="mainEntity"]
|
|
78
|
+
.faq-question, .accordion-header, [itemprop="name"], summary
|
|
79
|
+
.faq-answer, .accordion-body, .accordion-content, [itemprop="acceptedAnswer"]
|
|
80
|
+
details, details > summary /* Native HTML accordion */
|
|
81
|
+
[role="tabpanel"] /* Tab-based FAQ */
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Pricing Tables
|
|
85
|
+
|
|
86
|
+
```css
|
|
87
|
+
/* SaaS pricing page patterns */
|
|
88
|
+
.pricing-table, .pricing-card, .plan-card, .pricing-tier
|
|
89
|
+
.plan-name, .tier-name, .pricing-title
|
|
90
|
+
.plan-price, .pricing-amount, .price-value
|
|
91
|
+
.plan-period, .billing-cycle /* monthly/annually */
|
|
92
|
+
.plan-features li, .feature-list li
|
|
93
|
+
.plan-cta, .pricing-button
|
|
94
|
+
[class*="popular"], [class*="recommended"], [class*="featured"] /* highlighted plan */
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Job Listings
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
/* Job board patterns */
|
|
101
|
+
.job-listing, .job-card, .job-posting, [itemtype*="JobPosting"]
|
|
102
|
+
.job-title, [itemprop="title"]
|
|
103
|
+
.company-name, [itemprop="hiringOrganization"]
|
|
104
|
+
.job-location, [itemprop="jobLocation"]
|
|
105
|
+
.job-salary, [itemprop="baseSalary"]
|
|
106
|
+
.job-type, .employment-type
|
|
107
|
+
.job-date, [itemprop="datePosted"]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Events
|
|
111
|
+
|
|
112
|
+
```css
|
|
113
|
+
/* Event listing patterns */
|
|
114
|
+
.event-card, .event-item, [itemtype*="Event"]
|
|
115
|
+
.event-title, [itemprop="name"]
|
|
116
|
+
.event-date, [itemprop="startDate"], time[datetime]
|
|
117
|
+
.event-location, [itemprop="location"]
|
|
118
|
+
.event-description, [itemprop="description"]
|
|
119
|
+
.event-speaker, .speaker-name
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Navigation / Pagination
|
|
123
|
+
|
|
124
|
+
```css
|
|
125
|
+
/* Pagination controls */
|
|
126
|
+
.pagination, .pager, nav[aria-label*="pagination"]
|
|
127
|
+
.pagination .next, a[rel="next"]
|
|
128
|
+
.pagination .prev, a[rel="prev"]
|
|
129
|
+
.page-numbers, .page-link
|
|
130
|
+
button[data-page], a[data-page]
|
|
131
|
+
.load-more, button.show-more
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Articles / Blog Posts
|
|
135
|
+
|
|
136
|
+
```css
|
|
137
|
+
/* Article content */
|
|
138
|
+
article, .post, .entry, .article-content
|
|
139
|
+
article h1, .post-title, .entry-title
|
|
140
|
+
.author, .byline, [rel="author"]
|
|
141
|
+
time, .date, .published, .post-date
|
|
142
|
+
.post-content, .entry-content, .article-body
|
|
143
|
+
.tags a, .categories a, .post-tags a
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## JavaScript Extraction Snippets
|
|
149
|
+
|
|
150
|
+
### Generic Table Extractor
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
function extractTable(selector) {
|
|
154
|
+
const table = document.querySelector(selector || 'table');
|
|
155
|
+
if (!table) return { error: 'No table found' };
|
|
156
|
+
|
|
157
|
+
const headers = Array.from(
|
|
158
|
+
table.querySelectorAll('thead th, tr:first-child th, tr:first-child td')
|
|
159
|
+
).map(el => el.textContent.trim());
|
|
160
|
+
|
|
161
|
+
const rows = Array.from(table.querySelectorAll('tbody tr, tr:not(:first-child)'))
|
|
162
|
+
.map(tr => {
|
|
163
|
+
const cells = Array.from(tr.querySelectorAll('td'))
|
|
164
|
+
.map(td => td.textContent.trim());
|
|
165
|
+
return cells.length > 0 ? cells : null;
|
|
166
|
+
})
|
|
167
|
+
.filter(Boolean);
|
|
168
|
+
|
|
169
|
+
return { headers, rows, rowCount: rows.length };
|
|
170
|
+
}
|
|
171
|
+
JSON.stringify(extractTable());
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Multi-Table Extractor
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
function extractAllTables() {
|
|
178
|
+
const tables = document.querySelectorAll('table');
|
|
179
|
+
return Array.from(tables).map((table, idx) => {
|
|
180
|
+
const caption = table.querySelector('caption')?.textContent?.trim()
|
|
181
|
+
|| table.getAttribute('aria-label') || `Table ${idx + 1}`;
|
|
182
|
+
const headers = Array.from(
|
|
183
|
+
table.querySelectorAll('thead th, tr:first-child th')
|
|
184
|
+
).map(el => el.textContent.trim());
|
|
185
|
+
const rows = Array.from(table.querySelectorAll('tbody tr'))
|
|
186
|
+
.map(tr => Array.from(tr.querySelectorAll('td')).map(td => td.textContent.trim()))
|
|
187
|
+
.filter(r => r.length > 0);
|
|
188
|
+
return { caption, headers, rows, rowCount: rows.length };
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
JSON.stringify(extractAllTables());
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Generic List Extractor
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
function extractList(containerSelector, itemSelector, fieldMap) {
|
|
198
|
+
// fieldMap: { fieldName: { selector: 'CSS', attr: 'href'|'src'|null } }
|
|
199
|
+
const container = document.querySelector(containerSelector);
|
|
200
|
+
if (!container) return { error: 'Container not found' };
|
|
201
|
+
|
|
202
|
+
const items = Array.from(container.querySelectorAll(itemSelector));
|
|
203
|
+
const data = items.map(item => {
|
|
204
|
+
const record = {};
|
|
205
|
+
for (const [key, config] of Object.entries(fieldMap)) {
|
|
206
|
+
const sel = typeof config === 'string' ? config : config.selector;
|
|
207
|
+
const attr = typeof config === 'object' ? config.attr : null;
|
|
208
|
+
const el = item.querySelector(sel);
|
|
209
|
+
if (!el) { record[key] = null; continue; }
|
|
210
|
+
record[key] = attr ? el.getAttribute(attr) : el.textContent.trim();
|
|
211
|
+
}
|
|
212
|
+
return record;
|
|
213
|
+
});
|
|
214
|
+
return { data, itemCount: data.length };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Example usage:
|
|
218
|
+
JSON.stringify(extractList('.results', '.result-item', {
|
|
219
|
+
title: '.result-title',
|
|
220
|
+
description: '.result-snippet',
|
|
221
|
+
url: { selector: '.result-title a', attr: 'href' },
|
|
222
|
+
date: '.result-date'
|
|
223
|
+
}));
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### JSON-LD Structured Data Extractor
|
|
227
|
+
|
|
228
|
+
Many pages embed structured data that's easier to parse than DOM:
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
function extractJsonLd(targetType) {
|
|
232
|
+
const scripts = document.querySelectorAll('script[type="application/ld+json"]');
|
|
233
|
+
const allData = Array.from(scripts).map(s => {
|
|
234
|
+
try { return JSON.parse(s.textContent); } catch { return null; }
|
|
235
|
+
}).filter(Boolean);
|
|
236
|
+
|
|
237
|
+
// Flatten @graph arrays
|
|
238
|
+
const flat = allData.flatMap(d => d['@graph'] || [d]);
|
|
239
|
+
|
|
240
|
+
if (targetType) {
|
|
241
|
+
return flat.filter(d =>
|
|
242
|
+
d['@type'] === targetType ||
|
|
243
|
+
(Array.isArray(d['@type']) && d['@type'].includes(targetType))
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
return flat;
|
|
247
|
+
}
|
|
248
|
+
// Extract products: extractJsonLd('Product')
|
|
249
|
+
// Extract articles: extractJsonLd('Article')
|
|
250
|
+
// Extract all: extractJsonLd()
|
|
251
|
+
JSON.stringify(extractJsonLd());
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Common JSON-LD types and their useful fields:
|
|
255
|
+
- `Product`: name, offers.price, offers.priceCurrency, aggregateRating, brand.name
|
|
256
|
+
- `Article`: headline, author.name, datePublished, description, wordCount
|
|
257
|
+
- `Organization`: name, address, telephone, email, url
|
|
258
|
+
- `BreadcrumbList`: itemListElement[].name (navigation path)
|
|
259
|
+
- `FAQPage`: mainEntity[].name (question), mainEntity[].acceptedAnswer.text
|
|
260
|
+
- `JobPosting`: title, hiringOrganization.name, jobLocation, baseSalary
|
|
261
|
+
- `Event`: name, startDate, endDate, location, performer
|
|
262
|
+
|
|
263
|
+
### OpenGraph / Meta Tag Extractor
|
|
264
|
+
|
|
265
|
+
```javascript
|
|
266
|
+
function extractMeta() {
|
|
267
|
+
const meta = {};
|
|
268
|
+
document.querySelectorAll('meta[property^="og:"], meta[name^="twitter:"]')
|
|
269
|
+
.forEach(el => {
|
|
270
|
+
const key = el.getAttribute('property') || el.getAttribute('name');
|
|
271
|
+
meta[key] = el.getAttribute('content');
|
|
272
|
+
});
|
|
273
|
+
meta.title = document.title;
|
|
274
|
+
meta.description = document.querySelector('meta[name="description"]')
|
|
275
|
+
?.getAttribute('content');
|
|
276
|
+
meta.canonical = document.querySelector('link[rel="canonical"]')
|
|
277
|
+
?.getAttribute('href');
|
|
278
|
+
return meta;
|
|
279
|
+
}
|
|
280
|
+
JSON.stringify(extractMeta());
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Pricing Plan Extractor
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
function extractPricingPlans() {
|
|
287
|
+
const cards = document.querySelectorAll(
|
|
288
|
+
'.pricing-card, .plan-card, .pricing-tier, [class*="pricing"] [class*="card"]'
|
|
289
|
+
);
|
|
290
|
+
return Array.from(cards).map(card => ({
|
|
291
|
+
name: card.querySelector('[class*="name"], [class*="title"], h2, h3')
|
|
292
|
+
?.textContent?.trim() || null,
|
|
293
|
+
price: card.querySelector('[class*="price"], [class*="amount"]')
|
|
294
|
+
?.textContent?.trim() || null,
|
|
295
|
+
period: card.querySelector('[class*="period"], [class*="billing"]')
|
|
296
|
+
?.textContent?.trim() || null,
|
|
297
|
+
features: Array.from(card.querySelectorAll('[class*="feature"] li, ul li'))
|
|
298
|
+
.map(li => li.textContent.trim()),
|
|
299
|
+
highlighted: card.matches('[class*="popular"], [class*="recommended"], [class*="featured"]'),
|
|
300
|
+
ctaText: card.querySelector('a, button')?.textContent?.trim() || null,
|
|
301
|
+
ctaUrl: card.querySelector('a')?.href || null,
|
|
302
|
+
}));
|
|
303
|
+
}
|
|
304
|
+
JSON.stringify(extractPricingPlans());
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### FAQ Extractor
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
function extractFAQ() {
|
|
311
|
+
// Try JSON-LD first
|
|
312
|
+
const ldFaq = extractJsonLd('FAQPage');
|
|
313
|
+
if (ldFaq.length > 0 && ldFaq[0].mainEntity) {
|
|
314
|
+
return ldFaq[0].mainEntity.map(q => ({
|
|
315
|
+
question: q.name,
|
|
316
|
+
answer: q.acceptedAnswer?.text || null
|
|
317
|
+
}));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Try <details>/<summary> pattern
|
|
321
|
+
const details = document.querySelectorAll('details');
|
|
322
|
+
if (details.length > 0) {
|
|
323
|
+
return Array.from(details).map(d => ({
|
|
324
|
+
question: d.querySelector('summary')?.textContent?.trim() || null,
|
|
325
|
+
answer: Array.from(d.children).filter(c => c.tagName !== 'SUMMARY')
|
|
326
|
+
.map(c => c.textContent.trim()).join(' ')
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Try accordion pattern
|
|
331
|
+
const items = document.querySelectorAll(
|
|
332
|
+
'.faq-item, .accordion-item, [class*="faq"] [class*="item"]'
|
|
333
|
+
);
|
|
334
|
+
return Array.from(items).map(item => ({
|
|
335
|
+
question: item.querySelector(
|
|
336
|
+
'[class*="question"], [class*="header"], [class*="title"], h3, h4'
|
|
337
|
+
)?.textContent?.trim() || null,
|
|
338
|
+
answer: item.querySelector(
|
|
339
|
+
'[class*="answer"], [class*="body"], [class*="content"], p'
|
|
340
|
+
)?.textContent?.trim() || null
|
|
341
|
+
}));
|
|
342
|
+
}
|
|
343
|
+
JSON.stringify(extractFAQ());
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Link Extractor
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
function extractLinks(scope) {
|
|
350
|
+
const container = scope ? document.querySelector(scope) : document;
|
|
351
|
+
const links = Array.from(container.querySelectorAll('a[href]'))
|
|
352
|
+
.map(a => ({
|
|
353
|
+
text: a.textContent.trim(),
|
|
354
|
+
href: a.href,
|
|
355
|
+
title: a.title || null
|
|
356
|
+
}))
|
|
357
|
+
.filter(l => l.text && l.href && !l.href.startsWith('javascript:'));
|
|
358
|
+
return { links, count: links.length };
|
|
359
|
+
}
|
|
360
|
+
JSON.stringify(extractLinks());
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Image Extractor
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
function extractImages(scope) {
|
|
367
|
+
const container = scope ? document.querySelector(scope) : document;
|
|
368
|
+
const images = Array.from(container.querySelectorAll('img'))
|
|
369
|
+
.map(img => ({
|
|
370
|
+
src: img.src,
|
|
371
|
+
alt: img.alt || null,
|
|
372
|
+
width: img.naturalWidth,
|
|
373
|
+
height: img.naturalHeight
|
|
374
|
+
}))
|
|
375
|
+
.filter(i => i.src && !i.src.includes('data:image/gif'));
|
|
376
|
+
return { images, count: images.length };
|
|
377
|
+
}
|
|
378
|
+
JSON.stringify(extractImages());
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Scroll-and-Collect Pattern
|
|
382
|
+
|
|
383
|
+
For pages with lazy-loaded content, use this pattern with Browser automation:
|
|
384
|
+
|
|
385
|
+
```javascript
|
|
386
|
+
// Count items before scroll
|
|
387
|
+
function countItems(selector) {
|
|
388
|
+
return document.querySelectorAll(selector).length;
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Then in the workflow:
|
|
393
|
+
1. `javascript_tool`: `countItems('.item')` -> get initial count
|
|
394
|
+
2. `computer(action="scroll", scroll_direction="down")`
|
|
395
|
+
3. `computer(action="wait", duration=2)`
|
|
396
|
+
4. `javascript_tool`: `countItems('.item')` -> get new count
|
|
397
|
+
5. If new count > old count, repeat from step 2
|
|
398
|
+
6. If count unchanged after 2 scrolls, all items loaded
|
|
399
|
+
7. Extract all items at once
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Domain-Specific Tips
|
|
404
|
+
|
|
405
|
+
### E-Commerce Sites
|
|
406
|
+
- Check for JSON-LD `Product` schema first - often has cleaner data than DOM
|
|
407
|
+
- Prices may have hidden original/sale price elements
|
|
408
|
+
- Availability often encoded in data attributes (`data-available="true"`)
|
|
409
|
+
- Product variants (size, color) may require click interactions
|
|
410
|
+
- Review data often loaded lazily - scroll to reviews section first
|
|
411
|
+
- Many sites have internal APIs at `/api/products` - check Network tab
|
|
412
|
+
|
|
413
|
+
### Wikipedia
|
|
414
|
+
- Tables use class `.wikitable` - always prefer this selector
|
|
415
|
+
- Infoboxes use class `.infobox`
|
|
416
|
+
- References in `<sup class="reference">` - exclude from text extraction
|
|
417
|
+
- Table cells may contain complex nested HTML - use `.textContent.trim()`
|
|
418
|
+
- Sortable tables have class `.sortable` with sort buttons in headers
|
|
419
|
+
|
|
420
|
+
### News Sites
|
|
421
|
+
- Article body often in `<article>` or `[itemprop="articleBody"]`
|
|
422
|
+
- Paywall indicators: `.paywall`, `.subscribe-wall`, truncated with "Read more"
|
|
423
|
+
- Publication date in `<time>` element or `[itemprop="datePublished"]`
|
|
424
|
+
- Author in `[itemprop="author"]` or `.byline`
|
|
425
|
+
- JSON-LD `NewsArticle` often has complete metadata
|
|
426
|
+
|
|
427
|
+
### Government / Data Portals
|
|
428
|
+
- Often use HTML tables without JavaScript
|
|
429
|
+
- May have download links for CSV/Excel - check for `.csv`, `.xlsx` links
|
|
430
|
+
- Data dictionaries may be on separate pages
|
|
431
|
+
- Look for API endpoints in page source (`/api/`, `.json` links)
|
|
432
|
+
- CORS may block direct API access; use Bash curl instead
|
|
433
|
+
|
|
434
|
+
### Social Media (Public Profiles)
|
|
435
|
+
- Content is almost always JS-rendered - use Browser automation
|
|
436
|
+
- Rate limiting is aggressive - keep requests minimal
|
|
437
|
+
- Infinite scroll is the norm - set clear item limits
|
|
438
|
+
- Structure changes frequently - prefer text extraction over selectors
|
|
439
|
+
|
|
440
|
+
### SaaS Pricing Pages
|
|
441
|
+
- Pricing often changes dynamically (monthly vs annual toggle)
|
|
442
|
+
- May need to click "Annual" toggle to see annual prices
|
|
443
|
+
- Feature comparison tables often use checkmarks (Unicode or SVG)
|
|
444
|
+
- Check for hidden elements toggled by billing period selector
|
|
445
|
+
|
|
446
|
+
### Job Boards
|
|
447
|
+
- Most use JSON-LD `JobPosting` schema
|
|
448
|
+
- Salary ranges often hidden behind "View salary" buttons
|
|
449
|
+
- Location may include remote/hybrid indicators
|
|
450
|
+
- Filters are URL-parameter based - useful for pagination
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Anti-Patterns to Avoid
|
|
455
|
+
|
|
456
|
+
| Anti-Pattern | Why It Fails | Better Approach |
|
|
457
|
+
|:-------------|:-------------|:----------------|
|
|
458
|
+
| Selectors with generated hashes (`.css-1a2b3c`) | Change on every deploy | Use semantic selectors, ARIA roles, data attributes |
|
|
459
|
+
| Deeply nested paths (`div > div > div > span`) | Fragile on layout changes | Use closest meaningful class or attribute |
|
|
460
|
+
| Index-based (`:nth-child(3)`) for dynamic lists | Order may change | Use content-based identification |
|
|
461
|
+
| Selecting by inline styles | Presentation, not semantics | Use classes, IDs, or data attributes |
|
|
462
|
+
| Hardcoded wait times for JS content | Too short or too long | Check for content presence in a loop |
|
|
463
|
+
| Single selector for variant pages | Different pages differ | Test selector on multiple pages first |
|
|
464
|
+
|
|
465
|
+
## Robust Selector Priority
|
|
466
|
+
|
|
467
|
+
Prefer selectors in this order (most stable to least):
|
|
468
|
+
|
|
469
|
+
1. `[data-testid="..."]`, `[data-id="..."]` - test/data attributes
|
|
470
|
+
2. `#unique-id` - unique IDs
|
|
471
|
+
3. `[role="..."]`, `[aria-label="..."]` - ARIA attributes
|
|
472
|
+
4. `[itemprop="..."]`, `[itemtype="..."]` - microdata / schema.org
|
|
473
|
+
5. `.semantic-class` - meaningful class names
|
|
474
|
+
6. `tag.class` - element type + class
|
|
475
|
+
7. Structural selectors - last resort
|