opencode-skills-collection 3.0.37 → 3.0.38
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/bundled-skills/.antigravity-install-manifest.json +13 -1
- package/bundled-skills/2slides-ppt-generator/SKILL.md +786 -0
- package/bundled-skills/2slides-ppt-generator/references/api-reference.md +499 -0
- package/bundled-skills/2slides-ppt-generator/references/mcp-integration.md +282 -0
- package/bundled-skills/2slides-ppt-generator/references/pricing.md +195 -0
- package/bundled-skills/2slides-ppt-generator/scripts/api_constants.py +87 -0
- package/bundled-skills/2slides-ppt-generator/scripts/create_pdf_slides.py +159 -0
- package/bundled-skills/2slides-ppt-generator/scripts/download_slides_pages_voices.py +157 -0
- package/bundled-skills/2slides-ppt-generator/scripts/generate_narration.py +197 -0
- package/bundled-skills/2slides-ppt-generator/scripts/generate_slides.py +247 -0
- package/bundled-skills/2slides-ppt-generator/scripts/get_job_status.py +106 -0
- package/bundled-skills/2slides-ppt-generator/scripts/search_themes.py +137 -0
- package/bundled-skills/anti-sycophancy/README.md +86 -0
- package/bundled-skills/anti-sycophancy/SKILL.md +40 -0
- package/bundled-skills/antigravity-agent-manager/SKILL.md +112 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/sources/sources.md +1 -0
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/event-staffing-compliance/SKILL.md +91 -0
- package/bundled-skills/event-staffing-ordering/SKILL.md +119 -0
- package/bundled-skills/examprep-ai/SKILL.md +446 -0
- package/bundled-skills/hasdata/SKILL.md +107 -0
- package/bundled-skills/hasdata/references/code-recipes.md +150 -0
- package/bundled-skills/hasdata/references/ecommerce.md +116 -0
- package/bundled-skills/hasdata/references/jobs.md +111 -0
- package/bundled-skills/hasdata/references/local-business.md +145 -0
- package/bundled-skills/hasdata/references/real-estate.md +84 -0
- package/bundled-skills/hasdata/references/scraper-jobs.md +252 -0
- package/bundled-skills/hasdata/references/search.md +154 -0
- package/bundled-skills/hasdata/references/travel.md +202 -0
- package/bundled-skills/hasdata/references/web-scraping.md +159 -0
- package/bundled-skills/hasdata/references/youtube.md +186 -0
- package/bundled-skills/hasdata-cli/SKILL.md +169 -0
- package/bundled-skills/hasdata-cli/references/all-commands.md +107 -0
- package/bundled-skills/hasdata-cli/references/ecommerce.md +106 -0
- package/bundled-skills/hasdata-cli/references/enrichment.md +227 -0
- package/bundled-skills/hasdata-cli/references/jobs.md +84 -0
- package/bundled-skills/hasdata-cli/references/local-business.md +123 -0
- package/bundled-skills/hasdata-cli/references/real-estate.md +126 -0
- package/bundled-skills/hasdata-cli/references/search.md +122 -0
- package/bundled-skills/hasdata-cli/references/travel.md +102 -0
- package/bundled-skills/hasdata-cli/references/web-scraping.md +181 -0
- package/bundled-skills/hasdata-cli/references/youtube.md +145 -0
- package/bundled-skills/linkedin-content-generator/SKILL.md +492 -0
- package/bundled-skills/linkedin-content-generator/scripts/generate_calendar.py +82 -0
- package/bundled-skills/linkedin-content-generator/scripts/generate_carousel.py +69 -0
- package/bundled-skills/linkedin-content-generator/scripts/generate_newsletter.py +64 -0
- package/bundled-skills/linkedin-content-generator/scripts/generate_post.py +77 -0
- package/bundled-skills/linkedin-content-generator/scripts/memory.md +49 -0
- package/bundled-skills/linkedin-content-generator/scripts/memory_manager.py +134 -0
- package/bundled-skills/linkedin-content-generator/scripts/utils.py +96 -0
- package/bundled-skills/permission-manager/README.md +22 -0
- package/bundled-skills/permission-manager/SKILL.md +54 -0
- package/bundled-skills/skill-suggester/README.md +14 -0
- package/bundled-skills/skill-suggester/SKILL.md +69 -0
- package/bundled-skills/smart-git-automation/README.md +31 -0
- package/bundled-skills/smart-git-automation/SKILL.md +96 -0
- package/bundled-skills/vercel-optimize/lib/cost-coverage.mjs +3 -1
- package/bundled-skills/vercel-optimize/lib/render-report.mjs +2 -2
- package/bundled-skills/vercel-optimize/lib/util.mjs +7 -0
- package/bundled-skills/vercel-optimize/lib/verify-claim.mjs +2 -7
- package/bundled-skills/vercel-optimize/lib/workspace-resolver.mjs +2 -1
- package/package.json +1 -1
- package/skills_index.json +268 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# E-commerce reference
|
|
2
|
+
|
|
3
|
+
Subcommands: `amazon-search`, `amazon-product`, `amazon-seller`, `amazon-seller-products`, `shopify-products`, `shopify-collections`. 5 credits each.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## amazon-search
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
hasdata amazon-search --q "wireless earbuds" [--domain amazon.com] --raw | jq '.results[]'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- `--q TEXT` (required)
|
|
14
|
+
- `--domain amazon.com|amazon.co.uk|amazon.de|amazon.in|amazon.co.jp|amazon.fr|amazon.it|amazon.es|amazon.com.br|amazon.com.mx|amazon.ca|amazon.com.au`
|
|
15
|
+
- `--page N` — pagination
|
|
16
|
+
- `--sort featured|price-asc-rank|price-desc-rank|review-rank|date-desc-rank`
|
|
17
|
+
- `--node ID` — restrict to category node
|
|
18
|
+
- `--customer-reviews` — only items with reviews
|
|
19
|
+
|
|
20
|
+
Per-result fields: `asin`, `title`, `price`, `link`, `image`, `rating`, `reviews_count`, `prime`.
|
|
21
|
+
|
|
22
|
+
## amazon-product
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
hasdata amazon-product --asin B08N5WRWNW [--domain amazon.com] --raw | jq .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- `--asin ASIN` (required)
|
|
29
|
+
- `--domain` as above
|
|
30
|
+
- `--include-reviews` — include first page of reviews
|
|
31
|
+
- `--include-html` — return raw HTML alongside parsed data
|
|
32
|
+
|
|
33
|
+
Returns: title, price, availability, features, descriptions, variants, images, ratings, top reviews, A+ content.
|
|
34
|
+
|
|
35
|
+
## amazon-seller
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
hasdata amazon-seller --seller-id A1234567890ABC [--domain amazon.com] --raw
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Seller profile: name, ratings, review count, returns policy, shipping policy, "About" content.
|
|
42
|
+
|
|
43
|
+
## amazon-seller-products
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
hasdata amazon-seller-products --seller-id A1234567890ABC [--domain amazon.com] [--page 1] --raw
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
List of products from a specific seller — useful for competitor analysis or storefront crawling.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## shopify-products
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
hasdata shopify-products --url "https://store.example.com" [--page 1] --raw | jq '.products[]'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Works on any Shopify store (it queries the public `/products.json`-style endpoint). Returns title, vendor, product_type, variants[] (with prices, SKUs, stock), images, tags, handle.
|
|
60
|
+
|
|
61
|
+
## shopify-collections
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
hasdata shopify-collections --url "https://store.example.com" --raw | jq '.collections[]'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
For drilling into a specific collection, append `/collections/SLUG` to the URL or use the collection handle returned here.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Non-obvious use cases
|
|
72
|
+
|
|
73
|
+
- **Cross-marketplace price arbitrage** — same `--asin` across `--domain amazon.com|amazon.co.uk|amazon.de` shows currency-normalized regional differences; useful for grey-market resellers and buyers shipping internationally.
|
|
74
|
+
- **"Is this product still available?"** — `amazon-product --asin X --raw | jq '.availability'`. Avoids hallucinating an answer based on stale training data.
|
|
75
|
+
- **Variant matrix dump** — `amazon-product --asin X --raw | jq '.variants[] | {asin, color, size, price}'` returns the full color/size/etc. lattice with current prices.
|
|
76
|
+
- **Counterfeit-listing detection** — `amazon-search --q "BRAND PRODUCT" --raw` then check `.results[].seller_name` for non-authorized sellers; pivot to `amazon-seller` to inspect their other listings.
|
|
77
|
+
- **Storefront catalog** — `amazon-seller-products --seller-id X --page 1..N` paginates a seller's full catalog; useful for competitor analysis or due diligence on a vendor.
|
|
78
|
+
- **"What were the bestsellers in category X?"** — `amazon-search --q "CATEGORY KEYWORD" --sort featured` returns Amazon's own ranking (`--sort review-rank` for review-weighted).
|
|
79
|
+
- **Lead enrichment for a Shopify store** — `shopify-products --url store.example.com --raw` exposes vendor names, tags, product types, SKUs — useful for competitor product-line audits.
|
|
80
|
+
- **Stock check** — `shopify-products` returns each variant's `available` boolean; can power "notify me when X is back" without scraping the cart UI.
|
|
81
|
+
- **Price-drop monitoring** — schedule `amazon-product --asin X` daily; persist `.price` to a file; alert when delta > N%.
|
|
82
|
+
- **A/B-test detection** — same `--asin` from two different `--proxy-country` settings (via web-scraping fallback if amazon-product doesn't support it) sometimes shows different price/title due to A/B tests.
|
|
83
|
+
- **Gift-card / coupon discovery** — `google-shopping --q "PRODUCT"` often surfaces resellers offering rebates Amazon doesn't show.
|
|
84
|
+
- **Product-image extraction for a moodboard** — `amazon-product --asin X --raw | jq -r '.images[]'` returns CDN URLs you can download separately.
|
|
85
|
+
- **Compare reviews summary** — `amazon-product --asin X --include-reviews --raw | jq '.reviews[] | {rating, title, body}'` gives a quick sentiment sample without scraping the review page.
|
|
86
|
+
- **Build a Shopify product feed for ads** — `shopify-products --url X --raw | jq -c '.products[] | {id, title, price: .variants[0].price, url: ("https://" + $store + "/products/" + .handle)}'`.
|
|
87
|
+
|
|
88
|
+
## Common patterns
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Price tracking — pull current price for a known ASIN
|
|
92
|
+
hasdata amazon-product --asin "$ASIN" --raw | jq '.price'
|
|
93
|
+
|
|
94
|
+
# Product discovery → details fan-out
|
|
95
|
+
hasdata amazon-search --q "$Q" --raw \
|
|
96
|
+
| jq -r '.results[].asin' \
|
|
97
|
+
| head -5 \
|
|
98
|
+
| xargs -I{} hasdata amazon-product --asin {} --raw
|
|
99
|
+
|
|
100
|
+
# Compare across marketplaces
|
|
101
|
+
for d in amazon.com amazon.co.uk amazon.de; do
|
|
102
|
+
echo "=== $d ==="
|
|
103
|
+
hasdata amazon-product --asin "$ASIN" --domain "$d" --raw \
|
|
104
|
+
| jq '{currency: .currency, price: .price}'
|
|
105
|
+
done
|
|
106
|
+
```
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Data enrichment
|
|
2
|
+
|
|
3
|
+
Enriching a company, domain, or authorized contact list with public data. Use these workflows only for permitted business research or user-authorized contact enrichment, and respect site terms, robots/access controls, privacy law, opt-out obligations, and rate limits.
|
|
4
|
+
|
|
5
|
+
## SERP first. Web-scraping is the last resort.
|
|
6
|
+
|
|
7
|
+
`google-serp` is your primary enrichment tool. Reasons:
|
|
8
|
+
|
|
9
|
+
- **Google has already extracted the structured fields you want.** `.knowledge_graph` carries HQ, founder, founded year, parent company, employees, industry. `.organic_results[]` titles and snippets carry person → role → employer mappings (LinkedIn titles are literally `Name — Role at Company`). `.local_results[]` carry phone/address/hours.
|
|
10
|
+
- **It avoids unnecessary direct access.** Many target sites gate, rate-limit, or restrict scraping. Google's snippets can answer public, high-level questions without rendering the target page.
|
|
11
|
+
- **It's a broad public index.** Quoted queries (`--q '"info@example.com"'`, `--q '"+1 555 123 4567"'`, `--q '"Acme Corp"'`) can find publicly indexed business contact or company references.
|
|
12
|
+
|
|
13
|
+
Use `google-serp` (or `google-news` for recency, `google-maps` for places, `google-shopping` for products) **first**. Only fall through to `web-scraping` when:
|
|
14
|
+
- A specific field you need isn't in any SERP snippet, AND
|
|
15
|
+
- The target page renders that field server-side or via JS that the scraper can handle, AND
|
|
16
|
+
- The user explicitly needs it and has authority to access it (don't fan out to N web-scraping calls when SERP would have answered N - 0 of them).
|
|
17
|
+
|
|
18
|
+
The patterns below show the full chain so you understand when to escalate. Most rows in a real CSV stop after step 1 or 2.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Person enrichment
|
|
23
|
+
|
|
24
|
+
### Step 1 — SERP for role, employer, LinkedIn URL
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
hasdata google-serp --q '"Jane Doe" linkedin' --num 5 --raw \
|
|
28
|
+
| jq -c '.organic_results[] | select(.link | contains("linkedin.com/in/")) |
|
|
29
|
+
{title, snippet, link}'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The result usually looks like:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"title": "Jane Doe — Senior Engineer at Acme Corp | LinkedIn",
|
|
37
|
+
"snippet": "San Francisco, CA · 500+ connections · Engineering @ Acme. Previously...",
|
|
38
|
+
"link": "https://www.linkedin.com/in/janedoe"
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
You now have role, employer, location, LinkedIn URL, and a connection-count hint — without scraping anything. **Stop here unless a specific extra field is required.**
|
|
43
|
+
|
|
44
|
+
### Step 2 — Refine with targeted SERP queries
|
|
45
|
+
|
|
46
|
+
If step 1 didn't carry what you need, ask Google more specifically:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Disambiguate by company
|
|
50
|
+
hasdata google-serp --q '"Jane Doe" "Acme Corp"' --num 10 --raw \
|
|
51
|
+
| jq -c '.organic_results[] | {title, snippet, link}'
|
|
52
|
+
|
|
53
|
+
# Other social profiles
|
|
54
|
+
hasdata google-serp --q '"Jane Doe" site:twitter.com OR site:x.com' --num 3 --raw
|
|
55
|
+
hasdata google-serp --q '"Jane Doe" site:github.com' --num 3 --raw
|
|
56
|
+
|
|
57
|
+
# Past employers / bio paragraphs
|
|
58
|
+
hasdata google-serp --q '"Jane Doe" bio OR background OR experience' --num 5 --raw \
|
|
59
|
+
| jq -r '.organic_results[].snippet'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Step 3 — Web-scraping (only if SERP came up short)
|
|
63
|
+
|
|
64
|
+
When SERP snippets truncated the field you need, or the user explicitly wants full profile content, first confirm the profile is public or the user has authorization to access it:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
hasdata web-scraping --url "https://www.linkedin.com/in/janedoe" \
|
|
68
|
+
--output-format markdown --no-screenshot --no-block-resources \
|
|
69
|
+
--raw | jq -r .markdown
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or for structured fields, AI extraction:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
hasdata web-scraping --url "https://www.linkedin.com/in/janedoe" \
|
|
76
|
+
--ai-extract-rules-json '{
|
|
77
|
+
"headline": {"type": "string"},
|
|
78
|
+
"location": {"type": "string"},
|
|
79
|
+
"company": {"type": "string"},
|
|
80
|
+
"role": {"type": "string"},
|
|
81
|
+
"followers": {"type": "number"},
|
|
82
|
+
"experience": {"type": "list", "output": {
|
|
83
|
+
"company": {"type": "string"},
|
|
84
|
+
"role": {"type": "string"},
|
|
85
|
+
"duration": {"type": "string"}
|
|
86
|
+
}}
|
|
87
|
+
}' --raw | jq .
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
LinkedIn sometimes blocks the public preview; if it does, fall back to step 2 (combining SERP snippets) — it's almost always enough.
|
|
91
|
+
|
|
92
|
+
### Email lookup
|
|
93
|
+
|
|
94
|
+
Triangulate, don't promise. Use this only for business contact discovery, user-authorized enrichment, or another legitimate purpose. SERP first, scraping last; never present a guessed personal email as verified.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 1. Has Google already indexed the email anywhere?
|
|
98
|
+
hasdata google-serp --q '"jane.doe@acme.com"' --num 10 --raw \
|
|
99
|
+
| jq -c '.organic_results[] | {title, snippet, link}'
|
|
100
|
+
|
|
101
|
+
# 2. What email format does the company use? Look for any indexed @company.com address.
|
|
102
|
+
hasdata google-serp --q 'site:acme.com "@acme.com"' --num 10 --raw \
|
|
103
|
+
| jq -r '.organic_results[].snippet' \
|
|
104
|
+
| grep -oE '[A-Za-z0-9._-]+@acme\.com' | sort -u
|
|
105
|
+
|
|
106
|
+
# 3. Pattern-guess + SERP-verify
|
|
107
|
+
for guess in "jane.doe" "jdoe" "jane" "j.doe" "janed"; do
|
|
108
|
+
count=$(hasdata google-serp --q "\"$guess@acme.com\"" --num 1 --raw \
|
|
109
|
+
| jq -r '.organic_results | length')
|
|
110
|
+
[ "$count" -gt 0 ] && echo "$guess@acme.com (appears in SERP)"
|
|
111
|
+
done
|
|
112
|
+
|
|
113
|
+
# 4. Last resort — scrape the company's public contact / about / team pages for emails
|
|
114
|
+
hasdata web-scraping --url "https://acme.com/about" --extract-emails --raw \
|
|
115
|
+
| jq -r '.emails // [] | .[]'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Always tell the user when an email is a pattern-guess vs. confirmed via SERP/scrape, and avoid collecting personal contact data when the user lacks authorization.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Company enrichment
|
|
123
|
+
|
|
124
|
+
### Step 1 — SERP knowledge_graph
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
hasdata google-serp --q "Acme Corp" --num 5 --raw | jq '.knowledge_graph // {}'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`.knowledge_graph` typically contains: founder, founded (year), headquarters, parent_organization, ceo, employees (range), revenue, stock_price, industry, products. **For the majority of company enrichment requests, this single call is the entire answer.**
|
|
131
|
+
|
|
132
|
+
### Step 2 — Targeted SERP for specific fields
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Headquarters
|
|
136
|
+
hasdata google-serp --q '"Acme Corp" headquarters' --num 5 --raw \
|
|
137
|
+
| jq -r '.organic_results[].snippet'
|
|
138
|
+
|
|
139
|
+
# Funding / acquisition signals
|
|
140
|
+
hasdata google-serp --q '"Acme Corp" raises OR acquires OR acquired OR ipo OR funding' --num 10 --raw \
|
|
141
|
+
| jq -c '.organic_results[] | {title, snippet, link}'
|
|
142
|
+
|
|
143
|
+
# Recent news
|
|
144
|
+
hasdata google-news --q "Acme Corp" --gl us --raw \
|
|
145
|
+
| jq -c '.news_results[] | {title, source: .source.name, date, link}'
|
|
146
|
+
|
|
147
|
+
# LinkedIn company page
|
|
148
|
+
hasdata google-serp --q '"Acme Corp" site:linkedin.com/company' --num 3 --raw \
|
|
149
|
+
| jq -c '.organic_results[] | {title, snippet, link}'
|
|
150
|
+
|
|
151
|
+
# Employee profiles in a specific function/region
|
|
152
|
+
hasdata google-serp \
|
|
153
|
+
--q 'site:linkedin.com/in "Acme Corp" engineer' --gl us --num 25 --raw \
|
|
154
|
+
| jq -r '.organic_results[] | "\(.title)\t\(.link)"'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Step 3 — Web-scraping (only when SERP can't fill a specific field)
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Company About page → AI-extract structured fields
|
|
161
|
+
hasdata web-scraping --url "https://acme.com/about" \
|
|
162
|
+
--ai-extract-rules-json '{
|
|
163
|
+
"name": {"type": "string"},
|
|
164
|
+
"founded": {"type": "number"},
|
|
165
|
+
"headquarters": {"type": "string"},
|
|
166
|
+
"employees": {"type": "string"},
|
|
167
|
+
"industry": {"type": "string"},
|
|
168
|
+
"description": {"type": "string"},
|
|
169
|
+
"products": {"type": "list"}
|
|
170
|
+
}' --raw | jq .
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Reach for this only when the user wants something SERP can't provide (e.g. mission statement verbatim, full product taxonomy, leadership team page parsed into rows).
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## CSV row enrichment
|
|
178
|
+
|
|
179
|
+
For a list of N rows, fan out one or two SERP calls per row. Keep web-scraping out of the loop unless a specific row needs it.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Input: people.csv with one column "name"
|
|
183
|
+
while IFS=, read -r name; do
|
|
184
|
+
result=$(hasdata google-serp --q "\"$name\" linkedin" --num 1 --raw)
|
|
185
|
+
linkedin=$(echo "$result" | jq -r '.organic_results[0].link // ""')
|
|
186
|
+
title=$(echo "$result" | jq -r '.organic_results[0].title // ""')
|
|
187
|
+
snippet=$(echo "$result" | jq -r '.organic_results[0].snippet // ""')
|
|
188
|
+
printf '%s\t%s\t%s\t%s\n' "$name" "$title" "$snippet" "$linkedin"
|
|
189
|
+
done < people.csv > enriched.tsv
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
That's it. One SERP call per row, role/employer/LinkedIn extracted from the title and snippet. Add a second SERP call only if a row's first result didn't match (`select(.title | test("\(name)"; "i"))` filtering for confidence).
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Reverse-lookup
|
|
197
|
+
|
|
198
|
+
Always SERP-first with the literal value quoted. Use reverse lookup only for user-authorized investigation, business contact verification, or another legitimate purpose; do not use it for doxxing, stalking, harassment, or collecting private personal data.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Business email → public identity signal
|
|
202
|
+
hasdata google-serp --q '"jane@example.com"' --num 10 --raw \
|
|
203
|
+
| jq -c '.organic_results[] | {title, snippet, link}'
|
|
204
|
+
|
|
205
|
+
# Business phone → owner / business
|
|
206
|
+
hasdata google-serp --q '"+1 555 123 4567"' --num 10 --raw
|
|
207
|
+
# Combine with yelp-search / yellowpages-search if it's a business number.
|
|
208
|
+
|
|
209
|
+
# Domain → company
|
|
210
|
+
hasdata google-serp --q "site:example.com" --num 5 --raw \
|
|
211
|
+
| jq '.organic_results[0].title'
|
|
212
|
+
hasdata google-serp --q "Acme Corp" --num 5 --raw | jq '.knowledge_graph // {}'
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Only scrape the domain (`web-scraping --url "https://example.com"`) when you specifically need the homepage's body text.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Tips for reliable enrichment
|
|
220
|
+
|
|
221
|
+
- **Always quote names and other multi-token strings** — `"Jane Doe"` matches the exact person; `Jane Doe` matches noise.
|
|
222
|
+
- **Use `site:` aggressively** — `site:linkedin.com/in/`, `site:linkedin.com/company/`, `site:github.com`, `site:crunchbase.com`. Google's `site:` is the cheapest way to scope an enrichment search.
|
|
223
|
+
- **Read the `.knowledge_graph`** before doing anything else for a company. If it's populated, you're often done.
|
|
224
|
+
- **AI-extract over CSS selectors** when you do need to scrape — LinkedIn / Crunchbase / About-page markup changes constantly; AI extraction with field names + descriptions survives layout churn.
|
|
225
|
+
- **Cross-source verify** — never enrich from a single source. If LinkedIn's title says "Acme Corp" and a `--q '"Jane Doe" "Acme Corp"'` SERP corroborates with multiple results, confidence is high.
|
|
226
|
+
- **Mark guesses** — pattern-guessed emails, inferred locations, single-source roles should be flagged to the user as unverified.
|
|
227
|
+
- **Respect privacy and authorization** — do not collect or infer personal contact details without a legitimate purpose and user authority.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Jobs reference
|
|
2
|
+
|
|
3
|
+
Subcommands: `indeed-listing`, `indeed-job`, `glassdoor-listing`, `glassdoor-job`. Indeed: 5 credits. Glassdoor: 10 credits.
|
|
4
|
+
|
|
5
|
+
`*-listing` searches by query/location; `*-job` deep-dives a specific posting by URL or ID.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## indeed-listing
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
hasdata indeed-listing \
|
|
13
|
+
--query "backend engineer" --location "Remote" \
|
|
14
|
+
[--days-since-posted 7] [--job-type fulltime|parttime|contract|temporary|internship] \
|
|
15
|
+
[--remote] [--page 1] \
|
|
16
|
+
--raw | jq '.jobs[] | {title, company, location, posted, salary, url}'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Other flags worth knowing:
|
|
20
|
+
- `--salary-min N` / `--salary-max N`
|
|
21
|
+
- `--experience-level entry|mid|senior`
|
|
22
|
+
- `--sort relevance|date`
|
|
23
|
+
- `--country us|gb|ca|de|fr|...`
|
|
24
|
+
|
|
25
|
+
## indeed-job
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
hasdata indeed-job --url "https://www.indeed.com/viewjob?jk=..." --raw | jq .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or `--job-key JK`. Returns full description, company info, benefits, hiring insights, similar jobs.
|
|
32
|
+
|
|
33
|
+
## glassdoor-listing
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
hasdata glassdoor-listing --keyword "data scientist" --location "Boston" --raw \
|
|
37
|
+
| jq '.jobs[] | {title, employer, salary_estimate, rating}'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Glassdoor includes employer ratings and salary estimates per result. Use this when the user cares about employer reputation alongside the role.
|
|
41
|
+
|
|
42
|
+
## glassdoor-job
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
hasdata glassdoor-job --url "https://www.glassdoor.com/Job/jobs.htm?...JV=..." --raw | jq .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Returns full posting plus employer rating breakdown, recent reviews, salary estimate range, interview difficulty.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Non-obvious use cases
|
|
53
|
+
|
|
54
|
+
- **Salary-negotiation research** — `indeed-listing --query ROLE --location CITY` then `jq '[.jobs[].salary | select(.)] | sort_by(.min)'` to build a defensible range before a comp conversation.
|
|
55
|
+
- **"Should I move for this job?"** — same role across 3–5 cities; compare median salaries to local cost of living.
|
|
56
|
+
- **Hiring-pattern intel on a competitor** — `indeed-listing --query "company:NAME"` (or use `glassdoor-listing` filtered by employer) returns recent postings; surfaces what teams are growing, what stack they're on, what locations they're in.
|
|
57
|
+
- **"Are they really hiring or is this a ghost job?"** — `indeed-job --url X --raw | jq '.posted_at'`. Postings older than 60 days that haven't been refreshed are often ghosts.
|
|
58
|
+
- **Stack popularity by region** — `indeed-listing --query "Rust" --location "Berlin"` vs `--location "San Francisco"` to compare absolute postings and salary deltas for a specific tech.
|
|
59
|
+
- **Career-pivot research** — `indeed-listing --query "TARGET ROLE" --raw | jq -r '.jobs[].description'` then summarize the most-required skills with an LLM. Reveals the actual gap, not what bootcamps claim.
|
|
60
|
+
- **Employer reputation deep-dive** — `glassdoor-listing` returns ratings inline; `glassdoor-job` returns recent reviews + interview difficulty. Use before applying or accepting.
|
|
61
|
+
- **Remote-job filter** — `--remote` on `indeed-listing` cuts to fully-remote postings; use `--country gb` etc. to find role markets that are remote-friendly outside the US.
|
|
62
|
+
- **Visa-friendly employer detection** — search `indeed-listing --query "ROLE H1B sponsorship"` or `--query "ROLE relocation"` — listings that mention these are more likely to support visa transfers.
|
|
63
|
+
- **Internship-only filter** — `--job-type internship` on `indeed-listing` for early-career searches.
|
|
64
|
+
- **Salary-band reverse engineering** — Glassdoor's `salary_estimate` is an estimate; cross-check by sampling 5–10 indeed postings for the same role/title in the same city and computing your own median.
|
|
65
|
+
- **"Who's leaving Company X?"** — `glassdoor-listing --keyword "previously at: COMPANY"` is a stretch query but sometimes surfaces postings where ex-employees describe their transition.
|
|
66
|
+
- **Detect layoffs before the news** — sudden surge in `indeed-listing --query "ex-COMPANY"` postings in a region often precedes the announcement.
|
|
67
|
+
- **Negotiation prep — interview difficulty** — `glassdoor-job --url X --raw | jq '.interview_difficulty, .interview_experiences[]'` shows how previous candidates rated the process.
|
|
68
|
+
|
|
69
|
+
## Common patterns
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Salary distribution for a role
|
|
73
|
+
hasdata indeed-listing --query "senior python developer" --location "New York, NY" \
|
|
74
|
+
--raw | jq '[.jobs[].salary | select(. != null)] | unique'
|
|
75
|
+
|
|
76
|
+
# Compare same role on both platforms
|
|
77
|
+
for src in indeed-listing glassdoor-listing; do
|
|
78
|
+
echo "=== $src ==="
|
|
79
|
+
hasdata "$src" --query "platform engineer" --location "SF" --raw \
|
|
80
|
+
| jq '.jobs[:5][] | {title, company: (.company // .employer), location}'
|
|
81
|
+
done
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Start with Indeed for breadth; escalate to Glassdoor when employer ratings or interview-difficulty data are needed.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Local-business / maps reference
|
|
2
|
+
|
|
3
|
+
Subcommands: `google-maps`, `google-maps-place`, `google-maps-reviews`, `google-maps-contributor-reviews`, `google-maps-photos`, `google-maps-posts`, `yelp-search`, `yelp-place`, `yellowpages-search`, `yellowpages-place`. 5 credits each (10 for `google-maps-posts` and YellowPages).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## google-maps
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
hasdata google-maps --q "coffee" --ll "@30.2672,-97.7431,14z" --raw | jq '.local_results[]'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Required: `--q TEXT`. Other useful flags:
|
|
14
|
+
- `--ll "@LAT,LNG,ZOOMz"` — center point + zoom (Google's `ll` parameter)
|
|
15
|
+
- `--gl us|gb|...` — country
|
|
16
|
+
- `--hl en|es|...` — language
|
|
17
|
+
- `--type search|place` — search vs. specific place lookup
|
|
18
|
+
- `--data` / `--cid` / `--fid` — Google identifiers (advanced)
|
|
19
|
+
|
|
20
|
+
Per-result: `title`, `place_id`, `rating`, `reviews`, `address`, `phone`, `website`, `types[]`, `gps_coordinates`.
|
|
21
|
+
|
|
22
|
+
## google-maps-place
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
hasdata google-maps-place --place-id "ChIJ..." --raw | jq .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Single place: full details, hours, popular times, attributes.
|
|
29
|
+
|
|
30
|
+
## google-maps-reviews
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
hasdata google-maps-reviews --place-id "ChIJ..." [--sort newest|highest|lowest] --raw \
|
|
34
|
+
| jq '.reviews[] | {author, rating, date, snippet}'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For pagination, the response includes a `next_page_token` — pass via `--next-page-token`.
|
|
38
|
+
|
|
39
|
+
## google-maps-contributor-reviews
|
|
40
|
+
|
|
41
|
+
Reviews authored by a specific Google contributor (by `--contributor-id`). Useful for local-guide analysis.
|
|
42
|
+
|
|
43
|
+
## google-maps-photos
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
hasdata google-maps-photos --place-id "ChIJ..." --raw
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Returns photo URLs by category (interior, exterior, food, etc.).
|
|
50
|
+
|
|
51
|
+
## google-maps-posts (10 credits)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
hasdata google-maps-posts --place-id "ChIJ..." [--hl en] [--next-page-token TOKEN] --raw \
|
|
55
|
+
| jq '.posts[] | {postedAt, description, cta, postUrl}'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Posts are the business-owner publications shown on a Maps listing: offers, events, holiday hours, announcements. Either `--place-id` **or** `--data-id` is required.
|
|
59
|
+
|
|
60
|
+
Per-post fields (verified live): `postId`, `locationId`, `title`, `description`, `image`, `cta` (object with `label` + `url`), `createdAt` (ISO), `postedAt` (human-readable), `shareUrl`, `postUrl`. Use `pagination.nextPageToken` for older posts.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## yelp-search
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
hasdata yelp-search --query "italian" --location "Brooklyn, NY" [--page 1] --raw \
|
|
68
|
+
| jq '.businesses[] | {name, rating, review_count, price, categories}'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## yelp-place
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
hasdata yelp-place --url "https://www.yelp.com/biz/SLUG" --raw | jq .
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Single business: full details, hours, top reviews, photos, attributes.
|
|
78
|
+
|
|
79
|
+
## yellowpages-search
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
hasdata yellowpages-search --search-terms "plumber" --geo-location-terms "Atlanta, GA" --raw
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## yellowpages-place
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
hasdata yellowpages-place --url "https://www.yellowpages.com/atlanta-ga/mip/..." --raw
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Non-obvious use cases
|
|
94
|
+
|
|
95
|
+
- **Sales-lead research** — `google-maps --q "INDUSTRY" --ll "@LAT,LNG,12z"` to enumerate businesses, then `xargs` into `google-maps-place` for public phone/website details. Use email collection only for legitimate business outreach with opt-out, privacy-law, and rate-limit controls.
|
|
96
|
+
- **Reputation monitoring** — `google-maps-reviews --place-id X --sort lowest` returns the worst reviews first; great for surfacing crisis signals fast. Run weekly to detect new 1-star drops.
|
|
97
|
+
- **"Is this business open?"** — `google-maps-place --place-id X --raw | jq '.hours'` for current hours; also surfaces `permanently_closed` status.
|
|
98
|
+
- **Verify an address user gave you** — `google-maps --q "BUSINESS NAME, CITY" --raw | jq '.local_results[0].address'`. Don't trust user-provided addresses for high-stakes actions (mailing, payments).
|
|
99
|
+
- **Public business contact lookup** — `google-maps-place` includes phone and website; `web-scraping --url WEBSITE --extract-emails` returns emails parsed from the homepage. Use only for public business contact channels and disclose uncertainty.
|
|
100
|
+
- **Competitive-density mapping** — `google-maps --q "coffee shop" --ll "@LAT,LNG,Zz"` at varying zoom levels; aggregate `.local_results[]` into a CSV with addresses + ratings to find under-served zones.
|
|
101
|
+
- **Service-area validation** — chain `yelp-search --location "CITY"` for a few cities to confirm a business with the same name covers them.
|
|
102
|
+
- **Find recently opened businesses** — `google-maps-place` returns `description.years_in_business` and posts/updates timestamps; sort.
|
|
103
|
+
- **Negative-review sample for product analysis** — `yelp-place --url X --raw | jq '.reviews[] | select(.rating <= 2)'`; useful as input to a "what do customers complain about" summary.
|
|
104
|
+
- **Photo-mining for visual docs** — `google-maps-photos --place-id X` returns categorized photo URLs (interior, food, exterior). Useful when the user needs an image and doesn't want to rely on `google-images`.
|
|
105
|
+
- **Local-guide credibility** — `google-maps-contributor-reviews --contributor-id X` shows everything a specific reviewer wrote, useful for filtering out shilling/fake reviewers when their pattern is suspicious.
|
|
106
|
+
- **YellowPages for B2B niches** — service-business categories (plumbers, electricians, lawyers) are often better indexed by YellowPages than Yelp; try both when one comes up empty.
|
|
107
|
+
- **Cross-platform reputation diff** — same business name + city via `yelp-search` and `google-maps` to compare ratings across platforms (gap often signals fake reviews on one).
|
|
108
|
+
- **Promo / event surveillance** — `google-maps-posts --place-id X` surfaces current offers, holiday hours, and limited-time events the business is actively pushing. Cheaper signal than scraping the website, and the `cta.url` typically links to the canonical landing page.
|
|
109
|
+
- **Detect a business about to relaunch / rebrand** — sudden burst of new `google-maps-posts` after months of silence usually precedes a re-grand-opening or ownership change.
|
|
110
|
+
|
|
111
|
+
## Common patterns
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Build a directory: search → fan out to per-place details
|
|
115
|
+
hasdata google-maps --q "yoga studios" --ll "@30.27,-97.74,12z" --raw \
|
|
116
|
+
| jq -r '.local_results[].place_id' \
|
|
117
|
+
| head -10 \
|
|
118
|
+
| xargs -I{} hasdata google-maps-place --place-id {} --raw
|
|
119
|
+
|
|
120
|
+
# Sentiment / review analysis
|
|
121
|
+
hasdata google-maps-reviews --place-id "$PID" --sort lowest --raw \
|
|
122
|
+
| jq '.reviews[] | {rating, snippet}'
|
|
123
|
+
```
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Real-estate reference
|
|
2
|
+
|
|
3
|
+
Subcommands: `zillow-listing`, `zillow-property`, `redfin-listing`, `redfin-property` — 5 credits each.
|
|
4
|
+
|
|
5
|
+
For short-term rentals (Airbnb), hotels (Booking) and flights, see `travel.md`.
|
|
6
|
+
|
|
7
|
+
`*-listing` is for filtered searches; `*-property` is a single-property deep dive.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## zillow-listing
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
hasdata zillow-listing --keyword "Austin, TX" --type forSale [filters] --raw | jq '.results[]'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Required:
|
|
18
|
+
- `--keyword "City, ST"` (default: `New York, NY`)
|
|
19
|
+
- `--type forSale|forRent|sold` (default: `forSale`)
|
|
20
|
+
|
|
21
|
+
Price / size (bracketed pairs, kept as floats):
|
|
22
|
+
- `--price-min N --price-max N`
|
|
23
|
+
- `--beds-min N --beds-max N`
|
|
24
|
+
- `--baths-min N --baths-max N`
|
|
25
|
+
- `--square-feet-min N --square-feet-max N`
|
|
26
|
+
- `--lot-size-min N --lot-size-max N`
|
|
27
|
+
- `--year-built-min N --year-built-max N`
|
|
28
|
+
- `--hoa N` — max HOA fee
|
|
29
|
+
- `--parking-spots-min N`
|
|
30
|
+
|
|
31
|
+
Array filters (enum-validated, lowercase camelCase values):
|
|
32
|
+
- `--home-types house|townhome|multiFamily|condo|lot|apartment|manufactured` (repeatable)
|
|
33
|
+
- `--pets allowsLargeDogs|allowsSmallDogs|allowsCats` (repeatable)
|
|
34
|
+
- `--other-amenities ac|pool|waterfront|onsiteParking|inUnitLaundry|acceptZillowApplications|incomeRestricted|apartmentCommunity` (repeatable)
|
|
35
|
+
- `--views city|mountain|park|water` (repeatable)
|
|
36
|
+
- `--basement finished|unfinished` (repeatable)
|
|
37
|
+
- `--property-status comingSoon|acceptingBackupOffers|pendingAndUnderContract` (repeatable)
|
|
38
|
+
- `--listing-publish-options ownerPosted|agentListed|newConstruction|foreclosures|auctions|foreclosed|preForeclosures` (repeatable)
|
|
39
|
+
- `--tours open|3d` (repeatable)
|
|
40
|
+
|
|
41
|
+
Booleans:
|
|
42
|
+
- `--must-have-garage` — only listings with a garage
|
|
43
|
+
- `--single-story-only`
|
|
44
|
+
- `--hide55plus-communities`
|
|
45
|
+
|
|
46
|
+
Other:
|
|
47
|
+
- `--listing-type byAgent|byOwner`
|
|
48
|
+
- `--days-on-zillow 1|7|14|30|90|6m|12m|24m|36m`
|
|
49
|
+
- `--keywords "open floor plan"` — refinement keywords (matches in description)
|
|
50
|
+
- `--move-in-date 2026-06-01`
|
|
51
|
+
- `--page N` — pagination
|
|
52
|
+
- `--sort verifiedSource|homesForYou|priceHighToLow|priceLowToHigh|paymentHighToLow|paymentLowToHigh|newest|bedrooms|bathrooms|squareFeet|lotSize`
|
|
53
|
+
|
|
54
|
+
### Examples
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Family home, mid-market, sorted cheapest first
|
|
58
|
+
hasdata zillow-listing \
|
|
59
|
+
--keyword "Austin, TX" --type forSale \
|
|
60
|
+
--price-min 400000 --price-max 900000 \
|
|
61
|
+
--beds-min 3 --beds-max 5 --baths-min 2 \
|
|
62
|
+
--home-types house --home-types townhome \
|
|
63
|
+
--sort priceLowToHigh --raw | jq '.results[] | {address, price, beds, baths}'
|
|
64
|
+
|
|
65
|
+
# Pet-friendly rental
|
|
66
|
+
hasdata zillow-listing \
|
|
67
|
+
--keyword "Seattle, WA" --type forRent \
|
|
68
|
+
--price-max 4000 \
|
|
69
|
+
--pets allowsSmallDogs --pets allowsCats \
|
|
70
|
+
--parking-spots-min 1 --must-have-garage \
|
|
71
|
+
--raw
|
|
72
|
+
|
|
73
|
+
# Recently sold comps
|
|
74
|
+
hasdata zillow-listing \
|
|
75
|
+
--keyword "Miami, FL" --type sold \
|
|
76
|
+
--square-feet-min 1500 --square-feet-max 4000 \
|
|
77
|
+
--year-built-min 2000 --year-built-max 2020 \
|
|
78
|
+
--days-on-zillow 12m --sort newest --raw
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Bracketed query params (`price[max]`, `homeTypes[]`, `yearBuilt[min]`) are handled by the CLI — pass the kebab-case flags shown above, not the raw API names.
|
|
82
|
+
|
|
83
|
+
## zillow-property
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
hasdata zillow-property --url "https://www.zillow.com/homedetails/.../123_zpid/" --raw | jq .
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Or with `--zpid <ID>`. Returns full property details (photos, history, schools, taxes, walk-score, etc.).
|
|
90
|
+
|
|
91
|
+
## redfin-listing
|
|
92
|
+
|
|
93
|
+
Similar shape to `zillow-listing` but Redfin's enums differ. Run `hasdata redfin-listing --help` for the exact list. Common pattern:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
hasdata redfin-listing --location "San Francisco, CA" --status forSale \
|
|
97
|
+
--min-price 800000 --max-price 1500000 \
|
|
98
|
+
--min-beds 2 --raw
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## redfin-property
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
hasdata redfin-property --url "https://www.redfin.com/CA/San-Francisco/.../home/12345" --raw
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Non-obvious use cases
|
|
110
|
+
|
|
111
|
+
- **Investment screening** — combine `--type sold` + `--days-on-zillow 12m` + `--year-built-min` + `--lot-size-min` to surface flip / value-add candidates. Then `xargs` into `zillow-property` for ARV analysis.
|
|
112
|
+
- **Tax-appeal comps** — `--type sold --keyword "ZIP CODE" --days-on-zillow 12m` filtered to your home's beds/baths/sqft band gives recent sales the assessor used; export to CSV with `jq -r '.results[] | [.address, .price, .beds, .baths, .squareFootage, .soldDate] | @csv'`.
|
|
113
|
+
- **Appraiser comp pull** — same trick, narrower square-footage and same year-built band.
|
|
114
|
+
- **Motivated-seller signal** — `--type forSale --days-on-zillow 90` returns listings that have lingered. Often willing to negotiate.
|
|
115
|
+
- **Pre-relocation neighborhood scan** — run the same `--type forRent` filter across 5–10 neighborhoods, dump rent distributions with `jq '.results[].price'`, eyeball cost differences before booking visits.
|
|
116
|
+
- **STR-vs-LTR feasibility** — pair `airbnb-listing` (see `travel.md`) for nightly rates with `zillow-listing --type forSale` for purchase price in the same area; compute gross yield client-side.
|
|
117
|
+
- **HOA filter** — `--hoa N` caps fee; useful for buyers who want max payment ceilings.
|
|
118
|
+
- **School-driven house hunt** — `zillow-property` returns school ratings; filter `zillow-listing` results down by walking each property and keeping those with rating ≥ X.
|
|
119
|
+
- **Open-houses this weekend** — Zillow tags open-house listings; check `.results[].openHouseTimes` for upcoming slots.
|
|
120
|
+
- **3D-tour / virtual-tour-only filter** — `--tours 3d` → only listings with virtual tours. Useful for remote / international buyers.
|
|
121
|
+
- **Pet-friendly rentals at scale** — `--pets allowsLargeDogs --pets allowsCats` for multi-pet households. Pairs well with `--keyword` for specific neighborhoods.
|
|
122
|
+
- **Foreclosure and pre-foreclosure leads** — `--listing-publish-options foreclosures --listing-publish-options preForeclosures`.
|
|
123
|
+
- **Non-traditional listing types** — `--listing-type byOwner` for FSBO; `--listing-type byAgent` for agent-listed (default mix).
|
|
124
|
+
- **Move-in date constraint** — `--move-in-date YYYY-MM-DD` for rental searches with a hard timing requirement.
|
|
125
|
+
- **Bulk address verification** — pipe a list of property URLs through `zillow-property` to confirm they resolve and pull the canonical address Zillow uses.
|
|
126
|
+
- **Verify a Redfin/Zillow listing is real** — `redfin-property --url X --raw | jq .status` to confirm it hasn't been pulled.
|