#98 by GitHub stars
browser-use/browser-harness
Let Claude Code, Codex or Cursor use your real Chrome, logged in as you. One prompt to set up. Open source, MIT.
History
Review weekly changes to SKILL.md before updating. Dates mark the weeks in which we observed each version; checks apply to the recorded commits.
View weekly changes
SKILL.md
Week of Nov 2, 2026 · +2 / −0 lines
Before Network or broad shell → After Network or broad shell
4ced8e0087d2 → 6e69c7fbe97e
+ 181 Cloud browsers ignore viewport and device emulation (`Emulation.setDeviceMetricsOverride`, touch, window bounds) unless started with `start_remote_daemon(name, allowResizing=True)`.
+ 182
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 4ced8e0087d2
No earlier version was observed for comparison.
skills/browser-harness/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
4ced8e0087d2 → 6e69c7fbe97e
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 4ced8e0087d2
No earlier version was observed for comparison.
src/browser_harness/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
4ced8e0087d2 → 6e69c7fbe97e
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 4ced8e0087d2
No earlier version was observed for comparison.
Verified commit 6e69c7fbe97edded9934e3fb305d9af3536f941f
git clone --filter=blob:none --no-checkout https://github.com/browser-use/browser-harness.git .hotskills/browser-use-browser-harness && git -C .hotskills/browser-use-browser-harness checkout --detach 6e69c7fbe97edded9934e3fb305d9af3536f941f
# Copy each selected skill directory from .hotskills/browser-use-browser-harness into .claude/skills/<skill-name>/git clone --filter=blob:none --no-checkout https://github.com/browser-use/browser-harness.git .hotskills/browser-use-browser-harness && git -C .hotskills/browser-use-browser-harness checkout --detach 6e69c7fbe97edded9934e3fb305d9af3536f941f
# Copy each selected skill directory from .hotskills/browser-use-browser-harness into .agents/skills/<skill-name>/Heat
7.2- Star growth, last 7 daysAhead of 79% of tracked repositories
- Star growth, last 24 hoursAhead of 84% of tracked repositories
- Rank movement, last 7 daysAhead of 80% of tracked repositories
- Commits, last 30 daysAhead of 95% of tracked repositories
- Accounts asking about it through MCP, last 7 daysNot available
- Hot votes this weekAhead of 0% of tracked repositories
Heat never changes the order by stars, and sponsorship never touches it. How heat works
Stars over time
Individual skills in this repository
- browser-harness
/ - browser-harness
skills/browser-harness - browser-harness
src/browser_harness
How it works
browser-harness
When your agent uses it
Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those.
What it loads into context
Frontmatter
51 tokensAlways available to the agent
SKILL.md
3,322 tokensWhen the skill is activated
Reference documents
739,099 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- When Not to Use
- Usage
- Local Chrome
- Remote Browsers
- Page Workflow
- Recordings and Videos
- Interaction Skills
- Design Constraints
- Gotchas
- Domain Skills
Scripts executed separately
agent-workspace/agent_helpers.pyagent-workspace/domain-skills/browser-use-cloud/cleanup-zombies.pyagent-workspace/domain-skills/claude-ai/extract-share-transcript.pybrowser-harnesssrc/mcp_server.pytests/__init__.pytests/conftest.pytests/integration/__init__.pytests/integration/test_js.pytests/unit/__init__.pytests/unit/test_admin.pytests/unit/test_auth.pytests/unit/test_brave_origin.pytests/unit/test_daemon.pytests/unit/test_helpers.pytests/unit/test_ipc.pytests/unit/test_macos.pytests/unit/test_mcp_cli.pytests/unit/test_mcp_server.pytests/unit/test_recorder.pytests/unit/test_run.pytests/unit/test_skill.pytests/unit/test_video_render.py
Files
.claude-plugin/marketplace.jsonasset750 bytes.claude-plugin/plugin.jsonasset694 bytes.env.exampleasset102 bytes.github/ISSUE_TEMPLATE/bug-report.ymlasset1,468 bytes.github/ISSUE_TEMPLATE/config.ymlasset395 bytes.github/ISSUE_TEMPLATE/feature-request.ymlasset909 bytes.github/VOUCHED.tdasset470 bytes.github/workflows/release.ymlasset545 bytes.gitignoreasset101 bytesAGENTS.mddoc2,185 bytesCONTRIBUTING.mddoc1,272 bytesLICENSEasset1,068 bytesREADME.mddoc8,867 bytesSKILL.mdcore14,519 bytesSKILL.mdcore14,519 bytesagent-workspace/agent_helpers.pyruns243 bytesagent-workspace/domain-skills/BOSS-zhipin/chat.mddoc12,942 bytesagent-workspace/domain-skills/BOSS-zhipin/job-search.mddoc13,045 bytesagent-workspace/domain-skills/BOSS-zhipin/navigation.mddoc2,650 bytesagent-workspace/domain-skills/aa/checkout.mddoc10,076 bytesagent-workspace/domain-skills/admin/microsoft-365.mddoc123 bytesagent-workspace/domain-skills/agentlist/discovery.mddoc5,996 bytesagent-workspace/domain-skills/agoda/scraping.mddoc34,654 bytesagent-workspace/domain-skills/airbnb/monthly-search.mddoc3,140 bytesagent-workspace/domain-skills/alaska/checkout.mddoc5,751 bytesagent-workspace/domain-skills/aliexpress/scraping.mddoc44,619 bytesagent-workspace/domain-skills/amazon/order-history.mddoc4,977 bytesagent-workspace/domain-skills/amazon/product-search.mddoc8,703 bytesagent-workspace/domain-skills/ap/namecheap.mddoc96 bytesagent-workspace/domain-skills/apartments-com/scraping.mddoc27,001 bytesagent-workspace/domain-skills/apollo/search-and-lists.mddoc4,641 bytesagent-workspace/domain-skills/app/apollo.mddoc95 bytesagent-workspace/domain-skills/app/smartlead.mddoc107 bytesagent-workspace/domain-skills/apple-app-store/scraping.mddoc32,355 bytesagent-workspace/domain-skills/archive-org/scraping.mddoc15,174 bytesagent-workspace/domain-skills/articulate-rise/code-blocks.mddoc9,646 bytesagent-workspace/domain-skills/arxiv-bulk/scraping.mddoc13,989 bytesagent-workspace/domain-skills/arxiv/scraping.mddoc13,766 bytesagent-workspace/domain-skills/atlas/overview.mddoc3,467 bytesagent-workspace/domain-skills/bbb/scraping.mddoc25,063 bytesagent-workspace/domain-skills/best-buy/scraping.mddoc41,992 bytesagent-workspace/domain-skills/bigbang-hr/checkout.mddoc4,739 bytesagent-workspace/domain-skills/bilbasen/search.mddoc4,235 bytesagent-workspace/domain-skills/bilibili/navigation.mddoc11,330 bytesagent-workspace/domain-skills/bluesky/scraping.mddoc35,756 bytesagent-workspace/domain-skills/booking-com/scraping.mddoc22,283 bytesagent-workspace/domain-skills/booking/frontier-checkout.mddoc128 bytesagent-workspace/domain-skills/browser-use-cloud/cleanup-zombies.pyruns5,841 bytesagent-workspace/domain-skills/browser-use-cloud/cloud.mddoc8,884 bytesagent-workspace/domain-skills/capterra/scraping.mddoc18,700 bytesagent-workspace/domain-skills/centilebrain/generate-estimates.mddoc5,218 bytesagent-workspace/domain-skills/chess-com/scraping.mddoc25,391 bytesagent-workspace/domain-skills/claude-ai/extract-share-transcript.pyruns2,814 bytesagent-workspace/domain-skills/claude-ai/share-export.mddoc3,886 bytesagent-workspace/domain-skills/claude/custom-connectors.mddoc2,061 bytesagent-workspace/domain-skills/claude/skills.mddoc3,409 bytesagent-workspace/domain-skills/clinicaltrials-gov/scraping.mddoc30,162 bytesagent-workspace/domain-skills/coingecko/scraping.mddoc14,610 bytesagent-workspace/domain-skills/coinmarketcap/scraping.mddoc16,916 bytesagent-workspace/domain-skills/costco/scraping.mddoc25,432 bytesagent-workspace/domain-skills/coursera/scraping.mddoc13,453 bytesagent-workspace/domain-skills/craigslist/scraping.mddoc15,804 bytesagent-workspace/domain-skills/crossref/scraping.mddoc23,847 bytesagent-workspace/domain-skills/ctrip/hotels.mddoc10,296 bytesagent-workspace/domain-skills/dashboard/stripe.mddoc112 bytesagent-workspace/domain-skills/dev-to/scraping.mddoc13,439 bytesagent-workspace/domain-skills/dexscreener/scraping.mddoc45,805 bytesagent-workspace/domain-skills/dice/scraping.mddoc28,180 bytesagent-workspace/domain-skills/discogs/scraping.mddoc24,385 bytesagent-workspace/domain-skills/docs/google-sheets.mddoc124 bytesagent-workspace/domain-skills/doordash/search-and-product-pages.mddoc7,572 bytesagent-workspace/domain-skills/duckduckgo/scraping.mddoc15,857 bytesagent-workspace/domain-skills/ebay/scraping.mddoc21,125 bytesagent-workspace/domain-skills/espn/scraping.mddoc14,404 bytesagent-workspace/domain-skills/etsy/scraping.mddoc18,940 bytesagent-workspace/domain-skills/eventbrite/scraping.mddoc15,703 bytesagent-workspace/domain-skills/expedia/api.mddoc3,298 bytesagent-workspace/domain-skills/expedia/automation.mddoc5,084 bytesagent-workspace/domain-skills/expedia/flights-search.mddoc10,356 bytesagent-workspace/domain-skills/facebook/groups.mddoc10,089 bytesagent-workspace/domain-skills/facebook/pages.mddoc13,754 bytesagent-workspace/domain-skills/feishu/docx-scraping.mddoc4,887 bytesagent-workspace/domain-skills/figma/comments.mddoc2,418 bytesagent-workspace/domain-skills/finviz/scraping.mddoc21,415 bytesagent-workspace/domain-skills/flighthub/flights-search.mddoc6,911 bytesagent-workspace/domain-skills/flipkart/shopping.mddoc10,290 bytesagent-workspace/domain-skills/flyfrontier/checkout.mddoc116 bytesagent-workspace/domain-skills/framer/editor.mddoc6,841 bytesagent-workspace/domain-skills/fred/scraping.mddoc19,679 bytesagent-workspace/domain-skills/frontier/checkout.mddoc7,479 bytesagent-workspace/domain-skills/furnishedfinder/search.mddoc4,509 bytesagent-workspace/domain-skills/g2/scraping.mddoc22,513 bytesagent-workspace/domain-skills/gemini/spark-skills.mddoc1,654 bytesagent-workspace/domain-skills/genius/scraping.mddoc20,164 bytesagent-workspace/domain-skills/github/repo-actions.mddoc3,508 bytesagent-workspace/domain-skills/github/scraping.mddoc8,031 bytesagent-workspace/domain-skills/glassdoor/scraping.mddoc20,069 bytesagent-workspace/domain-skills/gmail/compose.mddoc5,586 bytesagent-workspace/domain-skills/goodreads/scraping.mddoc19,783 bytesagent-workspace/domain-skills/google-maps/scraping.mddoc21,894 bytesagent-workspace/domain-skills/google-patents/scraping.mddoc27,972 bytesagent-workspace/domain-skills/google-play/scraping.mddoc32,693 bytesagent-workspace/domain-skills/google-sheets/writing-cells.mddoc2,761 bytesagent-workspace/domain-skills/google-trends/scraping.mddoc21,520 bytesagent-workspace/domain-skills/google/flights-multi-city.mddoc5,377 bytesagent-workspace/domain-skills/gutenberg/scraping.mddoc16,280 bytesagent-workspace/domain-skills/hackernews/scraping.mddoc8,669 bytesagent-workspace/domain-skills/home-depot/scraping.mddoc43,604 bytesagent-workspace/domain-skills/howlongtobeat/scraping.mddoc22,177 bytesagent-workspace/domain-skills/hubspot/private-app-webhooks.mddoc6,123 bytesagent-workspace/domain-skills/iherb/product-labels.mddoc2,840 bytesagent-workspace/domain-skills/imdb/scraping.mddoc12,706 bytesagent-workspace/domain-skills/itch-io/scraping.mddoc17,293 bytesagent-workspace/domain-skills/jetblue/checkout.mddoc8,555 bytesagent-workspace/domain-skills/job-boards/indeed-glassdoor.mddoc36,538 bytesagent-workspace/domain-skills/kalshi/scraping.mddoc27,623 bytesagent-workspace/domain-skills/letterboxd/scraping.mddoc15,039 bytesagent-workspace/domain-skills/linkedin/invitation-manager.mddoc4,568 bytesagent-workspace/domain-skills/loom/folder-enumeration.mddoc8,793 bytesagent-workspace/domain-skills/loom/read-recording.mddoc4,688 bytesagent-workspace/domain-skills/lulu/account-currency.mddoc1,926 bytesagent-workspace/domain-skills/ly-com/hotels.mddoc10,500 bytesagent-workspace/domain-skills/macrotrends/scraping.mddoc21,013 bytesagent-workspace/domain-skills/manus/tasks.mddoc12,220 bytesagent-workspace/domain-skills/medium/article-hydration.mddoc5,663 bytesagent-workspace/domain-skills/medium/scraping.mddoc17,239 bytesagent-workspace/domain-skills/mercari/scraping.mddoc25,679 bytesagent-workspace/domain-skills/mermaid/render.mddoc2,965 bytesagent-workspace/domain-skills/metacritic/scraping.mddoc20,734 bytesagent-workspace/domain-skills/microsoft-365/domain-setup.mddoc1,765 bytesagent-workspace/domain-skills/musicbrainz/scraping.mddoc19,581 bytesagent-workspace/domain-skills/namecheap/advanced-dns.mddoc1,664 bytesagent-workspace/domain-skills/nasa/scraping.mddoc15,105 bytesagent-workspace/domain-skills/news-aggregation/multi-source.mddoc8,133 bytesagent-workspace/domain-skills/nordic/product-labels.mddoc1,141 bytesagent-workspace/domain-skills/ods/fact-sheets.mddoc1,762 bytesagent-workspace/domain-skills/open-library/scraping.mddoc19,294 bytesagent-workspace/domain-skills/openalex/scraping.mddoc18,250 bytesagent-workspace/domain-skills/openstreetmap/scraping.mddoc20,955 bytesagent-workspace/domain-skills/outlook/webmail-compose.mddoc2,110 bytesagent-workspace/domain-skills/package-registries/npm-pypi.mddoc16,645 bytesagent-workspace/domain-skills/partsouq/vin-lookup.mddoc1,654 bytesagent-workspace/domain-skills/perplexity/computer.mddoc16,424 bytesagent-workspace/domain-skills/polymarket/scraping.mddoc13,673 bytesagent-workspace/domain-skills/poshmark/scraping.mddoc25,121 bytesagent-workspace/domain-skills/producthunt/scraping.mddoc11,349 bytesagent-workspace/domain-skills/pubmed/scraping.mddoc18,774 bytesagent-workspace/domain-skills/qbo/report-export.mddoc5,786 bytesagent-workspace/domain-skills/quora/scraping.mddoc16,564 bytesagent-workspace/domain-skills/rawg/scraping.mddoc13,740 bytesagent-workspace/domain-skills/realtor-com/scraping.mddoc30,754 bytesagent-workspace/domain-skills/reddit/scraping.mddoc8,480 bytesagent-workspace/domain-skills/redfin/scraping.mddoc33,903 bytesagent-workspace/domain-skills/rest-countries/scraping.mddoc9,951 bytesagent-workspace/domain-skills/rightmove/scraping.mddoc34,054 bytesagent-workspace/domain-skills/rotten-tomatoes/scraping.mddoc35,789 bytesagent-workspace/domain-skills/salesforce/.gitkeepasset0 bytesagent-workspace/domain-skills/sec-edgar/scraping.mddoc15,988 bytesagent-workspace/domain-skills/sephora/scraping.mddoc23,117 bytesagent-workspace/domain-skills/shopify-admin/README.mddoc2,101 bytesagent-workspace/domain-skills/shopify-admin/embedded-apps.mddoc2,607 bytesagent-workspace/domain-skills/shopify-admin/forms-app.mddoc2,227 bytesagent-workspace/domain-skills/shopify-admin/knowledge-base.mddoc4,258 bytesagent-workspace/domain-skills/shopify-admin/polaris-inputs.mddoc5,379 bytesagent-workspace/domain-skills/shopify-storefronts/scraping.mddoc25,154 bytesagent-workspace/domain-skills/slack/files.mddoc3,410 bytesagent-workspace/domain-skills/smartlead/mailbox-warmup.mddoc3,465 bytesagent-workspace/domain-skills/sofascore/scraping.mddoc25,540 bytesagent-workspace/domain-skills/soundcloud/scraping.mddoc14,202 bytesagent-workspace/domain-skills/spotify/scraping.mddoc14,821 bytesagent-workspace/domain-skills/spreadshirt/.gitkeepasset0 bytesagent-workspace/domain-skills/stackoverflow/scraping.mddoc18,587 bytesagent-workspace/domain-skills/steam/scraping.mddoc22,127 bytesagent-workspace/domain-skills/stripe/account-sandboxes.mddoc1,797 bytesagent-workspace/domain-skills/substack/scraping.mddoc12,204 bytesagent-workspace/domain-skills/supabase/dashboard.mddoc2,684 bytesagent-workspace/domain-skills/target/scraping.mddoc25,196 bytesagent-workspace/domain-skills/tasksquad-ai/agents.mddoc3,035 bytesagent-workspace/domain-skills/tasksquad-ai/auth.mddoc3,118 bytesagent-workspace/domain-skills/tasksquad-ai/tasks.mddoc6,452 bytesagent-workspace/domain-skills/tcgplayer/scraping.mddoc23,445 bytesagent-workspace/domain-skills/thetechgeeks/pricing.mddoc2,615 bytesagent-workspace/domain-skills/thorne/product-labels.mddoc1,580 bytesagent-workspace/domain-skills/ticketmaster/scraping.mddoc22,874 bytesagent-workspace/domain-skills/tiktok/upload.mddoc3,918 bytesagent-workspace/domain-skills/tradingview/scraping.mddoc12,728 bytesagent-workspace/domain-skills/trello/boards-and-lists.mddoc3,616 bytesagent-workspace/domain-skills/tripadvisor/scraping.mddoc23,302 bytesagent-workspace/domain-skills/trulia/scraping.mddoc26,054 bytesagent-workspace/domain-skills/trustpilot/scraping.mddoc13,939 bytesagent-workspace/domain-skills/twitch/scraping.mddoc42,469 bytesagent-workspace/domain-skills/ulta/scraping.mddoc39,949 bytesagent-workspace/domain-skills/upwork/scraping.mddoc19,341 bytesagent-workspace/domain-skills/vercel/archive-and-audit.mddoc3,045 bytesagent-workspace/domain-skills/vercel/observability.mddoc2,157 bytesagent-workspace/domain-skills/vercel/vercel.mddoc7,497 bytesagent-workspace/domain-skills/vinted/scraping.mddoc16,295 bytesagent-workspace/domain-skills/walmart/scraping.mddoc18,974 bytesagent-workspace/domain-skills/wayback-machine/scraping.mddoc10,863 bytesagent-workspace/domain-skills/weather/scraping.mddoc16,925 bytesagent-workspace/domain-skills/wehotel/hotels.mddoc10,273 bytesagent-workspace/domain-skills/wellfound/scraping.mddoc21,318 bytesagent-workspace/domain-skills/weread/read.mddoc9,066 bytesagent-workspace/domain-skills/wikipedia/scraping.mddoc28,432 bytesagent-workspace/domain-skills/world-bank/scraping.mddoc11,893 bytesagent-workspace/domain-skills/x/article-source-recovery.mddoc2,019 bytesagent-workspace/domain-skills/x/posting.mddoc2,796 bytesagent-workspace/domain-skills/xiaohongshu/scraping.mddoc6,265 bytesagent-workspace/domain-skills/yahoo-finance/scraping.mddoc18,419 bytesagent-workspace/domain-skills/youtube/playback.mddoc4,305 bytesagent-workspace/domain-skills/youtube/scraping.mddoc18,142 bytesagent-workspace/domain-skills/zillow/scraping.mddoc21,268 bytesagent-workspace/domain-skills/zoopla/scraping.mddoc26,188 bytesbrowser-harnessruns939 bytesdocs/MCP.mddoc2,241 bytesdocs/allow-remote-debugging.pngasset192,627 bytesdocs/download-latest-20-x-videos.gifasset1,352,637 bytesdocs/setup-remote-debugging.pngasset50,720 bytesdocs/snap-linux-headless.mddoc2,061 bytesinstall.mddoc4,054 bytesinteraction-skills/connection.mddoc1,979 bytesinteraction-skills/cookies.mddoc119 bytesinteraction-skills/cross-origin-iframes.mddoc165 bytesinteraction-skills/dialogs.mddoc2,328 bytesinteraction-skills/downloads.mddoc160 bytesinteraction-skills/drag-and-drop.mddoc168 bytesinteraction-skills/dropdowns.mddoc193 bytesinteraction-skills/iframes.mddoc168 bytesinteraction-skills/make-video.mddoc4,479 bytesinteraction-skills/network-requests.mddoc196 bytesinteraction-skills/print-as-pdf.mddoc171 bytesinteraction-skills/profile-sync.mddoc4,994 bytesinteraction-skills/screenshots.mddoc1,063 bytesinteraction-skills/scrolling.mddoc1,018 bytesinteraction-skills/shadow-dom.mddoc147 bytesinteraction-skills/tabs.mddoc2,488 bytesinteraction-skills/uploads.mddoc10 bytesinteraction-skills/viewport.mddoc529 bytespyproject.tomlasset1,525 bytessrc/mcp_server.pyruns8,500 bytestests/__init__.pyruns0 bytestests/conftest.pyruns293 bytestests/integration/__init__.pyruns0 bytestests/integration/test_js.pyruns6,443 bytestests/unit/__init__.pyruns0 bytestests/unit/test_admin.pyruns60,999 bytestests/unit/test_auth.pyruns1,072 bytestests/unit/test_brave_origin.pyruns2,647 bytestests/unit/test_daemon.pyruns32,144 bytestests/unit/test_helpers.pyruns28,367 bytestests/unit/test_ipc.pyruns5,232 bytestests/unit/test_macos.pyruns4,297 bytestests/unit/test_mcp_cli.pyruns604 bytestests/unit/test_mcp_server.pyruns1,104 bytestests/unit/test_recorder.pyruns3,345 bytestests/unit/test_run.pyruns14,128 bytestests/unit/test_skill.pyruns1,130 bytestests/unit/test_video_render.pyruns697 bytes
Read SKILL.md
# browser-harness
Direct browser control via CDP. For task-specific edits, use `agent-workspace/agent_helpers.py`. For setup, install, or connection problems, read https://github.com/browser-use/browser-harness/blob/main/install.md.
## When Not to Use
A basic fetch of public information needs no browser. If a plain HTTP request can read it — a public page, an API, docs — use `curl` or your fetch tool, and leave the browser alone. Use browser-harness when the task needs interaction (click, type, navigate), the user's logged-in session, JS rendering, or a bot-protected page. If a direct fetch fails or returns a shell page, then escalate to the browser.
Domain skills are off by default. Set `BH_DOMAIN_SKILLS=1` to enable them; see the bottom section.
**If `BH_DOMAIN_SKILLS=1` and the task is site-specific, read every file in the matching `$BH_AGENT_WORKSPACE/domain-skills/<site>/` directory before inventing an approach.**
## Usage
View the complete source on GitHubbrowser-harness
When your agent uses it
Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those.
What it loads into context
Frontmatter
51 tokensAlways available to the agent
SKILL.md
3,322 tokensWhen the skill is activated
Reference documents
663 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- When Not to Use
- Usage
- Local Chrome
- Remote Browsers
- Page Workflow
- Recordings and Videos
- Interaction Skills
- Design Constraints
- Gotchas
- Domain Skills
Scripts executed separately
../../browser-harness../../browser-harness
Files
../../browser-harnessruns939 bytes../../browser-harnessruns939 bytesSKILL.mdcore14,519 bytesSKILL.mdcore14,519 bytesreferences/install.mddoc2,796 bytes
Read SKILL.md
# browser-harness
Direct browser control via CDP. For task-specific edits, use `agent-workspace/agent_helpers.py`. For setup, install, or connection problems, read https://github.com/browser-use/browser-harness/blob/main/install.md.
## When Not to Use
A basic fetch of public information needs no browser. If a plain HTTP request can read it — a public page, an API, docs — use `curl` or your fetch tool, and leave the browser alone. Use browser-harness when the task needs interaction (click, type, navigate), the user's logged-in session, JS rendering, or a bot-protected page. If a direct fetch fails or returns a shell page, then escalate to the browser.
Domain skills are off by default. Set `BH_DOMAIN_SKILLS=1` to enable them; see the bottom section.
**If `BH_DOMAIN_SKILLS=1` and the task is site-specific, read every file in the matching `$BH_AGENT_WORKSPACE/domain-skills/<site>/` directory before inventing an approach.**
## Usage
View the complete source on GitHubbrowser-harness
When your agent uses it
Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those.
What it loads into context
Frontmatter
51 tokensAlways available to the agent
SKILL.md
3,322 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- When Not to Use
- Usage
- Local Chrome
- Remote Browsers
- Page Workflow
- Recordings and Videos
- Interaction Skills
- Design Constraints
- Gotchas
- Domain Skills
Scripts executed separately
../../browser-harness../../browser-harness__init__.py_ipc.pyadmin.pyauth.pydaemon.pyhelpers.pymacos.pymcp_cli.pypaths.pyrecorder.pyrun.pytelemetry.pyvideo.pyvideo_render.py
Files
../../browser-harnessruns939 bytes../../browser-harnessruns939 bytesSKILL.mdcore14,519 bytesSKILL.mdcore14,519 bytes__init__.pyruns37 bytes_ipc.pyruns9,158 bytesadmin.pyruns66,297 bytesauth.pyruns18,340 bytesdaemon.pyruns40,951 byteshelpers.pyruns27,779 bytesmacos.pyruns4,213 bytesmcp_cli.pyruns565 bytespaths.pyruns1,516 bytesrecorder.pyruns12,497 bytesrun.pyruns14,479 bytestelemetry.pyruns8,961 bytesvideo-template.htmlasset70,505 bytesvideo.pyruns29,518 bytesvideo_render.pyruns20,489 bytes
Read SKILL.md
# browser-harness
Direct browser control via CDP. For task-specific edits, use `agent-workspace/agent_helpers.py`. For setup, install, or connection problems, read https://github.com/browser-use/browser-harness/blob/main/install.md.
## When Not to Use
A basic fetch of public information needs no browser. If a plain HTTP request can read it — a public page, an API, docs — use `curl` or your fetch tool, and leave the browser alone. Use browser-harness when the task needs interaction (click, type, navigate), the user's logged-in session, JS rendering, or a bot-protected page. If a direct fetch fails or returns a shell page, then escalate to the browser.
Domain skills are off by default. Set `BH_DOMAIN_SKILLS=1` to enable them; see the bottom section.
**If `BH_DOMAIN_SKILLS=1` and the task is site-specific, read every file in the matching `$BH_AGENT_WORKSPACE/domain-skills/<site>/` directory before inventing an approach.**
## Usage
View the complete source on GitHubSkills included
- browser-harness
- browser-harness
- browser-harness
Repository facts
- License
- MIT
- Created
- Apr 17, 2026
- Last pushed
- Nov 6, 2026
- Forks
- 1,865
- Open issues
- 60
- Project activity
- Active
Rank over the last 12 weeks
Now #98 · best #90 · down 5 in 30 days
- #98 from Oct 28 to Oct 29
- #99 from Oct 30 to Oct 31
- #97 on Nov 1
- #98 on Nov 2
- #99 on Nov 3
- #98 since Nov 4
24 earlier periods
- #85 on Aug 2
- #89 on Aug 7
- #90 on Aug 8
- #89 on Aug 9
- #90 from Aug 10 to Aug 13
- #91 from Aug 14 to Aug 15
- #90 on Aug 16
- #91 from Aug 17 to Aug 21
- #90 on Aug 22
- #91 on Aug 23
- #90 from Aug 24 to Aug 25
- #91 from Aug 26 to Sep 17
- #92 on Sep 18
- #91 on Sep 19
- #92 from Sep 20 to Oct 3
- #93 from Oct 4 to Oct 5
- #92 on Oct 6
- #93 from Oct 7 to Oct 11
- #94 from Oct 12 to Oct 14
- #95 from Oct 15 to Oct 16
- #96 from Oct 17 to Oct 19
- #97 on Oct 20
- #98 from Oct 21 to Oct 24
- #99 on Oct 25
Before you install
Network or broad shellAutomated signals, not a guarantee
Checked Nov 3, 2026
Not fully analyzed: some files were too long, unreadable or missing. This never lowers the level.
Show 7 notes
SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedbrowser-harness:1Analysis incomplete: Referenced executable target unavailable; not analyzedskills/browser-harness/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedbrowser-harness:1Analysis incomplete: Referenced executable target unavailable; not analyzedsrc/browser_harness/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedsrc/browser_harness/video-template.html:184Analysis incomplete: physical or joined line exceeds character limitsrc/browser_harness/video-template.html:183Analysis incomplete: physical or joined line exceeds character limit
- No broad tool permissions
- 17 dangerous shell commandsin 10 files: agent-workspace/domain-skills/agoda/scraping.md:89 agent-workspace/domain-skills/best-buy/scraping.md:37 browser_harness/admin.py:511 and 7 more
- 4,549 network referencesin 208 files: agent-workspace/domain-skills/bluesky/scraping.md:3 agent-workspace/domain-skills/open-library/scraping.md:3 agent-workspace/domain-skills/chess-com/scraping.md:3 and 205 more
- 11 obfuscation signalsin 10 files: agent-workspace/domain-skills/tcgplayer/scraping.md:67 agent-workspace/domain-skills/feishu/docx-scraping.md:110 agent-workspace/domain-skills/github/scraping.md:129 and 7 more
- No instruction overrides
- 41 executable scriptsin 37 files: browser-harness:1 agent-workspace/agent_helpers.py:1 agent-workspace/domain-skills/browser-use-cloud/cleanup-zombies.py:1 and 34 more
- 220 references to secretsin 55 files: agent-workspace/domain-skills/metacritic/scraping.md:14 browser_harness/auth.py:83 agent-workspace/domain-skills/nasa/scraping.md:14 and 52 more
- No requests to vote in Hot
Show all 4,838 signals by file
.claude-plugin/marketplace.json
- Network accessline 4
"owner": { "name": "Browser Use", "url": "https://browser-use.com" - Network accessline 5
"name": "Browser Use", "url": "https://browser-use.com" }, - Network accessline 6
"url": "https://browser-use.com" - Network accessline 12
"category": "automation", "source": ".", "homepage": "https://github.com/browser-use/browser-harness", - Network accessline 13
"source": ".", "homepage": "https://github.com/browser-use/browser-harness", "keywords": [ - Network accessline 14
"homepage": "https://github.com/browser-use/browser-harness",
.claude-plugin/plugin.json
- Network accessline 5
"author": { "name": "Browser Use", "url": "https://browser-use.com" - Network accessline 6
"name": "Browser Use", "url": "https://browser-use.com" }, - Network accessline 7
"url": "https://browser-use.com" - Network accessline 8
}, "homepage": "https://github.com/browser-use/browser-harness", "repository": "https://github.com/browser-use/browser-harness", - Network accessline 9
"homepage": "https://github.com/browser-use/browser-harness", - Network accessline 10
"repository": "https://github.com/browser-use/browser-harness",
.env.example
.github/ISSUE_TEMPLATE/config.yml
- Network accessline 2
contact_links: - name: Question or how-to url: https://github.com/browser-use/browser-harness/discussions/categories/q-a - Network accessline 3
- name: Question or how-to url: https://github.com/browser-use/browser-harness/discussions/categories/q-a about: Ask in Discussions Q&A, not Issues. - Network accessline 4
url: https://github.com/browser-use/browser-harness/discussions/categories/q-a - Network accessline 5
about: Ask in Discussions Q&A, not Issues. - name: Install or setup troubleshooting url: https://github.com/browser-use/browser-harness/blob/main/install.md - Network accessline 6
- name: Install or setup troubleshooting url: https://github.com/browser-use/browser-harness/blob/main/install.md about: Most install and "DevTools not live" errors are covered here. - Network accessline 7
url: https://github.com/browser-use/browser-harness/blob/main/install.md
.github/VOUCHED.td
.gitignore
- Access to secretsline 4
[Credential-related source omitted]
AGENTS.md
- Access to secretsline 51
[Credential-related source omitted]
README.md
- Network accessline 1
<img src="https://raw.githubusercontent.com/browser-use/media/main/browser-harness/banner-ink.svg" alt="Browser Harness" width="100%" /> - Network accessline 7
Try browser-harness in [Browser Use Cloud](https://cloud.browser-use.com/v4?utm_campaign=browser-harness-use-in-cloud&utm_source=github) or paste the setup prompt into your coding agent. - Network accessline 25
[](https://browser-use.com/showcase/videos/download-latest-20-x-videos.mp4) - Network accessline 32
Install or upgrade browser-harness to the latest stable version with uv using Python 3.12, register the skill from `browser-harness skill`, and connect it to my browser. Ask whether I want local browser recordings enabled; default to no and - Network accessline 58
Matched eval by Browser Use on 100 of the 200 public [BU Bench V2.1](https://github.com/browser-use/benchmark) tasks (bu2-001 to bu2-100; 101-200 not run). Measured 2026-10-14. - Network accessline 78
Measured with Codex only. Claude Code, Cursor, Playwright CLI and Claude in Chrome were not measured. Method and per-task scores: [coding-agent-browser-tools.json](https://browser-use.com/benchmarks/coding-agent-browser-tools.json). - Network accessline 91
Use your local browser for logged-in, personal work. When you want many browsers in parallel, with live previews, proxies, stealth, CAPTCHA solving, and more, scale with [Browser Use Cloud](https://cloud.browser-use.com/new-api-key). - Network accessline 102
Add this to `.cursor/mcp.json` in your project, or to `~/.cursor/mcp.json` for every project. It needs [uv](https://docs.astral.sh/uv/). - Network accessline 103
every project. It needs [uv](https://docs.astral.sh/uv/). - Network accessline 123
[The Bitter Lesson of Agent Harnesses](https://browser-use.com/posts/bitter-lesson-agent-harnesses) · [Web Agents That Actually Learn](https://browser-use.com/posts/web-agents-that-actually-learn)
SKILL.md
- Network accessline 1
--- name: browser-harness description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." - Network accessline 2
name: browser-harness description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." --- - Network accessline 3
description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." - Network accessline 8
Direct browser control via CDP. For task-specific edits, use `agent-workspace/agent_helpers.py`. For setup, install, or connection problems, read https://github.com/browser-use/browser-harness/blob/main/install.md. - Access to secretsline 143
[Credential-related source omitted] - Network accessline 150
You can also direct the user to try the same agent behind Browser Harness, fully hosted, in Browser Use Cloud (it's called the v4 agent): https://cloud.browser-use.com?utm_source=skill&utm_medium=browser-use&utm_campaign=v4. - Access to secretsline 161
[Credential-related source omitted] - Network accessline 171
BU_NAME=r7k2 browser-harness <<'PY' new_tab("https://example.com") - Network accessline 172
new_tab("https://example.com") - Network accessline 183
Cloud profile cookie sync reference: https://github.com/browser-use/browser-harness/blob/main/interaction-skills/profile-sync.md. - Network accessline 223
Use it only if timestamps and pages match; otherwise say the work was not captured. Never reenact a completed task. For a video, follow [make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.m - Network accessline 224
captured. Never reenact a completed task. For a video, follow [make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.md). If sub-agents are available, they may handle post-production from the - Network accessline 225
[make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.md). - Network accessline 231
If you get stuck on a browser mechanic, check https://github.com/browser-use/browser-harness/tree/main/interaction-skills.
agent-workspace/agent_helpers.py
- Executable scriptline 1
Executable file
agent-workspace/domain-skills/BOSS-zhipin/chat.md
- Network accessline 191
"uid": 502838021, # sender user ID "name": "张女士", "avatar": "https://img.bosszhipin.com/..." - Network accessline 192
"name": "张女士", "avatar": "https://img.bosszhipin.com/..." }, - Network accessline 193
"avatar": "https://img.bosszhipin.com/..." - Network accessline 226
"uid": 3872648, "name": "刘女士", "avatar": "https://img.bosszhipin.com/..." - Network accessline 227
"name": "刘女士", "avatar": "https://img.bosszhipin.com/..." }, - Network accessline 228
"avatar": "https://img.bosszhipin.com/..." - Network accessline 242
(async function() {{ var url = '/wapi/zpchat/geek/historyMsg?bossId={boss_id}&maxMsgId=0&c={count}&page={page}&src=0'; var r = await fetch(url); - Network accessline 243
var url = '/wapi/zpchat/geek/historyMsg?bossId={boss_id}&maxMsgId=0&c={count}&page={page}&src=0'; var r = await fetch(url); var d = await r.json(); - Network accessline 244
var r = await fetch(url); - Network accessline 289
raw = js(f""" (async function() {{ var r = await fetch('/wapi/zpchat/geek/historyMsg?bossId={boss_id}&maxMsgId={max_msg_id}&c=20&page=1&src=0'); - Network accessline 290
(async function() {{ var r = await fetch('/wapi/zpchat/geek/historyMsg?bossId={boss_id}&maxMsgId={max_msg_id}&c=20&page=1&src=0'); var d = await r.json(); - Network accessline 291
var r = await fetch('/wapi/zpchat/geek/historyMsg?bossId={boss_id}&maxMsgId={max_msg_id}&c=20&page=1&src=0');
agent-workspace/domain-skills/BOSS-zhipin/job-search.md
- Network accessline 13
[Credential-related source omitted] - Access to secretsline 13
[Credential-related source omitted] - Network accessline 24
goto_url("https://www.zhipin.com/web/geek/jobs?ka=open_joblist") - Network accessline 28
jobs = json.loads(js(""" (async function() { var r = await fetch('/wapi/zpgeek/pc/recommend/job/list.json?page=1&pageSize=15&city=101020100'); - Network accessline 29
(async function() { var r = await fetch('/wapi/zpgeek/pc/recommend/job/list.json?page=1&pageSize=15&city=101020100'); var d = await r.json(); - Network accessline 30
var r = await fetch('/wapi/zpgeek/pc/recommend/job/list.json?page=1&pageSize=15&city=101020100'); - Network accessline 45
| Resource | URL | |----------|-----| | Job search page | `https://www.zhipin.com/web/geek/jobs` | - Network accessline 46
|----------|-----| | Job search page | `https://www.zhipin.com/web/geek/jobs` | | Job search (with prefs) | `https://www.zhipin.com/web/geek/jobs?ka=open_joblist` | - Network accessline 47
| Job search page | `https://www.zhipin.com/web/geek/jobs` | - Network accessline 48
| Job search (with prefs) | `https://www.zhipin.com/web/geek/jobs?ka=open_joblist` | - Network accessline 49
| Job detail page | `https://www.zhipin.com/job_detail/{JOB_ID}.html` | - Network accessline 50
| Company page | `https://www.zhipin.com/gongsi/{COMPANY_ID}~.html` | - Network accessline 101
"bossTitle": "人事", "bossOnline": false, "bossAvatar": "https://img.bosszhipin.com/...", - Network accessline 102
"bossOnline": false, "bossAvatar": "https://img.bosszhipin.com/...", "brandLogo": "https://img.bosszhipin.com/...", - Network accessline 103
"bossAvatar": "https://img.bosszhipin.com/...", - Network accessline 104
"brandLogo": "https://img.bosszhipin.com/...", - Network accessline 134
raw = js(f""" (async function() {{ var r = await fetch('/wapi/zpgeek/pc/recommend/job/list.json?{params}'); - Network accessline 135
(async function() {{ var r = await fetch('/wapi/zpgeek/pc/recommend/job/list.json?{params}'); var d = await r.json(); - Network accessline 136
var r = await fetch('/wapi/zpgeek/pc/recommend/job/list.json?{params}'); - Network accessline 183
raw = js(f""" (async function() {{ var r = await fetch('/wapi/zpgeek/job/detail.json?securityId={security_id}'); - Network accessline 184
(async function() {{ var r = await fetch('/wapi/zpgeek/job/detail.json?securityId={security_id}'); var d = await r.json(); - Network accessline 185
var r = await fetch('/wapi/zpgeek/job/detail.json?securityId={security_id}'); - Network accessline 232
raw = js(""" (async function() { var r = await fetch('/wapi/zpgeek/pc/all/filter/conditions.json'); - Network accessline 233
(async function() { var r = await fetch('/wapi/zpgeek/pc/all/filter/conditions.json'); var d = await r.json(); - Network accessline 234
var r = await fetch('/wapi/zpgeek/pc/all/filter/conditions.json'); - Network accessline 340
- **Always prefer the API** — `salaryDesc` returns human-readable salary. DOM salary uses font-encoded PUA chars that require OCR or font-file reversal to decode. - **API needs browser session** — `/wapi/` endpoints require cookies from a r - Network accessline 341
[Credential-related source omitted] - Access to secretsline 341
[Credential-related source omitted]
agent-workspace/domain-skills/BOSS-zhipin/navigation.md
- Network accessline 9
| Page | URL | |------|-----| | Home (redirects to city) | `https://www.zhipin.com/` → `https://www.zhipin.com/{city}/` | - Network accessline 10
|------|-----| | Home (redirects to city) | `https://www.zhipin.com/` → `https://www.zhipin.com/{city}/` | | Job search | `https://www.zhipin.com/web/geek/jobs` | - Network accessline 11
| Home (redirects to city) | `https://www.zhipin.com/` → `https://www.zhipin.com/{city}/` | - Network accessline 12
| Job search | `https://www.zhipin.com/web/geek/jobs` | - Network accessline 13
| Company search | `https://www.zhipin.com/gongsi/` | - Network accessline 14
| Messages / Chat | `https://www.zhipin.com/web/geek/chat` | - Network accessline 15
| Personal center | `https://www.zhipin.com/web/geek/recommend` | - Network accessline 19
| Page | URL | |------|-----| | Campus recruitment | `https://www.zhipin.com/school/` | - Network accessline 20
|------|-----| | Campus recruitment | `https://www.zhipin.com/school/` | | Returnee / Overseas talent | `https://www.zhipin.com/returnee_jobs/` | - Network accessline 21
| Campus recruitment | `https://www.zhipin.com/school/` | - Network accessline 22
| Returnee / Overseas talent | `https://www.zhipin.com/returnee_jobs/` | - Network accessline 23
| Overseas jobs | `https://www.zhipin.com/overseas/` | - Network accessline 24
| Accessibility jobs | `https://www.zhipin.com/accessible_job/` | - Network accessline 25
| Youle (career community) | `https://youle.zhipin.com/recommend/selected/` |
agent-workspace/domain-skills/aa/checkout.md
- Network accessline 7
| Step | URL | Title | | --- | --- | --- | | Home | `https://www.aa.com/` → redirects to `/homePage.do` | American Airlines … | - Network accessline 8
| --- | --- | --- | | Home | `https://www.aa.com/` → redirects to `/homePage.do` | American Airlines … | | Search results (**deep link**) | `https://www.aa.com/booking/search/find-flights?locale=en_US&fareType=Lowest&pax=1&adult=1&type=OneW - Network accessline 9
| Home | `https://www.aa.com/` → redirects to `/homePage.do` | American Airlines … | - Network accessline 10
| Search results (**deep link**) | `https://www.aa.com/booking/search/find-flights?locale=en_US&fareType=Lowest&pax=1&adult=1&type=OneWay&searchType=Revenue&cabin=&carriers=ALL&travelType=personal&slices=<urlencoded JSON>` | Choose flights - Network accessline 11
| After fare select | `https://www.aa.com/booking/choose-flights/1?sid=…` | same | - Network accessline 12
| Trip summary | `https://www.aa.com/booking/your-trip-summary?sid=…` | Your trip summary | - Network accessline 13
| Passenger details (separate Angular app) | `https://www.aa.com/airfare-sales/ui/passenger-ui/?search-journey-id=…&cid=…&sid=…` | Passengers | - Network accessline 14
| Seat map | `https://www.aa.com/booking/passengers/deeplink/airfare-booking/<journey-id>?journey-state-id=<journey-id>&shopping-cart=<cart-id>` | Choose your seat | - Network accessline 15
| Trip extras | `https://www.aa.com/ancillaries/offers/storefront/2/<cart-id>` | Trip extras | - Network accessline 16
| Checkout / payment | `https://www.aa.com/ecommerce/checkout-app/cart/<cart-id>` | American Airlines Checkout |
agent-workspace/domain-skills/agentlist/discovery.md
- Network accessline 3
`https://agentlist.com` — public directory of skills, agents, MCPs, configs, and paid services. Field-tested with browser-harness on 2026-05-03. - Network accessline 12
listings = json.loads(http_get("https://agentlist.com/api/listings?category=skill&q=github&limit=10")) - Network accessline 26
# Search everything items = json.loads(http_get("https://agentlist.com/api/listings?q=github&limit=10")) - Network accessline 27
items = json.loads(http_get("https://agentlist.com/api/listings?q=github&limit=10")) - Network accessline 29
# Filter by category skills = json.loads(http_get("https://agentlist.com/api/listings?category=skill&q=browser&limit=10")) - Network accessline 30
skills = json.loads(http_get("https://agentlist.com/api/listings?category=skill&q=browser&limit=10")) - Network accessline 31
agents = json.loads(http_get("https://agentlist.com/api/listings?category=agent&limit=10")) - Network accessline 32
mcps = json.loads(http_get("https://agentlist.com/api/listings?category=mcp&limit=10")) - Network accessline 33
configs = json.loads(http_get("https://agentlist.com/api/listings?category=config&limit=10")) - Network accessline 34
paid = json.loads(http_get("https://agentlist.com/api/listings?category=paid&limit=10")) - Network accessline 36
# Sort and paginate new_items = json.loads(http_get("https://agentlist.com/api/listings?sort=new&skip=0&limit=20")) - Network accessline 37
new_items = json.loads(http_get("https://agentlist.com/api/listings?sort=new&skip=0&limit=20")) - Network accessline 38
top_items = json.loads(http_get("https://agentlist.com/api/listings?sort=top&limit=20")) - Network accessline 39
trending_items = json.loads(http_get("https://agentlist.com/api/listings?sort=trending&limit=20")) - Network accessline 41
# Fetch one listing listing = json.loads(http_get("https://agentlist.com/api/listings/6ea8f4f2-83cf-4625-a3cd-98b49d49a7b2")) - Network accessline 42
listing = json.loads(http_get("https://agentlist.com/api/listings/6ea8f4f2-83cf-4625-a3cd-98b49d49a7b2")) - Network accessline 57
skill_md = http_get("https://agentlist.com/raw/6ea8f4f2-83cf-4625-a3cd-98b49d49a7b2") - Network accessline 63
skill_md = http_get("https://skills.agentlist.com/skill/6ea8f4f2-83cf-4625-a3cd-98b49d49a7b2/SKILL.md") - Network accessline 69
https://skills.agentlist.com/skill/{id}/ - Network accessline 75
new_tab("https://agentlist.com") - Network accessline 127
""") wait(1) print(page_info()) # URL becomes https://agentlist.com/?q=github - Network accessline 129
print(page_info()) # URL becomes https://agentlist.com/?q=github - Network accessline 137
https://agentlist.com/listing/{id} - Network accessline 143
new_tab("https://agentlist.com/listing/6ea8f4f2-83cf-4625-a3cd-98b49d49a7b2") - Network accessline 163
https://agentlist.com/submit
agent-workspace/domain-skills/agoda/scraping.md
- Network accessline 27
def city_id(slug): """slug like 'bangkok-th' or 'tokyo-jp' (the /city/<slug>.html landing page).""" url = f"https://www.agoda.com/city/{slug}.html" - Network accessline 28
"""slug like 'bangkok-th' or 'tokyo-jp' (the /city/<slug>.html landing page).""" url = f"https://www.agoda.com/city/{slug}.html" deadline, delay = time.time() + 120, 5 # one deadline for every attempt and backoff - Network accessline 29
url = f"https://www.agoda.com/city/{slug}.html" - Network accessline 31
while True: try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Language": "en-US"}) - Network accessline 32
try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Language": "en-US"}) with urllib.request.urlopen(req, timeout=max(1, min(30, deadline - time.time()))) as r: - Network accessline 33
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Language": "en-US"}) - Network accessline 34
with urllib.request.urlopen(req, timeout=max(1, min(30, deadline - time.time()))) as r: - Network accessline 71
params = {"city": CITY_ID, "checkIn": check_in, "los": 2, "rooms": 1, "adults": 2, "children": 0, "locale": "en-us", "currency": "USD"} SEARCH_URL = "https://www.agoda.com/search?" + urllib.parse.urlencode(params) - Network accessline 73
SEARCH_URL = "https://www.agoda.com/search?" + urllib.parse.urlencode(params) - Dangerous shell operationline 89
const rm = rev && ((rev.getAttribute('aria-label') || '') + ' ' + rev.innerText) - Dangerous shell operationline 98
review_score: rm ? parseFloat(rm[1]) : null, - Dangerous shell operationline 99
review_count: rm ? parseInt(rm[2].replace(/,/g, '')) : null, - Network accessline 265
search: https://www.agoda.com/search?city=9395&checkIn=2026-11-23&los=2&rooms=1&adults=2&children=0&locale=en-us¤cy=USD&ds=zr2H4S2qsZq8000i - Network accessline 268
Page 3 of 75: 97 properties unique 293 duplicates dropped 0 {'hotel_id': '51238093', 'name': 'Maison Hotel Bangkok', 'stars': 5, 'review_score': 8.9, 'review_count': 9464, 'price': 72, 'currency': 'USD', 'sold_out': False, 'promoted': False - Network accessline 269
unique 293 duplicates dropped 0 {'hotel_id': '51238093', 'name': 'Maison Hotel Bangkok', 'stars': 5, 'review_score': 8.9, 'review_count': 9464, 'price': 72, 'currency': 'USD', 'sold_out': False, 'promoted': False, 'area': 'Sukhumvit, Bangko - Network accessline 270
{'hotel_id': '51238093', 'name': 'Maison Hotel Bangkok', 'stars': 5, 'review_score': 8.9, 'review_count': 9464, 'price': 72, 'currency': 'USD', 'sold_out': False, 'promoted': False, 'area': 'Sukhumvit, Bangkok - City center', 'url': 'https: - Network accessline 283
HOTEL_URLS = [ # any `url` values from the search rows "https://www.agoda.com/bless-residence/hotel/bangkok-th.html", - Network accessline 284
"https://www.agoda.com/bless-residence/hotel/bangkok-th.html", - Network accessline 285
"https://www.agoda.com/accom/property?propertyId=14654101", # the other href form - Network accessline 286
"https://www.agoda.com/accom/property?propertyId=14651963", # had no rate for 2026-11-23 when tested; other dates may have one - Network accessline 364
query = dict(urllib.parse.parse_qsl(u.query), **STAY) target = u._replace(query=urllib.parse.urlencode(query)).geturl() if current_tab()["url"].startswith("https://www.agoda.com/"): - Network accessline 365
target = u._replace(query=urllib.parse.urlencode(query)).geturl() if current_tab()["url"].startswith("https://www.agoda.com/"): goto_url(target) # reuse this skill's own Agoda tab - Network accessline 366
if current_tab()["url"].startswith("https://www.agoda.com/"): - Network accessline 410
"jsonld_loaded": true, "name": "The Bless Hotel & Residence", "url": "https://www.agoda.com/bless-residence/hotel/bangkok-th.html", - Network accessline 411
"name": "The Bless Hotel & Residence", "url": "https://www.agoda.com/bless-residence/hotel/bangkok-th.html", "stars": 4, - Network accessline 412
"url": "https://www.agoda.com/bless-residence/hotel/bangkok-th.html", - Network accessline 447
"Airport transfer" ], "image": "https://pix8.agoda.net/hotelImages/177997/-1/794165056d07deceb10d1f2d79f00e4c.jpg?ce=0&s=1024x768", - Network accessline 448
], "image": "https://pix8.agoda.net/hotelImages/177997/-1/794165056d07deceb10d1f2d79f00e4c.jpg?ce=0&s=1024x768", "description": "Experience Comfort and Convenience at The Bless Hotel & Residence, BangkokNestle..." - Network accessline 449
"image": "https://pix8.agoda.net/hotelImages/177997/-1/794165056d07deceb10d1f2d79f00e4c.jpg?ce=0&s=1024x768", - Network accessline 454
"jsonld_loaded": true, "name": "Madison Bangkok", "url": "https://www.agoda.com/accom/property?propertyId=14651963", - Network accessline 455
"name": "Madison Bangkok", "url": "https://www.agoda.com/accom/property?propertyId=14651963", ... - Network accessline 456
"url": "https://www.agoda.com/accom/property?propertyId=14651963", - Network accessline 478
| `promoted` | card text `"Promoted"` (Agoda says it earns more commission on these) | `false` | | `area` | `[data-selenium="area-city-text"]` | `"Sukhumvit, Bangkok - City center"` | | `url` | `a[data-selenium="hotel-name"]` `href`, search - Network accessline 479
| `area` | `[data-selenium="area-city-text"]` | `"Sukhumvit, Bangkok - City center"` | | `url` | `a[data-selenium="hotel-name"]` `href`, search parameters stripped | `https://www.agoda.com/bless-residence/hotel/bangkok-th.html` or `https:// - Network accessline 480
| `url` | `a[data-selenium="hotel-name"]` `href`, search parameters stripped | `https://www.agoda.com/bless-residence/hotel/bangkok-th.html` or `https://www.agoda.com/accom/property?propertyId=177997` | - Network accessline 499
| `sold_out` | no "from" bar and an `h2` in `#property-room-grid-root` reading `"Sold out!"` or `"Unavailable on Agoda"` | `false` | | `top_amenities` | `[data-element-name="atf-top-amenities-item"]` | `["Free Wi-Fi", "Swimming pool", ...]` - Network accessline 500
| `top_amenities` | `[data-element-name="atf-top-amenities-item"]` | `["Free Wi-Fi", "Swimming pool", ...]` | | `image` | JSON-LD `image` (protocol-relative, made absolute) | `https://pix8.agoda.net/hotelImages/...` | | `description` | JSON - Network accessline 501
| `image` | JSON-LD `image` (protocol-relative, made absolute) | `https://pix8.agoda.net/hotelImages/...` | - Network accessline 513
- **Review counts disagree.** JSON-LD `aggregateRating.reviewCount` lags the rendered count (12,409 vs 13,034 for the same hotel the same minute; 16,192 vs 17,767 for another). Use the rendered number if you want what users see. - **JSON-LD - Network accessline 514
- **JSON-LD arrives late.** `script[data-selenium="bay-hotel-schema-json-ld"]` is in the DOM empty when the `h1` appears and is filled about 2 s later (0 then 23,163 characters). Reading too early returned `postal`, `lat`, `image` all `null - Network accessline 515
- **JSON-LD `url` on `/accom/property` pages** is the bare `https://www.agoda.com/accom/property`, so block 3 rebuilds the URL with `propertyId` there.
agent-workspace/domain-skills/airbnb/monthly-search.md
- Network accessline 6
https://www.airbnb.com/s/San-Francisco--CA--United-States/homes?refinement_paths%5B%5D=%2Fhomes&checkin=2026-10-11&checkout=2026-11-11&adults=2&min_bedrooms=2&room_types%5B%5D=Entire%20home%2Fapt&ne_lat=37.812&ne_lng=-122.405&sw_lat=37.778& - Network accessline 45
`https://www.airbnb.com/rooms/<id>?check_in=..&check_out=..&adults=2` — `document.body.innerText`
agent-workspace/domain-skills/alaska/checkout.md
- Network accessline 7
- **Results deep link (cash mode once toggled)**: `https://www.alaskaair.com/search/results?O={orig}&D={dest}&OD={YYYY-MM-DD}&A=1&C=0&L=0&RT=false`. The site sometimes lands in award/points mode. Flip via the `Money`/`Points` toggle (see se - Network accessline 8
- **Cart**: `https://www.alaskaair.com/search/cart?...` — arrived via `Add to cart` from results. - Network accessline 9
- **Guest info**: `https://www.alaskaair.com/book/guest-info` — arrived via `Continue as guest` from cart. - Network accessline 10
- **Seat selection**: `https://www.alaskaair.com/book/seat-selection`. - Network accessline 11
- **Review & pay**: `https://www.alaskaair.com/book/checkout` — the payment page, card fields live here.
agent-workspace/domain-skills/aliexpress/scraping.md
- Network accessline 26
import email.utils, gzip, http.client, json, re, time, urllib.error, urllib.parse, urllib.request - Network accessline 28
# Truthful client User-Agent; it returned the full search page on 2026-10-23. HEADERS = { "User-Agent": "browser-harness-skill/1.0 (+https://github.com/browser-use/browser-harness)", - Network accessline 29
HEADERS = { "User-Agent": "browser-harness-skill/1.0 (+https://github.com/browser-use/browser-harness)", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - Network accessline 30
"User-Agent": "browser-harness-skill/1.0 (+https://github.com/browser-use/browser-harness)", - Network accessline 45
slug = re.sub(r"[^a-z0-9]+", "-", query.lower()).strip("-") params = {"SearchText": query, "page": page, **({"sortType": sort} if sort else {})} return f"https://www.aliexpress.com/w/wholesale-{slug}.html?{urllib.parse.urlencode(par - Network accessline 47
return f"https://www.aliexpress.com/w/wholesale-{slug}.html?{urllib.parse.urlencode(params)}" # safe="": "/" -> %2F - Network accessline 61
def fetch(url, attempts=4, timeout=30): - Network accessline 65
for attempt in range(1, attempts + 1): try: with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=timeout) as r: - Network accessline 66
try: with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=timeout) as r: body = r.read() - Network accessline 67
with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=timeout) as r: - Network accessline 74
raise # 3xx loop / 4xx: retrying will not help wait, err = retry_after_seconds(e.headers.get("Retry-After")) or delay, e except (urllib.error.URLError, http.client.HTTPException, TimeoutError, Con - Network accessline 75
wait, err = retry_after_seconds(e.headers.get("Retry-After")) or delay, e except (urllib.error.URLError, http.client.HTTPException, TimeoutError, ConnectionError) as e: wait, err = delay, e - Network accessline 76
except (urllib.error.URLError, http.client.HTTPException, TimeoutError, ConnectionError) as e: - Network accessline 157
"sponsored": "p4p" in c, "image": img, "url": f"https://www.aliexpress.com/item/{pid}.html" if pid else None, - Network accessline 158
"image": img, "url": f"https://www.aliexpress.com/item/{pid}.html" if pid else None, }) - Network accessline 159
"url": f"https://www.aliexpress.com/item/{pid}.html" if pid else None, - Network accessline 167
rows, report = {}, {"pages_read": 0, "stopped": None, "totalResults": None} for page in range(1, max_pages + 1): html = fetch(search_url(query, page, sort)) - Network accessline 168
for page in range(1, max_pages + 1): html = fetch(search_url(query, page, sort)) data = parse_init_data(html) - Network accessline 169
html = fetch(search_url(query, page, sort)) - Network accessline 218
price_source: {'card': 102, 'tracking': 64, None: 0} present: {'price': 166, 'original_price': 153, 'sold': 159, 'sold_count': 159, 'rating': 143, 'store_name': 66, 'image': 166} sponsored: 38 {"product_id": "3256813091598934", "title": "IN - Network accessline 219
present: {'price': 166, 'original_price': 153, 'sold': 159, 'sold_count': 159, 'rating': 143, 'store_name': 66, 'image': 166} sponsored: 38 {"product_id": "3256813091598934", "title": "INS Korean Simple Blue Pink Bow Girl Mirror Cute Phone - Network accessline 220
{"product_id": "3256813091598934", "title": "INS Korean Simple Blue Pink Bow Girl Mirror Cute Phone Case For iPhone 17 16 15 Pro Max ...", "price": 1.09, "price_text": "US $1.09", "original_price": 3.73, "currency": "USD", "price_source": " - Network accessline 221
{"product_id": "3256810401258185", "title": "Custom Matte Case For iPhone 17 16 15 14 13 12 11 Pro Max ...", "price": 1.09, "price_text": null, "original_price": 7.71, "currency": "USD", "price_source": "tracking", "welcome_deal": true, "so - Network accessline 234
slug = re.sub(r"[^a-z0-9]+", "-", query.lower()).strip("-") params = {"SearchText": query, "page": page, **({"sortType": sort} if sort else {})} return f"https://www.aliexpress.com/w/wholesale-{slug}.html?{urllib.parse.urlencode(par - Network accessline 236
return f"https://www.aliexpress.com/w/wholesale-{slug}.html?{urllib.parse.urlencode(params)}" - Network accessline 274
rating: n(o(c.evaluation).starRating), store_name: store, sponsored: 'p4p' in c, image: (typeof img === 'string' && img) ? (img.startsWith('//') ? 'https:' + img : img) : null, url: pid ? 'https://www.aliexpress.com/item/' + - Network accessline 275
image: (typeof img === 'string' && img) ? (img.startsWith('//') ? 'https:' + img : img) : null, url: pid ? 'https://www.aliexpress.com/item/' + pid + '.html' : null}; })}); - Network accessline 276
url: pid ? 'https://www.aliexpress.com/item/' + pid + '.html' : null}; - Network accessline 346
163 unique products {'pages_read': 3, 'stopped': 'max_pages=3'} price_source: {'card': 110, 'tracking': 53, None: 0} {"product_id": "3256811701939685", "title": "Red Cherry Pattern Mirror Phone Case For iPhone 17 Pro Max ...", "price": 1.09 - Network accessline 348
{"product_id": "3256811701939685", "title": "Red Cherry Pattern Mirror Phone Case For iPhone 17 Pro Max ...", "price": 1.09, "price_text": null, "original_price": 3.54, "currency": "USD", "price_source": "tracking", "welcome_deal": true, "s - Network accessline 384
pass try: goto_url(f"https://www.aliexpress.com/item/{product_id}.html") - Network accessline 385
try: goto_url(f"https://www.aliexpress.com/item/{product_id}.html") except TimeoutError: # IPC timeout; the navigation may still be running - Network accessline 386
goto_url(f"https://www.aliexpress.com/item/{product_id}.html") - Network accessline 509
new_tab() ids = search_ids("https://www.aliexpress.com/w/wholesale-mechanical-keyboard.html?SearchText=mechanical+keyboard") - Network accessline 510
ids = search_ids("https://www.aliexpress.com/w/wholesale-mechanical-keyboard.html?SearchText=mechanical+keyboard") - Network accessline 538
"title": "AJAZZ AK820 and AK820PRO Mechanical Gaming Keyboard 75% Layout PBT OEM Keycap RGB Backlight Full Key Anti-Ghosting Type-C", "rating": "4.9", "reviews": 5048, "sales_text": "This seller: 700+ sales | Total sales: 10,000+", "store - Network accessline 539
"rating": "4.9", "reviews": 5048, "sales_text": "This seller: 700+ sales | Total sales: 10,000+", "store_name": "Stone's Store", "store_url": "https://www.aliexpress.com/store/1103576287", "store_positive_rate": "100.0", "store_open_since - Network accessline 540
"store_name": "Stone's Store", "store_url": "https://www.aliexpress.com/store/1103576287", - Network accessline 578
| `store_name` | `trace.custom.p4pExtendParam` (JSON string) `.store_name` | `"Shop1105082514 Store"` | 66 of 166 | | `sponsored` | `"p4p" in card` | `true` | boolean, 38 of 166 true | | `image` | `image.imgUrl`, protocol-relative made `htt - Network accessline 579
| `sponsored` | `"p4p" in card` | `true` | boolean, 38 of 166 true | | `image` | `image.imgUrl`, protocol-relative made `https:` | `https://ae-pic-a1.aliexpress-media.com/kf/...jpg` | 166 of 166 | | `url` | built from `productId` (`None` if - Network accessline 580
| `image` | `image.imgUrl`, protocol-relative made `https:` | `https://ae-pic-a1.aliexpress-media.com/kf/...jpg` | 166 of 166 | - Network accessline 581
| `url` | built from `productId` (`None` if no id) | `https://www.aliexpress.com/item/<id>.html` | 166 of 166 | - Network accessline 629
[Credential-related source omitted] - Access to secretsline 629
[Credential-related source omitted]
agent-workspace/domain-skills/amazon/order-history.md
- Network accessline 28
new_tab("https://www.amazon.co.uk/your-orders/orders?timeFilter=year-2025&startIndex=0")
agent-workspace/domain-skills/amazon/product-search.md
- Network accessline 10
goto_url("https://www.amazon.com/s?k=mechanical+keyboard") - Network accessline 17
goto_url("https://www.amazon.com") - Network accessline 32
# URL pattern: /dp/{ASIN} or /dp/{ASIN}?th=1 (Amazon may redirect to add ?th=1) goto_url("https://www.amazon.com/dp/B08Z6X4NK3") - Network accessline 33
goto_url("https://www.amazon.com/dp/B08Z6X4NK3") - Network accessline 45
tid = new_tab("https://www.amazon.com/s?k=mechanical+keyboard") - Network accessline 116
URL: `https://www.amazon.com/Best-Sellers-{Category}/zgbs/{slug}/` - Network accessline 117
e.g. `https://www.amazon.com/Best-Sellers-Electronics/zgbs/electronics/` - Network accessline 123
goto_url("https://www.amazon.com/Best-Sellers-Electronics/zgbs/electronics/") - Network accessline 133
title: container.querySelector('img[alt]')?.getAttribute('alt'), price: container.querySelector('.p13n-sc-price, .a-size-base.a-color-price')?.innerText, url: 'https://www.amazon.com/dp/' + el.getAttribute('data-asin') - Network accessline 134
price: container.querySelector('.p13n-sc-price, .a-size-base.a-color-price')?.innerText, url: 'https://www.amazon.com/dp/' + el.getAttribute('data-asin') } - Network accessline 135
url: 'https://www.amazon.com/dp/' + el.getAttribute('data-asin') - Network accessline 153
# Or construct by page number goto_url("https://www.amazon.com/s?k=wireless+mouse&page=2") - Network accessline 154
goto_url("https://www.amazon.com/s?k=wireless+mouse&page=2")
agent-workspace/domain-skills/apartments-com/scraping.md
- Network accessline 12
- Each card carries a `data-listing-share-lines` JSON array (street, city line, beds, baths, rent) plus a phone in `phone-data`. The code keeps the phone only for non-single-home tiers (see "Personal data"). Card amenities only exist on som - Network accessline 14
- The CDN blocks the whole browser session after sustained crawling. Observed: about 40 page loads plus same-origin `fetch()` calls in 25 minutes, then every request (pages and fetch) returned "Access Denied". Keep at least 5 s between page - Network accessline 121
listings, seen, repeats = [], set(), 0 url, page = f"https://www.apartments.com/{CITY}/", 1 - Network accessline 122
url, page = f"https://www.apartments.com/{CITY}/", 1 - Network accessline 169
Output observed on a fresh cloud browser (trimmed). The same code over `kerrville-tx` with `MAX_PAGES = 5` printed `complete: all 2 pages, 65 results` with address, beds, rent and url on 65/65; `alpine-tx` printed `(single page, no pager) 4 - Network accessline 188
"phone": "7372379124", "amenities": "Pets Allowed, Fitness Center, Pool, Walk-In Closets, Clubhouse, Stainless Steel Appliances, Business Center", "url": "https://www.apartments.com/ellwood-at-lake-travis-austin-tx/4v6169l/" - Network accessline 189
"amenities": "Pets Allowed, Fitness Center, Pool, Walk-In Closets, Clubhouse, Stainless Steel Appliances, Business Center", "url": "https://www.apartments.com/ellwood-at-lake-travis-austin-tx/4v6169l/" } - Network accessline 190
"url": "https://www.apartments.com/ellwood-at-lake-travis-austin-tx/4v6169l/" - Network accessline 255
if not PROPERTY_URL: open_page(f"https://www.apartments.com/{CITY}/", first=True) - Network accessline 256
open_page(f"https://www.apartments.com/{CITY}/", first=True) - Network accessline 355
{ "url": "https://www.apartments.com/ellwood-at-lake-travis-austin-tx/4v6169l/", - Network accessline 356
"url": "https://www.apartments.com/ellwood-at-lake-travis-austin-tx/4v6169l/", - Network accessline 423
- **CDN block (Akamai).** Plain HTTP is 403. In the browser, the session got "Access Denied" (title `Access Denied`, an `errors.edgesuite.net` reference) after sustained crawling, and same-origin `fetch()` from the page returned 403 too onc - Network accessline 424
- **Rate limits.** 18 consecutive page navigations at about 4.5 s spacing worked. The block came later in the session after extra rapid `fetch()` calls at 2 s spacing. Keep at least 5 s between loads and keep total volume modest. - Network accessline 437
- Plain HTTP (`http_get`, curl, requests) on any apartments.com URL, including `/robots.txt`: HTTP 403 "Access Denied" from the edge. - Paging past the cap: `/austin-tx/19/` redirects to `/austin-tx/`. - Continuing after a block: once "Acce - Network accessline 438
- Paging past the cap: `/austin-tx/19/` redirects to `/austin-tx/`. - Continuing after a block: once "Access Denied" appeared, the next pages and in-page `fetch()` calls in the same session were also 403, and a single page load about 12 min - Network accessline 439
- Continuing after a block: once "Access Denied" appeared, the next pages and in-page `fetch()` calls in the same session were also 403, and a single page load about 12 minutes later was still "Access Denied". On a block, stop and back off; - Network accessline 440
- Bursts of same-origin `fetch()` calls for other search pages (2 s spacing) were followed shortly by the session block. Plain page navigation at about 4.5 s spacing held up for a full 18-page crawl, so the code above uses it.
agent-workspace/domain-skills/apollo/search-and-lists.md
- Network accessline 5
- Company search: `https://app.apollo.io/#/companies`; people search: `#/people`.
agent-workspace/domain-skills/apple-app-store/scraping.md
- Network accessline 5
robots.txt (checked 2026-10-23): itunes.apple.com disallows `/search*` for all user agents and has no rule that matches `/lookup` (its `/*/lookup?` rule needs a path segment before `lookup`), so it allows the Lookup API; apps.apple.com does - Network accessline 9
- Use the public **iTunes Search/Lookup API** first. No key, no cookies, JSON out: - `https://itunes.apple.com/search?term=...&entity=software&country=us&limit=200` - up to 200 apps per query. - Network accessline 10
- `https://itunes.apple.com/search?term=...&entity=software&country=us&limit=200` - up to 200 apps per query. - Network accessline 11
- `https://itunes.apple.com/lookup?id=ID1,ID2,...&country=us` - many app IDs per call (also `bundleId=` and developer `id=` + `entity=software`). - Network accessline 12
- One API record already has name, developer, average rating, ratings count, price, category, size in bytes, current version, current-version release date and its release notes. - The app page (`https://apps.apple.com/us/app/id<ID>`) adds w - Network accessline 13
- The app page (`https://apps.apple.com/us/app/id<ID>`) adds what the API lacks: 5-to-1 star histogram, top-chart rank, the new age rating (13+, 9+), and the **25 most recent versions** with dates and notes. It is server-rendered JSON in `< - Network accessline 44
def fetch(url, retries=4): - Network accessline 47
for attempt in range(retries): try: req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 48
try: req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 49
req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 50
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 66
def itunes(path, params): """GET https://itunes.apple.com/<path>?<params> and return the parsed JSON object.""" url = f"https://itunes.apple.com/{path}?" + urllib.parse.urlencode(params) # quotes every value, '/' included - Network accessline 67
"""GET https://itunes.apple.com/<path>?<params> and return the parsed JSON object.""" url = f"https://itunes.apple.com/{path}?" + urllib.parse.urlencode(params) # quotes every value, '/' included body = fetch(url) - Network accessline 68
url = f"https://itunes.apple.com/{path}?" + urllib.parse.urlencode(params) # quotes every value, '/' included - Network accessline 69
body = fetch(url) - Network accessline 154
"first_release": "2012-07-18T07:00:00Z", "bundle_id": "com.creditkarma.mobile", "url": "https://apps.apple.com/us/app/intuit-credit-karma/id519817714" - Network accessline 155
"bundle_id": "com.creditkarma.mobile", "url": "https://apps.apple.com/us/app/intuit-credit-karma/id519817714" } - Network accessline 156
"url": "https://apps.apple.com/us/app/intuit-credit-karma/id519817714" - Network accessline 180
def fetch(url, retries=4): - Network accessline 181
for attempt in range(retries): try: req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 182
try: req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 183
req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 184
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 200
def itunes(path, params): url = f"https://itunes.apple.com/{path}?" + urllib.parse.urlencode(params) - Network accessline 201
url = f"https://itunes.apple.com/{path}?" + urllib.parse.urlencode(params) - Network accessline 202
body = fetch(url) - Network accessline 289
def fetch(url, retries=4): - Network accessline 290
for attempt in range(retries): try: req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 291
try: req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 292
req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 293
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 315
def app_page(app_id, country="us"): """Extras only the web page has. None if the app does not exist (HTTP 404); raises on anything else odd.""" url = f"https://apps.apple.com/{country}/app/id{app_id}" - Network accessline 316
"""Extras only the web page has. None if the app does not exist (HTTP 404); raises on anything else odd.""" url = f"https://apps.apple.com/{country}/app/id{app_id}" html = fetch(url) - Network accessline 317
url = f"https://apps.apple.com/{country}/app/id{app_id}" html = fetch(url) if html is None: - Network accessline 318
html = fetch(url) - Network accessline 388
def open_app(app_id, first_tab, timeout=30): """Navigate, then wait until location.href is the requested app and the document is complete.""" url = f"https://apps.apple.com/us/app/id{app_id}" - Network accessline 389
"""Navigate, then wait until location.href is the requested app and the document is complete.""" url = f"https://apps.apple.com/us/app/id{app_id}" new_tab(url) if first_tab else goto_url(url) - Network accessline 390
url = f"https://apps.apple.com/us/app/id{app_id}" - Network accessline 405
EXTRACT = r"""(async (url, appId) => { const res = await fetch(url, {credentials: 'omit'}); - Network accessline 406
const res = await fetch(url, {credentials: 'omit'}); - Network accessline 427
"""Page extras for app_id via an in-page fetch. None on HTTP 404; retries 429/5xx and browser timeouts with backoff (no sleep after the last try), then raises. 403 and other statuses raise at once.""" url, out = f"https://apps.apple - Network accessline 428
with backoff (no sleep after the last try), then raises. 403 and other statuses raise at once.""" url, out = f"https://apps.apple.com/us/app/id{app_id}", None for attempt in range(retries): - Network accessline 429
url, out = f"https://apps.apple.com/us/app/id{app_id}", None - Network accessline 461
310633997 https://apps.apple.com/us/app/whatsapp-messenger/id310633997 {"status": 200, "incomplete": false, "name": "WhatsApp Messenger", "rating": 4.7, "ratings_count": 18827914, "stars_5_to_1": [15891698, 1461031, 570089, 256170, 648926], - Network accessline 462
1586435171 https://apps.apple.com/us/app/actions/id1586435171 {"status": 200, "incomplete": false, "name": "Actions", "rating": 4.8, "ratings_count": 515, "stars_5_to_1": [469, 20, 8, 1, 17], "chart_rank": null, "age_rating": "4+", "size": - Network accessline 518
- Version history dates on the page are JS `Date.toString()` strings ("Mon Oct 19 2026 12:27:02 GMT+0000 ..."), not ISO. The API's `currentVersionReleaseDate` is ISO. - Only the 25 most recent versions are embedded (all 5 apps tested had ex - Network accessline 519
- Only the 25 most recent versions are embedded (all 5 apps tested had exactly 25). Older versions are not on the page, so 25 means "maybe more", not "all". - `https://apps.apple.com/us/app/id<ID>` works without the slug and redirects to th - Network accessline 520
- `https://apps.apple.com/us/app/id<ID>` works without the slug and redirects to the slugged URL. Match the tab URL on `/id<ID>`, not on the exact URL you navigated to. - No consent banner or login wall appeared on US app pages. - Plain HTT - Network accessline 526
- **Web search page** for scale: `https://apps.apple.com/us/iphone/search?term=...` rendered only **11** apps in the browser and scrolling 6 times loaded no more. A plain HTTP GET returns HTTP 200 (about 560 KB) whose `serialized-server-dat
agent-workspace/domain-skills/archive-org/scraping.md
- Network accessline 3
`https://archive.org` / `https://web.archive.org` — all public data, no auth required. Every workflow here is pure `http_get` — no browser needed. - Network accessline 12
# Find snapshots of any URL — primary entry point for Wayback data r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 13
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=iana.org&output=json&limit=5" - Network accessline 14
"https://web.archive.org/cdx/search/cdx" - Network accessline 21
for row in rows[1:]: ts, orig, status, mime, length = row snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 22
ts, orig, status, mime, length = row snap_url = f"https://web.archive.org/web/{ts}/{orig}" print(f"{ts} {status} {snap_url}") - Network accessline 23
snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 30
data = json.loads(http_get("https://archive.org/metadata/{identifier}", timeout=30.0)) - Network accessline 40
# CDX sort=closest returns the single snapshot nearest to the given timestamp r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 41
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=iana.org&output=json&limit=1" - Network accessline 42
"https://web.archive.org/cdx/search/cdx" - Network accessline 49
# rows[0] = header, rows[1] = closest snapshot ts, orig, status = rows[1] snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 50
ts, orig, status = rows[1] snap_url = f"https://web.archive.org/web/{ts}/{orig}" # Result: ts='20230601114925', orig='https://www.iana.org/', status='200' - Network accessline 51
snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 52
# Result: ts='20230601114925', orig='https://www.iana.org/', status='200' - Network accessline 53
# snap_url: https://web.archive.org/web/20230601114925/https://www.iana.org/ - Network accessline 63
r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 64
"https://web.archive.org/cdx/search/cdx" - Network accessline 72
# rows[0] = header ['timestamp', 'original'] # rows[1:] = one row per month: # ['20230101103807', 'https://www.iana.org/'] - Network accessline 73
# rows[1:] = one row per month: # ['20230101103807', 'https://www.iana.org/'] # ['20230201144829', 'https://www.iana.org/'] - Network accessline 74
# ['20230101103807', 'https://www.iana.org/'] - Network accessline 75
# ['20230201144829', 'https://www.iana.org/'] - Network accessline 78
for ts, orig in rows[1:]: print(f"{ts[:4]}-{ts[4:6]} https://web.archive.org/web/{ts}/{orig}") - Network accessline 79
print(f"{ts[:4]}-{ts[4:6]} https://web.archive.org/web/{ts}/{orig}") - Network accessline 90
# matchType=domain captures all URLs under that domain r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 91
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=iana.org&matchType=domain&output=json" - Network accessline 92
"https://web.archive.org/cdx/search/cdx" - Network accessline 99
for row in rows[1:]: print(row) # ['19971210061738', 'http://www.iana.org:80/', '200'] - Network accessline 100
print(row) # ['19971210061738', 'http://www.iana.org:80/', '200'] # ['19980211065537', 'http://www.iana.org:80/', '200'] - Network accessline 101
# ['19971210061738', 'http://www.iana.org:80/', '200'] - Network accessline 102
# ['19980211065537', 'http://www.iana.org:80/', '200'] - Network accessline 113
# All archived pages under /domains/ path r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 114
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=iana.org/domains/&matchType=prefix&output=json" - Network accessline 115
"https://web.archive.org/cdx/search/cdx" - Network accessline 121
for row in rows[1:]: print(row) # ['20080509121811', 'http://www.iana.org/domains/', '200'] - Network accessline 122
print(row) # ['20080509121811', 'http://www.iana.org/domains/', '200'] # ['20080704174537', 'http://iana.org/domains/', '200'] - Network accessline 123
# ['20080509121811', 'http://www.iana.org/domains/', '200'] - Network accessline 124
# ['20080704174537', 'http://iana.org/domains/', '200'] - Network accessline 134
"""Iterate all CDX records for a URL, yielding rows (excluding header).""" base = ( f"https://web.archive.org/cdx/search/cdx" - Network accessline 135
base = ( f"https://web.archive.org/cdx/search/cdx" f"?url={quote(url, safe='')}&output=json" - Network accessline 136
f"https://web.archive.org/cdx/search/cdx" - Network accessline 163
# Direct snapshot URL: /web/{14-digit-timestamp}/{original-url} snap_url = "https://web.archive.org/web/19971210061738/http://www.iana.org:80/" - Network accessline 164
snap_url = "https://web.archive.org/web/19971210061738/http://www.iana.org:80/" - Network accessline 169
# The calendar view URL pattern (for browser navigation, not http_get): # https://web.archive.org/web/20230101000000*/python.org - Network accessline 170
# https://web.archive.org/web/20230101000000*/python.org - Network accessline 180
identifier = "HardWonWisdomTrailer" data = json.loads(http_get(f"https://archive.org/metadata/{identifier}", timeout=30.0)) - Network accessline 181
data = json.loads(http_get(f"https://archive.org/metadata/{identifier}", timeout=30.0)) - Network accessline 216
from urllib.parse import quote as urlquote # Form 1: direct storage server (fastest) url1 = f"https://{server}{dir_path}/{urlquote(fname)}" - Network accessline 217
# Form 1: direct storage server (fastest) url1 = f"https://{server}{dir_path}/{urlquote(fname)}" # Form 2: standard redirect URL (always works, resolved by CDN) - Network accessline 218
url1 = f"https://{server}{dir_path}/{urlquote(fname)}" # Form 2: standard redirect URL (always works, resolved by CDN) url2 = f"https://archive.org/download/{identifier}/{urlquote(fname)}" - Network accessline 219
# Form 2: standard redirect URL (always works, resolved by CDN) url2 = f"https://archive.org/download/{identifier}/{urlquote(fname)}" # Both confirmed status 200, Content-Type: video/mp4 - Network accessline 220
url2 = f"https://archive.org/download/{identifier}/{urlquote(fname)}" - Network accessline 229
# advancedsearch.php is the correct API — /search returns HTML r = http_get( "https://archive.org/advancedsearch.php" - Network accessline 230
r = http_get( "https://archive.org/advancedsearch.php" "?q=artificial+intelligence+AND+mediatype:texts" - Network accessline 231
"https://archive.org/advancedsearch.php" - Network accessline 258
r = http_get( "https://archive.org/advancedsearch.php" - Network accessline 259
"https://archive.org/advancedsearch.php" - Network accessline 295
| `urlkey` | SURT-format URL (reversed domain, path in parens) | `org,iana)/` | | `timestamp` | Capture time, 14-digit `YYYYMMDDHHMMSS` | `19971210061738` | | `original` | Original crawled URL (exact, including port) | `http://www.iana.org: - Network accessline 296
| `timestamp` | Capture time, 14-digit `YYYYMMDDHHMMSS` | `19971210061738` | | `original` | Original crawled URL (exact, including port) | `http://www.iana.org:80/` | | `mimetype` | Content-Type of the archived response | `text/html` | - Network accessline 297
| `original` | Original crawled URL (exact, including port) | `http://www.iana.org:80/` | - Network accessline 327
- **The `original` field preserves port numbers.** Old crawls captured `http://www.iana.org:80/` — the `:80` is part of the URL. When building a playback URL, use `original` verbatim: `f"https://web.archive.org/web/{ts}/{orig}"` works corre - Network accessline 329
- **Metadata `{}` means the item doesn't exist or is private.** `http_get("https://archive.org/metadata/nonexistent")` returns `'{}'` (2-byte response) with HTTP 200. Always check `if not data` or `if not data.get('metadata')` before access
agent-workspace/domain-skills/articulate-rise/code-blocks.md
- Network accessline 8
authoring https://rise.{instance}.articulate.com/authoring/{courseId}/lesson/{lessonId} - Network accessline 9
preview https://rise.{instance}.articulate.com/preview/{courseId}#/lessons/{lessonId} - Network accessline 135
for (const rule of sheet.cssRules || []) { if (rule instanceof CSSFontFaceRule && /YourFontName/i.test(rule.cssText)) { console.log(rule.cssText); // → src: url('https://articulateusercontent.eu/rise/fonts/...') - Network accessline 136
if (rule instanceof CSSFontFaceRule && /YourFontName/i.test(rule.cssText)) { console.log(rule.cssText); // → src: url('https://articulateusercontent.eu/rise/fonts/...') } - Network accessline 137
console.log(rule.cssText); // → src: url('https://articulateusercontent.eu/rise/fonts/...') - Network accessline 149
@font-face { font-family: 'YourFontName'; src: url('https://articulateusercontent.eu/rise/fonts/{hash}.woff') format('woff'); - Network accessline 150
font-family: 'YourFontName'; src: url('https://articulateusercontent.eu/rise/fonts/{hash}.woff') format('woff'); font-weight: 400; - Network accessline 151
src: url('https://articulateusercontent.eu/rise/fonts/{hash}.woff') format('woff');
agent-workspace/domain-skills/arxiv-bulk/scraping.md
- Network accessline 18
https://oaipmh.arxiv.org/oai - Network accessline 21
`https://export.arxiv.org/oai2` is the old URL — it 301-redirects to the new one. Use the new URL directly to avoid the extra round-trip. - Network accessline 29
OAI_NS = { 'oai': 'http://www.openarchives.org/OAI/2.0/', - Network accessline 30
'oai': 'http://www.openarchives.org/OAI/2.0/', - Network accessline 31
'arXiv': 'http://arxiv.org/OAI/arXiv/', - Network accessline 72
BASE = 'https://oaipmh.arxiv.org/oai' - Network accessline 142
RAW_NS = { 'oai': 'http://www.openarchives.org/OAI/2.0/', - Network accessline 143
'oai': 'http://www.openarchives.org/OAI/2.0/', - Network accessline 144
'raw': 'http://arxiv.org/OAI/arXivRaw/', - Network accessline 147
xml = http_get( "https://oaipmh.arxiv.org/oai" - Network accessline 148
"https://oaipmh.arxiv.org/oai" - Network accessline 175
Base URL: `https://api.semanticscholar.org/graph/v1/` - Network accessline 183
paper = json.loads(http_get( "https://api.semanticscholar.org/graph/v1/paper/arXiv:1706.03762" - Network accessline 184
"https://api.semanticscholar.org/graph/v1/paper/arXiv:1706.03762" - Network accessline 210
body = json.dumps({"ids": ids}).encode() req = urllib.request.Request( - Network accessline 211
req = urllib.request.Request( - Network accessline 212
f"https://api.semanticscholar.org/graph/v1/paper/batch?fields={fields}", - Network accessline 215
method="POST", ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 216
) with urllib.request.urlopen(req, timeout=20) as r: results = json.loads(r.read()) - Network accessline 217
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 228
Note: `helpers.http_get` only does GET. For POST use `urllib.request.Request` directly as above. - Network accessline 236
results = json.loads(http_get( "https://api.semanticscholar.org/graph/v1/paper/search" - Network accessline 237
"https://api.semanticscholar.org/graph/v1/paper/search" - Network accessline 282
if 'v' not in arxiv_id.split('.')[-1] and version: arxiv_id = f"{arxiv_id}v{version}" url = f"https://arxiv.org/pdf/{arxiv_id}" - Network accessline 283
arxiv_id = f"{arxiv_id}v{version}" url = f"https://arxiv.org/pdf/{arxiv_id}" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 284
url = f"https://arxiv.org/pdf/{arxiv_id}" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 285
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 286
with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 300
- **OAI-PMH endpoint moved.** `https://export.arxiv.org/oai2` 301-redirects to `https://oaipmh.arxiv.org/oai`. Use the new URL. `helpers.http_get` (which uses `urllib`) does NOT follow redirects — you'll get an empty string or error. Either - Network accessline 320
- **`http_get` in helpers.py does NOT follow HTTP redirects.** If you must use it with the old OAI URL, you'll get an empty body. Either update the URL to the canonical one or use `urllib.request.urlopen` with a redirect handler.
agent-workspace/domain-skills/arxiv/scraping.md
- Network accessline 3
`https://arxiv.org` — open-access preprint server. **Never use the browser for ArXiv.** All data is reachable via `http_get` using the Atom API or HTML meta tags. No API key required. - Network accessline 13
NS = {'atom': 'http://www.w3.org/2005/Atom', 'arxiv': 'http://arxiv.org/schemas/atom'} - Network accessline 15
xml = http_get("http://export.arxiv.org/api/query?search_query=ti:transformer+AND+cat:cs.LG&max_results=5&sortBy=submittedDate&sortOrder=descending") - Network accessline 22
Use `http_get` on `https://arxiv.org/abs/{id}` + regex for `citation_*` meta tags when you need the full abstract from an HTML page. - Network accessline 32
NS = {'atom': 'http://www.w3.org/2005/Atom', 'arxiv': 'http://arxiv.org/schemas/atom'} - Network accessline 34
xml = http_get( "http://export.arxiv.org/api/query" - Network accessline 35
"http://export.arxiv.org/api/query" - Network accessline 57
# 2604.15259v1 2026-04-16 Stability and Generalization in Looped Transformers # Authors: ['Asher Labovich'] # PDF: https://arxiv.org/pdf/2604.15259v1 - Network accessline 59
# PDF: https://arxiv.org/pdf/2604.15259v1 - Network accessline 68
NS = {'atom': 'http://www.w3.org/2005/Atom', 'arxiv': 'http://arxiv.org/schemas/atom'} - Network accessline 70
xml = http_get("http://export.arxiv.org/api/query?id_list=1706.03762") - Network accessline 82
# Title: Attention Is All You Need # Categories: ['cs.CL', 'cs.LG'] # PDF: https://arxiv.org/pdf/1706.03762v7 - Network accessline 83
# Categories: ['cs.CL', 'cs.LG'] # PDF: https://arxiv.org/pdf/1706.03762v7 # Abstract: The dominant sequence transduction models are based on complex recurrent... - Network accessline 84
# PDF: https://arxiv.org/pdf/1706.03762v7 - Network accessline 96
NS = {'atom': 'http://www.w3.org/2005/Atom'} - Network accessline 98
ids = ['1706.03762', '1810.04805', '2005.14165'] # Transformer, BERT, GPT-3 xml = http_get(f"http://export.arxiv.org/api/query?id_list={','.join(ids)}&max_results={len(ids)}") - Network accessline 99
xml = http_get(f"http://export.arxiv.org/api/query?id_list={','.join(ids)}&max_results={len(ids)}") - Network accessline 114
### Parallel fetch (ThreadPoolExecutor for independent IDs) - Network accessline 123
NS = {'atom': 'http://www.w3.org/2005/Atom'} - Network accessline 125
def fetch_paper(arxiv_id): xml = http_get(f"http://export.arxiv.org/api/query?id_list={arxiv_id}") - Network accessline 126
xml = http_get(f"http://export.arxiv.org/api/query?id_list={arxiv_id}") - Network accessline 153
html = http_get("https://arxiv.org/abs/1706.03762", headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 168
# Confirmed output for 1706.03762: # Title: Attention Is All You Need # PDF: https://arxiv.org/pdf/1706.03762 (no version suffix — always latest) - Network accessline 169
# Title: Attention Is All You Need # PDF: https://arxiv.org/pdf/1706.03762 (no version suffix — always latest) # Authors: ['Vaswani, Ashish', 'Shazeer, Noam', 'Parmar, Niki'] - Network accessline 170
# PDF: https://arxiv.org/pdf/1706.03762 (no version suffix — always latest) - Network accessline 191
NS = { 'atom': 'http://www.w3.org/2005/Atom', - Network accessline 192
'atom': 'http://www.w3.org/2005/Atom', - Network accessline 193
'opensearch': 'http://a9.com/-/spec/opensearch/1.1/', - Network accessline 196
# Page 1 xml = http_get( "http://export.arxiv.org/api/query" - Network accessline 197
xml = http_get( "http://export.arxiv.org/api/query" "?search_query=cat:cs.AI" - Network accessline 198
"http://export.arxiv.org/api/query" - Network accessline 210
# Page 2: increment start xml2 = http_get( "http://export.arxiv.org/api/query" - Network accessline 211
xml2 = http_get( "http://export.arxiv.org/api/query" "?search_query=cat:cs.AI" - Network accessline 212
"http://export.arxiv.org/api/query" - Network accessline 223
http://export.arxiv.org/api/query - Network accessline 226
HTTPS also works: `https://export.arxiv.org/api/query` - Network accessline 259
pdf_versioned = f"https://arxiv.org/pdf/{arxiv_id}" # specific version - Network accessline 260
pdf_latest = f"https://arxiv.org/pdf/{bare_id}" # always redirects to latest - Network accessline 261
abs_versioned = f"https://arxiv.org/abs/{arxiv_id}" - Network accessline 262
abs_latest = f"https://arxiv.org/abs/{bare_id}" - Network accessline 281
Full category taxonomy: https://arxiv.org/category_taxonomy - Network accessline 287
- **Always define the namespace dict.** Without `NS = {'atom': 'http://www.w3.org/2005/Atom', 'arxiv': 'http://arxiv.org/schemas/atom'}`, `findall('atom:entry')` silently returns `[]`. All ArXiv Atom elements live in the `http://www.w3.org/ - Network accessline 291
- **`atom:id` contains a URL, not a bare ID.** The element text is `http://arxiv.org/abs/1706.03762v7` — always split on `/` and take `[-1]` to get the bare ID with version. Strip version with `re.sub(r'v\d+$', '', id)` if needed.
agent-workspace/domain-skills/atlas/overview.md
agent-workspace/domain-skills/bbb/scraping.md
- Network accessline 54
if not all(SLUG.match(p) for p in parts): raise ValueError("slugs must be lowercase-hyphenated, e.g. 'san-francisco', 'plumber'") url = "https://www.bbb.org/" + "/".join(parts) + ("/accredited" if accredited else "") - Network accessline 55
raise ValueError("slugs must be lowercase-hyphenated, e.g. 'san-francisco', 'plumber'") url = "https://www.bbb.org/" + "/".join(parts) + ("/accredited" if accredited else "") if not bbb_open(url): - Network accessline 56
url = "https://www.bbb.org/" + "/".join(parts) + ("/accredited" if accredited else "") - Network accessline 83
"primary_category": r.get("tobText"), "categories": [c["name"] for c in r.get("categories") or []], "profile_url": "https://www.bbb.org" + r["reportUrl"], - Network accessline 84
"categories": [c["name"] for c in r.get("categories") or []], "profile_url": "https://www.bbb.org" + r["reportUrl"], }) - Network accessline 85
"profile_url": "https://www.bbb.org" + r["reportUrl"], - Network accessline 146
"Tankless Water Heaters" ], "profile_url": "https://www.bbb.org/us/ca/san-francisco/profile/plumber/atlas-plumbing-rooter-1116-116593" - Network accessline 147
], "profile_url": "https://www.bbb.org/us/ca/san-francisco/profile/plumber/atlas-plumbing-rooter-1116-116593" } - Network accessline 148
"profile_url": "https://www.bbb.org/us/ca/san-francisco/profile/plumber/atlas-plumbing-rooter-1116-116593" - Network accessline 186
# Profile URLs end in <bbbId>-<businessId>; BBB redirects stale name/city/category slugs to the canonical URL. PROFILE = re.compile(r"^https://www\.bbb\.org/(?:us|ca)/[a-z]{2}/[a-z0-9-]+/profile/[a-z0-9-]+/[a-z0-9-]*-(\d{4}-\d+)/?$") - Network accessline 187
PROFILE = re.compile(r"^https://www\.bbb\.org/(?:us|ca)/[a-z]{2}/[a-z0-9-]+/profile/[a-z0-9-]+/[a-z0-9-]*-(\d{4}-\d+)/?$") - Network accessline 252
print(json.dumps(bbb_profile("https://www.bbb.org/us/ny/new-york/profile/telephones/verizon-communications-0011-1568"), indent=1)) - Network accessline 253
time.sleep(3) moved = bbb_profile("https://www.bbb.org/us/ca/oakland/profile/plumber/atlas-plumbing-rooter-1116-116593") print("redirected:", moved["requested_url"], "->", moved["profile_url"]) - Network accessline 254
moved = bbb_profile("https://www.bbb.org/us/ca/oakland/profile/plumber/atlas-plumbing-rooter-1116-116593") - Network accessline 261
Atlas Plumbing & Rooter A+ acc=True complaints_3y=1 12m=0 reviews=1 site=https://www.atlasplumbingandrooter.com - Network accessline 262
A G Quality Plumbing A+ acc=True complaints_3y=0 12m=0 reviews=1 site=https://www.agqualityplumbing.com/ - Network accessline 263
Jimenez Construction A+ acc=True complaints_3y=0 12m=0 reviews=1 site=https://jimenezconstructionsf.com/ - Network accessline 264
J. E. Brown Mechanical Co., Inc. A+ acc=True complaints_3y=0 12m=0 reviews=0 site=None Mr. Rooter Plumbing of San Francis A+ acc=True complaints_3y=0 12m=0 reviews=0 site=https://www.mrrooter.com/san-francisco/ PARTIAL: enriched 5 of - Network accessline 265
Mr. Rooter Plumbing of San Francis A+ acc=True complaints_3y=0 12m=0 reviews=0 site=https://www.mrrooter.com/san-francisco/ - Network accessline 266
PARTIAL: enriched 5 of 61 rows (LIMIT=5) { "requested_url": "https://www.bbb.org/us/ny/new-york/profile/telephones/verizon-communications-0011-1568", - Network accessline 267
{ "requested_url": "https://www.bbb.org/us/ny/new-york/profile/telephones/verizon-communications-0011-1568", "profile_url": "https://www.bbb.org/us/ny/new-york/profile/telephones/verizon-communications-0011-1568", - Network accessline 268
"requested_url": "https://www.bbb.org/us/ny/new-york/profile/telephones/verizon-communications-0011-1568", - Network accessline 269
"profile_url": "https://www.bbb.org/us/ny/new-york/profile/telephones/verizon-communications-0011-1568", - Network accessline 275
"reviews": 718, "avg_stars": 1.1, "website": "https://www.verizon.com/", - Network accessline 276
"avg_stars": 1.1, "website": "https://www.verizon.com/", "phone": "(800) 779-4116", - Network accessline 277
"website": "https://www.verizon.com/", - Network accessline 281
"jsonld_accreditation": "Not BBB Accredited" } redirected: https://www.bbb.org/us/ca/oakland/profile/plumber/atlas-plumbing-rooter-1116-116593 -> https://www.bbb.org/us/ca/san-francisco/profile/plumber/atlas-plumbing-rooter-1116-116593 - Network accessline 283
redirected: https://www.bbb.org/us/ca/oakland/profile/plumber/atlas-plumbing-rooter-1116-116593 -> https://www.bbb.org/us/ca/san-francisco/profile/plumber/atlas-plumbing-rooter-1116-116593 - Network accessline 291
import http.client, re, time, urllib.error, urllib.request - Network accessline 296
def fetch(url, tries=3): - Network accessline 300
attempt += 1 try: req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 301
try: req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=min(WAIT_S, deadline - time.monotonic())) as r: - Network accessline 302
req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 303
with urllib.request.urlopen(req, timeout=min(WAIT_S, deadline - time.monotonic())) as r: - Network accessline 314
raise RuntimeError(f"{url}: HTTP {e.code}; not retrying") from e err = e # 5xx: retry except (OSError, http.client.HTTPException) as e: - Network accessline 315
err = e # 5xx: retry except (OSError, http.client.HTTPException) as e: err = e # network error or timeout: retry; decode and other errors propagate at once - Network accessline 316
except (OSError, http.client.HTTPException) as e: - Network accessline 324
def state_category_slugs(state): idx = fetch("https://www.bbb.org/sitemap-us-state-categories-index.xml") - Network accessline 325
idx = fetch("https://www.bbb.org/sitemap-us-state-categories-index.xml") - Network accessline 329
slugs, seen_state = [], False for sm in files: locs = re.findall(r"<loc>https://www\.bbb\.org/us/([a-z]{2})/category/([^<]+)</loc>", fetch(sm)) - Network accessline 330
for sm in files: locs = re.findall(r"<loc>https://www\.bbb\.org/us/([a-z]{2})/category/([^<]+)</loc>", fetch(sm)) if not locs: - Network accessline 331
locs = re.findall(r"<loc>https://www\.bbb\.org/us/([a-z]{2})/category/([^<]+)</loc>", fetch(sm)) - Network accessline 368
| `primary_category` | `tobText` | BBB's main "type of business" for the row | | `categories` | `categories[].name` | BBB "type of business" names | | `profile_url` | `reportUrl` | relative path, prefix `https://www.bbb.org`; required; dedu - Network accessline 369
| `categories` | `categories[].name` | BBB "type of business" names | | `profile_url` | `reportUrl` | relative path, prefix `https://www.bbb.org`; required; dedupe key (the same profile appeared twice in one listing with different `id`s) | - Network accessline 370
| `profile_url` | `reportUrl` | relative path, prefix `https://www.bbb.org`; required; dedupe key (the same profile appeared twice in one listing with different `id`s) |
agent-workspace/domain-skills/best-buy/scraping.md
- Dangerous shell operationline 37
const rm = rnr.match(/rating,? ([\d.]+) out of 5 stars with ([\d,]+) review/i); - Dangerous shell operationline 54
rating: rm ? parseFloat(rm[1]) : null, - Dangerous shell operationline 55
review_count: rm ? parseInt(rm[2].replace(/,/g, ''), 10) : (/Not yet reviewed/i.test(card.innerText) ? 0 : null), - Network accessline 117
if page not in ROBOTS_PAGES: raise ValueError(f"page {page}: robots.txt disallows cp={page} for User-agent: *") url = f"https://www.bestbuy.com/site/searchpage.jsp?st={quote_plus(query)}" - Network accessline 118
raise ValueError(f"page {page}: robots.txt disallows cp={page} for User-agent: *") url = f"https://www.bestbuy.com/site/searchpage.jsp?st={quote_plus(query)}" return url if page == 1 else f"{url}&cp={page}" - Network accessline 119
url = f"https://www.bestbuy.com/site/searchpage.jsp?st={quote_plus(query)}" - Network accessline 245
112 unique products; Counter({'in_stock': 110, 'sold_out': 1, 'unavailable': 1}) {"sku": "6687893", "title": "HP - Googlebook 14\" 3K OLED Touchscreen - Snapdragon X Elite - 16GB Memory - 512GB SSD - Atmospheric Blue", "url": "https://www. - Network accessline 246
{"sku": "6687893", "title": "HP - Googlebook 14\" 3K OLED Touchscreen - Snapdragon X Elite - 16GB Memory - 512GB SSD - Atmospheric Blue", "url": "https://www.bestbuy.com/product/hp-googlebook-14-3k-oled-touchscreen-snapdragon-x-elite-16gb- - Network accessline 247
"url": "https://www.bestbuy.com/product/hp-googlebook-14-3k-oled-touchscreen-snapdragon-x-elite-16gb-memory-512gb-ssd-atmospheric-blue/J3PPHVH9QX/sku/6687893", - Network accessline 389
def get_product(sku): # /site/<sku>.p?skuId=<sku> redirects to the canonical /product/<slug>/<code> URL nav(f"https://www.bestbuy.com/site/{sku}.p?skuId={sku}", - Network accessline 390
# /site/<sku>.p?skuId=<sku> redirects to the canonical /product/<slug>/<code> URL nav(f"https://www.bestbuy.com/site/{sku}.p?skuId={sku}", lambda h: urlparse(h).netloc == "www.bestbuy.com" and urlparse(h).path.startswith("/produ - Network accessline 391
nav(f"https://www.bestbuy.com/site/{sku}.p?skuId={sku}", - Network accessline 449
ensure_visible() # Pick a SKU from a live search so this block does not depend on a hard-coded product. nav("https://www.bestbuy.com/site/searchpage.jsp?st=laptop", - Network accessline 450
# Pick a SKU from a live search so this block does not depend on a hard-coded product. nav("https://www.bestbuy.com/site/searchpage.jsp?st=laptop", lambda h: urlparse(h).path == "/site/searchpage.jsp" and parse_qs(urlparse(h).query).get - Network accessline 451
nav("https://www.bestbuy.com/site/searchpage.jsp?st=laptop", - Network accessline 488
"title": "HP - 14\" Laptop - Intel N150 Processor - 4GB Memory - 128GB Storage - Pale Rose Gold", "brand": "HP", "model": "14-dq6105dx", "url": "https://www.bestbuy.com/product/hp-14-laptop-intel-n150-processor-4gb-memory-128gb-storage-pa - Network accessline 489
"brand": "HP", "model": "14-dq6105dx", "url": "https://www.bestbuy.com/product/hp-14-laptop-intel-n150-processor-4gb-memory-128gb-storage-pale-rose-gold/JJGW3FGF9T", "price": 209.99, "price_block_price": 209.99, "regular_price": 349.99, " - Network accessline 490
"url": "https://www.bestbuy.com/product/hp-14-laptop-intel-n150-processor-4gb-memory-128gb-storage-pale-rose-gold/JJGW3FGF9T", - Network accessline 547
- **Lazy price blocks.** One top-to-bottom scroll left some cards unpriced; scrolling each unpriced card into view filled them in (24 of 24 on pages 2 and 3). The retry includes "Unavailable" and "Sold Out" cards, which do get a price block - Network accessline 548
- **Hydration order on product pages.** JSON-LD is there first; the main price block and `_BBY_DATA_.skus` arrive later (the `isPDP` entry took 12-18 s in one trace, and once did not appear within 20 s). A "See all specifications" click bef - Network accessline 549
- **Card shells mean the product API is failing.** In 2 fresh cloud browsers on 2026-10-23, page 1 of `gaming laptop` loaded but 17 and 15 of its 24 cards stayed shells: an `h3` with no title, a link with no `href`, "Not Yet Reviewed", "See - Network accessline 560
- `http_get`, curl or urllib against `www.bestbuy.com` search or product pages: no response before timeout, so plain HTTP is blocked; this skill uses a normal browser session. - Network accessline 561
[Credential-related source omitted]
agent-workspace/domain-skills/bigbang-hr/checkout.md
- Network accessline 7
- Homepage: `https://www.bigbang.hr` - Network accessline 8
- Product: `https://www.bigbang.hr/webshop/<slug>/<sku>` - Network accessline 9
- Cart: `https://www.bigbang.hr/webshop/kosarica/` - Network accessline 10
- Checkout: `https://www.bigbang.hr/webshop/kupac/` (all 3 steps live on this URL — SPA routing)
agent-workspace/domain-skills/bilbasen/search.md
- Network accessline 7
- **Plain HTTP is blocked.** `http_get` / `curl` with a full Chrome UA returns **HTTP 202 with an empty body** (JS bot challenge). Use the user's real browser. - **Search result pages embed every listing on the page as JSON** in `<script id - Network accessline 8
- **Search result pages embed every listing on the page as JSON** in `<script id="__NEXT_DATA__">` (Next.js SSR). No need to scrape cards or scroll. - Search URL pattern: `https://www.bilbasen.dk/brugt/bil/<make>/<model>?pricefrom=<int>&pri - Network accessline 9
- Search URL pattern: `https://www.bilbasen.dk/brugt/bil/<make>/<model>?pricefrom=<int>&priceto=<int>`. Make/model slugs are lowercase (`vw`, `id.4`). The site 302s to an internal model id (`/brugt/bil/vw/id2314`) and appends `includeengros - Network accessline 18
import json new_tab("https://www.bilbasen.dk/brugt/bil/vw/id.4?pricefrom=150000&priceto=195000") - Network accessline 19
new_tab("https://www.bilbasen.dk/brugt/bil/vw/id.4?pricefrom=150000&priceto=195000") - Network accessline 36
|---|---|---| | `externalId` | `6999185` | listing id, also last path segment of `uri` | | `uri` | `https://www.bilbasen.dk/brugt/bil/vw/id4/52-pure-5d/6999185` | detail page | - Network accessline 37
| `externalId` | `6999185` | listing id, also last path segment of `uri` | | `uri` | `https://www.bilbasen.dk/brugt/bil/vw/id4/52-pure-5d/6999185` | detail page | | `price.price` | `169900` | int DKK, use for math; `price.displayPrice` is f - Network accessline 38
| `uri` | `https://www.bilbasen.dk/brugt/bil/vw/id4/52-pure-5d/6999185` | detail page |
agent-workspace/domain-skills/bilibili/navigation.md
- Network accessline 12
| Page | URL | |------|-----| | Home (recommended feed) | `https://www.bilibili.com/` | - Network accessline 13
|------|-----| | Home (recommended feed) | `https://www.bilibili.com/` | | Dynamics (following feed) | `https://t.bilibili.com/` | - Network accessline 14
| Home (recommended feed) | `https://www.bilibili.com/` | - Network accessline 15
| Dynamics (following feed) | `https://t.bilibili.com/` | - Network accessline 16
| Personal space | `https://space.bilibili.com/{UID}` | - Network accessline 17
| Watch history | `https://www.bilibili.com/account/history` | - Network accessline 18
| Watch later | `https://www.bilibili.com/watchlater/#/list` | - Network accessline 19
| Messages | `https://message.bilibili.com/` | - Network accessline 20
| Search | `https://search.bilibili.com/all?keyword={QUERY}` | - Network accessline 24
| Page | URL | |------|-----| | Home (videos + favorites) | `https://space.bilibili.com/{UID}` | - Network accessline 25
|------|-----| | Home (videos + favorites) | `https://space.bilibili.com/{UID}` | | Dynamics (user activity) | `https://space.bilibili.com/{UID}/dynamic` | - Network accessline 26
| Home (videos + favorites) | `https://space.bilibili.com/{UID}` | - Network accessline 27
| Dynamics (user activity) | `https://space.bilibili.com/{UID}/dynamic` | - Network accessline 28
| Uploads | `https://space.bilibili.com/{UID}/upload` | - Network accessline 29
| Collections & series | `https://space.bilibili.com/{UID}/lists` | - Network accessline 30
| Favorites | `https://space.bilibili.com/{UID}/favlist` | - Network accessline 31
| Bangumi tracking | `https://space.bilibili.com/{UID}/bangumi` | - Network accessline 32
| Settings | `https://space.bilibili.com/{UID}/settings` | - Network accessline 36
| Page | URL | |------|-----| | Popular / Hot | `https://www.bilibili.com/v/popular/all` | - Network accessline 37
|------|-----| | Popular / Hot | `https://www.bilibili.com/v/popular/all` | | Weekly must-watch | `https://www.bilibili.com/v/popular/weekly?num={ISSUE}` | - Network accessline 38
| Popular / Hot | `https://www.bilibili.com/v/popular/all` | - Network accessline 39
| Weekly must-watch | `https://www.bilibili.com/v/popular/weekly?num={ISSUE}` | - Network accessline 40
| All-time classics | `https://www.bilibili.com/v/popular/all` (入站必刷 tab) | - Network accessline 41
| Ranking (all) | `https://www.bilibili.com/v/popular/rank/all` | - Network accessline 42
| Topics | `https://www.bilibili.com/v/topic/` | - Network accessline 46
| Aspect | Pattern | |--------|---------| | Watch URL | `https://www.bilibili.com/video/{BV_ID}` | - Network accessline 47
|--------|---------| | Watch URL | `https://www.bilibili.com/video/{BV_ID}` | | BV format | `BV` prefix + 10 alphanumeric chars, e.g. `BV1HeRKBdEoX` | - Network accessline 48
| Watch URL | `https://www.bilibili.com/video/{BV_ID}` | - Network accessline 54
| Page | URL | |------|-----| | Anime | `https://www.bilibili.com/anime/` | - Network accessline 55
|------|-----| | Anime | `https://www.bilibili.com/anime/` | | Movie | `https://www.bilibili.com/movie/` | - Network accessline 56
| Anime | `https://www.bilibili.com/anime/` | - Network accessline 57
| Movie | `https://www.bilibili.com/movie/` | - Network accessline 58
| TV series | `https://www.bilibili.com/tv/` | - Network accessline 59
| Documentary | `https://www.bilibili.com/documentary/` | - Network accessline 60
| Variety show | `https://www.bilibili.com/variety/` | - Network accessline 61
| Chinese animation | `https://www.bilibili.com/guochuang/` | - Network accessline 62
| Read (articles/blogs) | `https://www.bilibili.com/read/home` | - Network accessline 63
| Audio / Music | `https://www.bilibili.com/audio/home` | - Network accessline 64
| Courses (课堂) | `https://www.bilibili.com/cheese/` | - Network accessline 65
| Live | `https://live.bilibili.com/` | - Network accessline 66
| Game center | `https://game.bilibili.com/platform` | - Network accessline 67
| Manga (漫画) | `https://manga.bilibili.com/` | - Network accessline 68
| Mall (会员购) | `https://show.bilibili.com/platform/home.html` | - Network accessline 69
| Esports / Matches | `https://www.bilibili.com/match/home/` | - Network accessline 73
| Page | URL | |------|-----| | Creator center | `https://member.bilibili.com/platform/home` | - Network accessline 74
|------|-----| | Creator center | `https://member.bilibili.com/platform/home` | | Upload video | `https://member.bilibili.com/platform/upload/video/frame` | - Network accessline 75
| Creator center | `https://member.bilibili.com/platform/home` | - Network accessline 76
| Upload video | `https://member.bilibili.com/platform/upload/video/frame` | - Network accessline 80
| Page | URL | |------|-----| | Premium (大会员) | `https://account.bilibili.com/big` | - Network accessline 81
|------|-----| | Premium (大会员) | `https://account.bilibili.com/big` | | Blackroom (bans) | `https://www.bilibili.com/blackroom/ban` | - Network accessline 82
| Premium (大会员) | `https://account.bilibili.com/big` | - Network accessline 83
| Blackroom (bans) | `https://www.bilibili.com/blackroom/ban` | - Network accessline 126
| 动态 | `t.bilibili.com` | Following feed — most important for daily use | | 收藏 | `space.bilibili.com/{UID}/favlist` | Favorite folders | | 历史 | `https://www.bilibili.com/account/history` | Watch history | - Network accessline 127
| 收藏 | `space.bilibili.com/{UID}/favlist` | Favorite folders | | 历史 | `https://www.bilibili.com/account/history` | Watch history | | 创作中心 | `member.bilibili.com/platform/home` | Creator dashboard | - Network accessline 128
| 历史 | `https://www.bilibili.com/account/history` | Watch history |
agent-workspace/domain-skills/bluesky/scraping.md
- Network accessline 3
Field-tested against bsky.app and public.api.bsky.app on 2026-10-31 using a Browser Use cloud browser (logged out; API calls made with `fetch()` from a bsky.app tab) and plain Python urllib. - Network accessline 9
- **No scraping needed.** Logged out, bsky.app itself loads profiles and feeds from `https://public.api.bsky.app/xrpc/<method>` (seen in the tab's resource list: `app.bsky.actor.getProfile`, `app.bsky.feed.getAuthorFeed`, `com.atproto.ident - Network accessline 13
- **Thread for a post URL** (`app.bsky.feed.getPostThread`): the post plus its replies; a handle works inside the `at://` URI. - **Post search does not work logged out.** `app.bsky.feed.searchPosts` returns HTTP 403 from the CDN (plain HTTP - Network accessline 15
- Bluesky's docs (https://bsky.network/docs/rate-limits, fetched 2026-10-31) ask "public web" use cases to use the cached public.api.bsky.app host and call its limits "generous". The blocks pause 0.5 s between calls; about 100 calls today ( - Network accessline 19
All browser blocks share the same helpers: `on_bsky_tab()` attaches a bsky.app tab once (later blocks reuse it), and `xrpc()` runs `fetch()` in that tab. It returns parsed JSON on 200, raises `LookupError` on an XRPC 400 (`Profile not found - Network accessline 28
API = "https://public.api.bsky.app/xrpc/" - Network accessline 43
"""Fetches run inside a logged-out bsky.app tab; reuse it if the attached tab is already there.""" try: if js("location.origin") == "https://bsky.app": - Network accessline 44
try: if js("location.origin") == "https://bsky.app": return - Network accessline 45
if js("location.origin") == "https://bsky.app": - Network accessline 47
except Exception: pass new_tab("https://bsky.app/") - Network accessline 48
pass new_tab("https://bsky.app/") wait_for_load() - Network accessline 49
new_tab("https://bsky.app/") - Network accessline 52
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, body: await r.text()}; } - Network accessline 53
try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, body: await r.text()}; } - Network accessline 82
def profile_row(p): base = {"handle": p["handle"], "did": p["did"], "url": f"https://bsky.app/profile/{p['handle']}"} - Network accessline 83
base = {"handle": p["handle"], "did": p["did"], "url": f"https://bsky.app/profile/{p['handle']}"} - Network accessline 123
"handle": "bsky.app", "did": "did:plc:z72i7hdynmk6r22z27h6tvur", "url": "https://bsky.app/profile/bsky.app", - Network accessline 124
"did": "did:plc:z72i7hdynmk6r22z27h6tvur", "url": "https://bsky.app/profile/bsky.app", "display_name": "Bluesky", - Network accessline 125
"url": "https://bsky.app/profile/bsky.app", "display_name": "Bluesky", "bio": "official Bluesky account (check username👆)\n\nBugs, feature requests, feedback: [email]", - Network accessline 134
"labels": [], "pinned_post": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3l6oveex3ii2l", "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkreihwihm6kpd6zuwhhlro75p5qks5qtrcu55jp3gddbfjsi - Network accessline 135
"pinned_post": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3l6oveex3ii2l", "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkreihwihm6kpd6zuwhhlro75p5qks5qtrcu55jp3gddbfjsieiv7wuka" }, - Network accessline 136
"avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkreihwihm6kpd6zuwhhlro75p5qks5qtrcu55jp3gddbfjsieiv7wuka" - Network accessline 139
"handle": "atproto.com", "did": "did:plc:ewvi7nxzyoun6zhxrhs64oiz", "url": "https://bsky.app/profile/atproto.com", - Network accessline 140
"did": "did:plc:ewvi7nxzyoun6zhxrhs64oiz", "url": "https://bsky.app/profile/atproto.com", "display_name": "AT Protocol Developers", - Network accessline 141
"url": "https://bsky.app/profile/atproto.com", - Network accessline 150
"labels": [], "pinned_post": null, "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:ewvi7nxzyoun6zhxrhs64oiz/bafkreiaihtwfr2d6mjfb6drzaze2gubqtst4ymiwxowqfxpsqxpnz2t33u" - Network accessline 151
"pinned_post": null, "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:ewvi7nxzyoun6zhxrhs64oiz/bafkreiaihtwfr2d6mjfb6drzaze2gubqtst4ymiwxowqfxpsqxpnz2t33u" } - Network accessline 152
"avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:ewvi7nxzyoun6zhxrhs64oiz/bafkreiaihtwfr2d6mjfb6drzaze2gubqtst4ymiwxowqfxpsqxpnz2t33u" - Network accessline 167
API = "https://public.api.bsky.app/xrpc/" - Network accessline 183
"""Fetches run inside a logged-out bsky.app tab; reuse it if the attached tab is already there.""" try: if js("location.origin") == "https://bsky.app": - Network accessline 184
try: if js("location.origin") == "https://bsky.app": return - Network accessline 185
if js("location.origin") == "https://bsky.app": - Network accessline 187
except Exception: pass new_tab("https://bsky.app/") - Network accessline 188
pass new_tab("https://bsky.app/") wait_for_load() - Network accessline 189
new_tab("https://bsky.app/") - Network accessline 192
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, body: await r.text()}; } - Network accessline 193
try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, body: await r.text()}; } - Network accessline 218
def post_url(uri, handle): """at://<did>/app.bsky.feed.post/<rkey> -> https://bsky.app/profile/<handle>/post/<rkey>""" - Network accessline 219
"""at://<did>/app.bsky.feed.post/<rkey> -> https://bsky.app/profile/<handle>/post/<rkey>""" - Network accessline 220
return f"https://bsky.app/profile/{handle}/post/{uri.rsplit('/', 1)[-1]}" - Network accessline 294
{ "kind": "post", "url": "https://bsky.app/profile/atproto.com/post/3mz4m677rsc2o", - Network accessline 295
"kind": "post", "url": "https://bsky.app/profile/atproto.com/post/3mz4m677rsc2o", "uri": "at://did:plc:ewvi7nxzyoun6zhxrhs64oiz/app.bsky.feed.post/3mz4m677rsc2o", - Network accessline 296
"url": "https://bsky.app/profile/atproto.com/post/3mz4m677rsc2o", - Network accessline 334
API = "https://public.api.bsky.app/xrpc/" - Network accessline 349
"""Fetches run inside a logged-out bsky.app tab; reuse it if the attached tab is already there.""" try: if js("location.origin") == "https://bsky.app": - Network accessline 350
try: if js("location.origin") == "https://bsky.app": return - Network accessline 351
if js("location.origin") == "https://bsky.app": - Network accessline 353
except Exception: pass new_tab("https://bsky.app/") - Network accessline 354
pass new_tab("https://bsky.app/") wait_for_load() - Network accessline 355
new_tab("https://bsky.app/") - Network accessline 358
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, body: await r.text()}; } - Network accessline 359
try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, body: await r.text()}; } - Network accessline 401
"verified": (a.get("verification") or {}).get("verifiedStatus") == "valid", "labels": sorted({l["val"] for l in a.get("labels", [])}), "url": f"https://bsky.app/profile/{a['handle']}", - Network accessline 402
"labels": sorted({l["val"] for l in a.get("labels", [])}), "url": f"https://bsky.app/profile/{a['handle']}", }) - Network accessline 403
"url": f"https://bsky.app/profile/{a['handle']}", - Network accessline 429
"verified": true, "labels": [], "url": "https://bsky.app/profile/atproto.com" - Network accessline 430
"labels": [], "url": "https://bsky.app/profile/atproto.com" }, - Network accessline 431
"url": "https://bsky.app/profile/atproto.com" - Network accessline 439
"verified": false, "labels": [], "url": "https://bsky.app/profile/microcosm.blue" - Network accessline 440
"labels": [], "url": "https://bsky.app/profile/microcosm.blue" }, - Network accessline 441
"url": "https://bsky.app/profile/microcosm.blue" - Network accessline 454
POST_URL = "https://bsky.app/profile/atproto.com/post/3mz4m677rsc2o" - Network accessline 458
API = "https://public.api.bsky.app/xrpc/" - Network accessline 473
"""Fetches run inside a logged-out bsky.app tab; reuse it if the attached tab is already there.""" try: if js("location.origin") == "https://bsky.app": - Network accessline 474
try: if js("location.origin") == "https://bsky.app": return - Network accessline 475
if js("location.origin") == "https://bsky.app": - Network accessline 477
except Exception: pass new_tab("https://bsky.app/") - Network accessline 478
pass new_tab("https://bsky.app/") wait_for_load() - Network accessline 479
new_tab("https://bsky.app/") - Network accessline 482
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, body: await r.text()}; } - Network accessline 483
try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, body: await r.text()}; } - Network accessline 508
def to_at_uri(url): """https://bsky.app/profile/<handle-or-did>/post/<rkey> -> at://<handle-or-did>/app.bsky.feed.post/<rkey> - Network accessline 509
"""https://bsky.app/profile/<handle-or-did>/post/<rkey> -> at://<handle-or-did>/app.bsky.feed.post/<rkey> - Network accessline 510
(the AppView resolves a handle in the URI itself).""" m = re.match(r"https://bsky\.app/profile/([^/]+)/post/([^/?#]+)", url) if not m: - Network accessline 511
m = re.match(r"https://bsky\.app/profile/([^/]+)/post/([^/?#]+)", url) - Network accessline 517
rec = post["record"] return { "url": f"https://bsky.app/profile/{post['author']['handle']}/post/{post['uri'].rsplit('/', 1)[-1]}", - Network accessline 518
return { "url": f"https://bsky.app/profile/{post['author']['handle']}/post/{post['uri'].rsplit('/', 1)[-1]}", "author": post["author"]["handle"], - Network accessline 519
"url": f"https://bsky.app/profile/{post['author']['handle']}/post/{post['uri'].rsplit('/', 1)[-1]}", - Network accessline 555
{ "post": { "url": "https://bsky.app/profile/atproto.com/post/3mz4m677rsc2o", - Network accessline 556
"post": { "url": "https://bsky.app/profile/atproto.com/post/3mz4m677rsc2o", "author": "atproto.com", - Network accessline 557
"url": "https://bsky.app/profile/atproto.com/post/3mz4m677rsc2o", - Network accessline 568
"replies": [ { "url": "https://bsky.app/profile/atproto.com/post/3mz4m67ahbs2o", - Network accessline 569
{ "url": "https://bsky.app/profile/atproto.com/post/3mz4m67ahbs2o", "author": "atproto.com", - Network accessline 570
"url": "https://bsky.app/profile/atproto.com/post/3mz4m67ahbs2o", - Dangerous shell operationline 573
"text": "Self-hosters can force an immediate Caddy update with:\n\n sudo pdsadmin update \n\nFor additional confidence, you can disable mptcp system-wide with:\n\n sudo sysctl -w net.mptcp.enabled=0\n\nWe recommend upgrading your system ke - Network accessline 578
}, { "url": "https://bsky.app/profile/<handle>/post/3mz4yxxldg22n", - Network accessline 579
{ "url": "https://bsky.app/profile/<handle>/post/3mz4yxxldg22n", "author": "<handle>", - Network accessline 580
"url": "https://bsky.app/profile/<handle>/post/3mz4yxxldg22n", - Network accessline 588
}, { "url": "https://bsky.app/profile/<handle>/post/3mz4mei4scs2p", - Network accessline 589
{ "url": "https://bsky.app/profile/<handle>/post/3mz4mei4scs2p", "author": "<handle>", - Network accessline 590
"url": "https://bsky.app/profile/<handle>/post/3mz4mei4scs2p", - Network accessline 613
API = "https://public.api.bsky.app/xrpc/" UA = "browser-harness-skill/1.0 (Python urllib)" # truthful client UA - Network accessline 620
for attempt in range(tries): try: with urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": UA}), timeout=30) as r: - Network accessline 621
try: with urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": UA}), timeout=30) as r: time.sleep(PAUSE) - Network accessline 622
with urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": UA}), timeout=30) as r: - Network accessline 676
| `pinned_post` | `pinnedPost.uri` | `at://` URI or null | | `kind` (block 2) | `reason.$type` (`#reasonRepost`, `#reasonPin`), `record.reply`, `post.embed.$type` | `post`, `reply`, `quote`, `repost`, `pin` | | `url` | built from `post.auth - Network accessline 677
| `kind` (block 2) | `reason.$type` (`#reasonRepost`, `#reasonPin`), `record.reply`, `post.embed.$type` | `post`, `reply`, `quote`, `repost`, `pin` | | `url` | built from `post.author.handle` + rkey (last part of `post.uri`) | `https://bsky - Network accessline 678
| `url` | built from `post.author.handle` + rkey (last part of `post.uri`) | `https://bsky.app/profile/<handle>/post/<rkey>`; for a repost it is the original post | - Network accessline 695
- **Handles work inside `at://` URIs** for getPostThread; the error message shows the resolved DID. - **Logged-out visibility.** Accounts can self-label `!no-unauthenticated` to ask not to be shown to logged-out viewers. The blocks skip tho - Network accessline 696
- **Logged-out visibility.** Accounts can self-label `!no-unauthenticated` to ask not to be shown to logged-out viewers. The blocks skip those accounts and replies. None turned up in today's runs, so that branch is untested. - **Failed CORS - Network accessline 697
- **Failed CORS looks like status 0.** The 403 on searchPosts has no CORS header, so `fetch()` in the tab throws `TypeError: Failed to fetch` instead of showing 403. `xrpc()` retries status 0 once, then raises. - Network accessline 703
- **Post search logged out.** `GET https://public.api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=atproto&limit=2` returned HTTP 403 with a plain BunnyCDN "403 Forbidden" HTML page (plain HTTP and in-tab `fetch()`; block 5 shows it). `searchA
agent-workspace/domain-skills/booking-com/scraping.md
- Access to secretsline 14
[Credential-related source omitted] - Network accessline 17
- Enumerate hotel/city/region URLs from XML sitemaps (Googlebot UA required). - Read `robots.txt` for URL pattern documentation. - Query the GraphQL endpoint `https://www.booking.com/dml/graphql` for schema - Network accessline 18
- Read `robots.txt` for URL pattern documentation. - Query the GraphQL endpoint `https://www.booking.com/dml/graphql` for schema exploration (no auth = internal errors, but validation errors reveal the - Network accessline 19
- Query the GraphQL endpoint `https://www.booking.com/dml/graphql` for schema - Network accessline 34
<script src="https://www.booking.com/__challenge_{KEY}/{HASH}/challenge.js"></script> - Network accessline 40
**Variant B (~8,410 bytes) — with AJAX error reporting:** Same AWS WAF SDK, plus an `XMLHttpRequest`-based error reporter that POSTs to `https://reports.booking.com/chal_report`. This variant is more common on - Network accessline 41
Same AWS WAF SDK, plus an `XMLHttpRequest`-based error reporter that POSTs to `https://reports.booking.com/chal_report`. This variant is more common on non-browser UA strings. - Network accessline 42
`https://reports.booking.com/chal_report`. This variant is more common on - Network accessline 85
GOOGLEBOT = {"User-Agent": "Googlebot/2.1 (+http://www.google.com/bot.html)"} - Network accessline 88
"""Returns list of child sitemap URLs from an index sitemap.""" xml = http_get(url, headers=GOOGLEBOT) return re.findall(r'<loc>(https://[^<]+)</loc>', xml) - Network accessline 90
return re.findall(r'<loc>(https://[^<]+)</loc>', xml) - Network accessline 92
def fetch_sitemap_gz(gz_url: str) -> list[str]: """Decompresses a gzipped sitemap and returns all <loc> URLs.""" req = urllib.request.Request(gz_url, headers=GOOGLEBOT) - Network accessline 93
"""Decompresses a gzipped sitemap and returns all <loc> URLs.""" req = urllib.request.Request(gz_url, headers=GOOGLEBOT) with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 94
req = urllib.request.Request(gz_url, headers=GOOGLEBOT) - Network accessline 95
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 97
return re.findall(r'<loc>(https://[^<]+)</loc>', data.decode()) - Network accessline 99
# Example: get all en-gb hotel URLs hotel_idx = http_get( "https://www.booking.com/sitembk-hotel-index.xml", - Network accessline 100
hotel_idx = http_get( "https://www.booking.com/sitembk-hotel-index.xml", headers=GOOGLEBOT - Network accessline 101
"https://www.booking.com/sitembk-hotel-index.xml", - Network accessline 104
# 74 shards for en-gb; each shard has ~45,000-50,000 property URLs en_gb_shards = re.findall( r'<loc>(https://www\.booking\.com/sitembk-hotel-en-gb\.\d+\.xml\.gz)</loc>', - Network accessline 105
en_gb_shards = re.findall( r'<loc>(https://www\.booking\.com/sitembk-hotel-en-gb\.\d+\.xml\.gz)</loc>', hotel_idx - Network accessline 106
r'<loc>(https://www\.booking\.com/sitembk-hotel-en-gb\.\d+\.xml\.gz)</loc>', - Network accessline 127
robots = http_get("https://www.booking.com/robots.txt", headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 136
The endpoint `https://www.booking.com/dml/graphql` is **not WAF-protected**. It accepts POST requests and returns JSON. Without a session, most queries - Network accessline 144
GQL_URL = "https://www.booking.com/dml/graphql?lang=en-gb" - Network accessline 147
"Accept": "application/json", "Content-Type": "application/json", "Origin": "https://www.booking.com", - Network accessline 148
"Content-Type": "application/json", "Origin": "https://www.booking.com", "Referer": "https://www.booking.com/searchresults.html", - Network accessline 149
"Origin": "https://www.booking.com", - Network accessline 150
"Referer": "https://www.booking.com/searchresults.html", - Network accessline 158
if variables: payload["variables"] = variables req = urllib.request.Request( - Network accessline 159
payload["variables"] = variables req = urllib.request.Request( GQL_URL, - Network accessline 160
req = urllib.request.Request( - Network accessline 164
method="POST" ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 165
) with urllib.request.urlopen(req, timeout=20) as r: data = r.read() - Network accessline 166
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 222
### Search Results `https://www.booking.com/searchresults.html` - Network accessline 223
`https://www.booking.com/searchresults.html` - Network accessline 253
### Property Pages `https://www.booking.com/hotel/{country_code}/{hotel_slug}.html` - Network accessline 254
`https://www.booking.com/hotel/{country_code}/{hotel_slug}.html` - Network accessline 258
https://www.booking.com/hotel/{cc}/{slug}.html - Network accessline 259
https://www.booking.com/hotel/{cc}/{slug}.en-gb.html - Network accessline 260
https://www.booking.com/hotel/{cc}/{slug}.{lang}.html - Network accessline 268
https://www.booking.com/city/{cc}/{city-slug}.html - Network accessline 269
https://www.booking.com/region/{cc}/{region-slug}.html - Network accessline 270
https://www.booking.com/country/{cc}.html - Network accessline 283
# Always use new_tab() for the first Booking.com load in a session tid = new_tab("https://www.booking.com/searchresults.html?ss=Paris&checkin=2026-05-01&checkout=2026-05-03&group_adults=2&no_rooms=1&selected_currency=USD") - Network accessline 284
tid = new_tab("https://www.booking.com/searchresults.html?ss=Paris&checkin=2026-05-01&checkout=2026-05-03&group_adults=2&no_rooms=1&selected_currency=USD") - Network accessline 505
# Use after goto_url(): goto_url("https://www.booking.com/searchresults.html?ss=London&checkin=2026-06-01&checkout=2026-06-03&group_adults=2&no_rooms=1") - Network accessline 506
goto_url("https://www.booking.com/searchresults.html?ss=London&checkin=2026-06-01&checkout=2026-06-03&group_adults=2&no_rooms=1") - Network accessline 522
GOOGLEBOT = {"User-Agent": "Googlebot/2.1 (+http://www.google.com/bot.html)"} - Network accessline 524
def get_hotel_urls_for_country(cc: str, lang: str = "en-gb", max_shards: int = 2) -> list[str]: """Returns property page URLs for a country from sitemaps. No browser needed.""" idx_url = f"https://www.booking.com/sitembk-hotel-index - Network accessline 525
"""Returns property page URLs for a country from sitemaps. No browser needed.""" idx_url = f"https://www.booking.com/sitembk-hotel-index.xml" idx = http_get(idx_url, headers=GOOGLEBOT) - Network accessline 526
idx_url = f"https://www.booking.com/sitembk-hotel-index.xml" - Network accessline 527
idx = http_get(idx_url, headers=GOOGLEBOT) pattern = rf'<loc>(https://www\.booking\.com/sitembk-hotel-{lang}\.\d+\.xml\.gz)</loc>' shards = re.findall(pattern, idx)[:max_shards] - Network accessline 528
pattern = rf'<loc>(https://www\.booking\.com/sitembk-hotel-{lang}\.\d+\.xml\.gz)</loc>' - Network accessline 531
urls = [] for shard_url in shards: req = urllib.request.Request(shard_url, headers=GOOGLEBOT) - Network accessline 532
for shard_url in shards: req = urllib.request.Request(shard_url, headers=GOOGLEBOT) with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 533
req = urllib.request.Request(shard_url, headers=GOOGLEBOT) - Network accessline 534
with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 535
xml = gzip.decompress(r.read()).decode() all_urls = re.findall(r'<loc>(https://[^<]+)</loc>', xml) # Filter by country code - Network accessline 536
all_urls = re.findall(r'<loc>(https://[^<]+)</loc>', xml)
agent-workspace/domain-skills/browser-use-cloud/cleanup-zombies.py
- Executable scriptline 1
Executable file - Access to secretsline 8
[Credential-related source omitted] - Access to secretsline 11
[Credential-related source omitted] - Access to secretsline 14
[Credential-related source omitted] - Network accessline 33
API = "https://api.browser-use.com/api/v3" - Access to secretsline 37
[Credential-related source omitted] - Access to secretsline 39
[Credential-related source omitted] - Network accessline 47
def _call(method: str, path: str, body: dict | None = None, timeout: float = 30.0) -> dict: req = urllib.request.Request( - Network accessline 48
req = urllib.request.Request( - Network accessline 52
headers=_headers(), ) with urllib.request.urlopen(req, timeout=timeout) as resp: - Network accessline 53
) with urllib.request.urlopen(req, timeout=timeout) as resp: return json.loads(resp.read() or b"{}") - Network accessline 54
with urllib.request.urlopen(req, timeout=timeout) as resp:
agent-workspace/domain-skills/browser-use-cloud/cloud.md
- Network accessline 3
`https://api.browser-use.com/api/v3` (REST). All five endpoints below were - Access to secretsline 4
[Credential-related source omitted] - Access to secretsline 22
[Credential-related source omitted] - Network accessline 32
All paths are under `https://api.browser-use.com/api/v3`. Verified status - Access to secretsline 116
[Credential-related source omitted] - Access to secretsline 119
[Credential-related source omitted] - Network accessline 152
cookies = cdp("Network.getCookies", urls=["https://cloud.browser-use.com"]) - Network accessline 179
(large profile sync) need their own polling. - **`profile-use` CLI is a separate install**: `curl -fsSL https://browser-use.com/profile.sh | sh`. - Network accessline 180
- **`profile-use` CLI is a separate install**: `curl -fsSL https://browser-use.com/profile.sh | sh`. - **`pageSize` caps at 100** silently — paginate via `pageNumber`. - Dangerous shell operationline 181
`curl -fsSL https://browser-use.com/profile.sh | sh`. - Network accessline 181
`curl -fsSL https://browser-use.com/profile.sh | sh`. - Network accessline 199
Live-tested 2026-05-05 against `https://api.browser-use.com/api/v3`:
agent-workspace/domain-skills/capterra/scraping.md
- Network accessline 17
# Works everywhere: html = http_get( "https://www.capterra.com/p/135003/Slack/reviews/", - Network accessline 18
html = http_get( "https://www.capterra.com/p/135003/Slack/reviews/", headers={"User-Agent": "ClaudeBot"} - Network accessline 19
"https://www.capterra.com/p/135003/Slack/reviews/", - Network accessline 42
slug: URL slug (e.g. 'Slack') """ url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/" - Network accessline 43
""" url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/" html = http_get(url, headers={"User-Agent": "ClaudeBot"}) - Network accessline 44
url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/" - Network accessline 106
Total pages = ceil(review_count / 25). """ url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/?page={page}" - Network accessline 107
""" url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/?page={page}" html = http_get(url, headers={"User-Agent": "ClaudeBot"}) - Network accessline 108
url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/?page={page}" - Dangerous shell operationline 139
rm = re.search(r"\n\n([\d.]+)\n\n", block) - Network accessline 186
def _fetch_page(args): product_id, slug, page = args url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/?page={page}" - Network accessline 187
product_id, slug, page = args url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/?page={page}" html = http_get(url, headers=UA) - Network accessline 188
url = f"https://www.capterra.com/p/{product_id}/{slug}/reviews/?page={page}" - Dangerous shell operationline 198
rm = re.search(r"\n\n([\d.]+)\n\n", block) - Network accessline 211
# First: get total pages summary_html = http_get( f"https://www.capterra.com/p/{product_id}/{slug}/reviews/", - Network accessline 212
summary_html = http_get( f"https://www.capterra.com/p/{product_id}/{slug}/reviews/", headers=UA - Network accessline 213
f"https://www.capterra.com/p/{product_id}/{slug}/reviews/", - Network accessline 240
def get_product_overview(product_id, slug): """Rating breakdown, sentiment, starting price from the product page.""" url = f"https://www.capterra.com/p/{product_id}/{slug}/" - Network accessline 241
"""Rating breakdown, sentiment, starting price from the product page.""" url = f"https://www.capterra.com/p/{product_id}/{slug}/" html = http_get(url, headers={"User-Agent": "ClaudeBot"}) - Network accessline 242
url = f"https://www.capterra.com/p/{product_id}/{slug}/" - Network accessline 270
# Categories ("What is X used for?" links) cats = re.findall(r'\[([^\]]+)\]\(https://www\.capterra\.com/([a-z-]+-software)/\)', html[:3000]) - Network accessline 271
cats = re.findall(r'\[([^\]]+)\]\(https://www\.capterra\.com/([a-z-]+-software)/\)', html[:3000]) - Network accessline 312
List products in a Capterra category. category_slug examples: 'project-management-software', 'crm-software', 'accounting-software' Full list: https://www.capterra.com/categories/ - Network accessline 313
category_slug examples: 'project-management-software', 'crm-software', 'accounting-software' Full list: https://www.capterra.com/categories/ """ - Network accessline 314
Full list: https://www.capterra.com/categories/ - Network accessline 315
""" url = f"https://www.capterra.com/{category_slug}/" if page > 1: - Network accessline 316
url = f"https://www.capterra.com/{category_slug}/" - Network accessline 317
if page > 1: url = f"https://www.capterra.com/{category_slug}/?page={page}" html = http_get(url, headers={"User-Agent": "ClaudeBot"}) - Network accessline 318
url = f"https://www.capterra.com/{category_slug}/?page={page}" - Network accessline 321
# Ratings: [4.6 (5732)](https://www.capterra.com/p/147657/monday-com/reviews/) - Network accessline 322
raw = re.findall( r'\[([\d.]+)\s+\(([\d,]+)\)\]\(https://www\.capterra\.com/p/(\d+)/([^/]+)/reviews/\)', html - Network accessline 323
r'\[([\d.]+)\s+\(([\d,]+)\)\]\(https://www\.capterra\.com/p/(\d+)/([^/]+)/reviews/\)', - Network accessline 326
# Product names from "Learn more about X" links names = {pid: name for name, pid in re.findall( r'\[Learn more about ([^\]]+)\]\(https://www\.capterra\.com/p/(\d+)/[^/]+/\)', html - Network accessline 327
names = {pid: name for name, pid in re.findall( r'\[Learn more about ([^\]]+)\]\(https://www\.capterra\.com/p/(\d+)/[^/]+/\)', html )} - Network accessline 328
r'\[Learn more about ([^\]]+)\]\(https://www\.capterra\.com/p/(\d+)/[^/]+/\)', html - Network accessline 339
"overall_rating": float(rating), "review_count": int(review_count.replace(",", "")), "product_url": f"https://www.capterra.com/p/{pid}/{slug}/", - Network accessline 340
"review_count": int(review_count.replace(",", "")), "product_url": f"https://www.capterra.com/p/{pid}/{slug}/", "reviews_url": f"https://www.capterra.com/p/{pid}/{slug}/reviews/", - Network accessline 341
"product_url": f"https://www.capterra.com/p/{pid}/{slug}/", - Network accessline 342
"reviews_url": f"https://www.capterra.com/p/{pid}/{slug}/reviews/", - Network accessline 360
def get_all_categories(): """Returns list of {name, slug} for all ~1003 Capterra software categories.""" html = http_get("https://www.capterra.com/categories/", headers={"User-Agent": "ClaudeBot"}) - Network accessline 361
"""Returns list of {name, slug} for all ~1003 Capterra software categories.""" html = http_get("https://www.capterra.com/categories/", headers={"User-Agent": "ClaudeBot"}) cats = re.findall(r'\[([^\]]+)\]\(https://www\.capterra\.com - Network accessline 362
html = http_get("https://www.capterra.com/categories/", headers={"User-Agent": "ClaudeBot"}) - Network accessline 363
cats = re.findall(r'\[([^\]]+)\]\(https://www\.capterra\.com/([a-z-]+-software)/\)', html) - Network accessline 377
| Page type | URL pattern | |-----------|-------------| | Product overview | `https://www.capterra.com/p/{id}/{Slug}/` | - Network accessline 378
|-----------|-------------| | Product overview | `https://www.capterra.com/p/{id}/{Slug}/` | | Product reviews | `https://www.capterra.com/p/{id}/{Slug}/reviews/` | - Network accessline 379
| Product overview | `https://www.capterra.com/p/{id}/{Slug}/` | - Network accessline 380
| Product reviews | `https://www.capterra.com/p/{id}/{Slug}/reviews/` | - Network accessline 381
| Reviews page N | `https://www.capterra.com/p/{id}/{Slug}/reviews/?page={N}` | - Network accessline 382
| Reviews (alt) | `https://www.capterra.com/reviews/{id}/{Slug}/` | - Network accessline 383
| Category listing | `https://www.capterra.com/{category}-software/` | - Network accessline 384
| Category page N | `https://www.capterra.com/{category}-software/?page={N}` | - Network accessline 385
| All categories | `https://www.capterra.com/categories/` | - Network accessline 386
| Product pricing | `https://www.capterra.com/p/{id}/{Slug}/pricing/` | - Network accessline 387
| Product alternatives | `https://www.capterra.com/p/{id}/{Slug}/alternatives/` | - Network accessline 388
| Compare A vs B | `https://www.capterra.com/compare/{id_a}-{id_b}/{Slug_a}-vs-{Slug_b}` | - Network accessline 390
**Finding a product's ID:** Look in the URL of any product listing in a category page. The pattern `https://www.capterra.com/p/{id}/{Slug}/reviews/` appears in every category listing as the link target for each rating badge. The slug is cas - Network accessline 412
- **Old Capterra product IDs may be invalid.** The URL `https://www.capterra.com/p/56703/Slack/` (ID 56703) returns 404 even with ClaudeBot — this is a stale or merged product ID. Slack's current ID is 135003, found in the team-communicatio
agent-workspace/domain-skills/centilebrain/generate-estimates.md
- Network accessline 3
URL: `https://centilebrain.org/#/model` - Network accessline 12
- The `/#/model` page is a thin wrapper around per-modality/sex **Shiny iframes** at `https://centilebrain-app.shinyapps.io/{SV|CT|SA}-{MALE|FEMALE}/`. - Network accessline 13
iframes** at `https://centilebrain-app.shinyapps.io/{SV|CT|SA}-{MALE|FEMALE}/`. - Network accessline 51
new_tab("https://centilebrain.org/#/model")
agent-workspace/domain-skills/chess-com/scraping.md
- Network accessline 3
Field-tested against api.chess.com on 2026-11-01 using a Browser Use cloud browser, logged out. Every call is a same-origin `fetch()` from an api.chess.com tab. No CAPTCHA, 403 or 429 across about 40 calls. - Network accessline 5
robots.txt (fetched 2026-11-01): api.chess.com is `User-agent: *` / `Disallow: /`; this skill uses it only under the official-API exception, because Chess.com documents these `/pub/...` endpoints as its public Published-Data API (https://ww - Network accessline 9
- **No scraping.** Three public JSON endpoints and one PGN endpoint cover the task. No key, no cookies, `access-control-allow-origin: *`: - `https://api.chess.com/pub/player/<user>` - profile: `player_id`, title, status, name, country, jo - Network accessline 10
- `https://api.chess.com/pub/player/<user>` - profile: `player_id`, title, status, name, country, joined, last online, followers. - Network accessline 11
- `https://api.chess.com/pub/player/<user>/stats` - ratings per game type (`chess_blitz`, `chess_bullet`, `chess_rapid`, `chess_daily`, `chess960_daily`) with current, best and W/L/D, plus `fide`, `tactics`, `puzzle_rush`. - Network accessline 12
- `https://api.chess.com/pub/player/<user>/games/archives` - every month with games, as URLs, oldest first. - `https://api.chess.com/pub/player/<user>/games/<YYYY>/<MM>` (JSON, one object per game incl. its PGN) and `.../<YYYY>/<MM>/pgn` - Network accessline 13
- `https://api.chess.com/pub/player/<user>/games/<YYYY>/<MM>` (JSON, one object per game incl. its PGN) and `.../<YYYY>/<MM>/pgn` (one multi-game PGN file). - **Serial calls only.** Chess.com's docs: "Your serial access rate is unlimited", - Network accessline 20
All blocks share the same helpers: `on_api_tab()` opens `https://api.chess.com/robots.txt` once (a tiny page on the API host, so `fetch()` is same-origin) and later blocks reuse it. `get(path)` fetches `https://api.chess.com/pub/<path>`, ke - Network accessline 30
API = "https://api.chess.com/pub/" - Network accessline 35
def on_api_tab(): """All calls run as same-origin fetch() in a logged-out api.chess.com tab; reuse it if already there.""" - Network accessline 36
"""All calls run as same-origin fetch() in a logged-out api.chess.com tab; reuse it if already there.""" - Network accessline 37
try: if js("location.origin") == "https://api.chess.com": return - Network accessline 38
if js("location.origin") == "https://api.chess.com": - Network accessline 40
except Exception: pass new_tab("https://api.chess.com/robots.txt") # tiny page on the API host - Network accessline 41
pass new_tab("https://api.chess.com/robots.txt") # tiny page on the API host wait_for_load() - Network accessline 42
new_tab("https://api.chess.com/robots.txt") # tiny page on the API host - Network accessline 45
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); - Network accessline 46
try { const r = await fetch(%s, {credentials: 'omit'}); window.__cc = await r.text(); - Network accessline 47
const r = await fetch(%s, {credentials: 'omit'}); - Network accessline 134
{ "username": "hikaru", "url": "https://www.chess.com/member/Hikaru", - Network accessline 135
"username": "hikaru", "url": "https://www.chess.com/member/Hikaru", "player_id": 15448422, - Network accessline 136
"url": "https://www.chess.com/member/Hikaru", - Network accessline 153
"best": 2464, "best_on": "2014-04-10T13:32Z", "best_game": "https://www.chess.com/game/daily/84604826", - Network accessline 154
"best_on": "2014-04-10T13:32Z", "best_game": "https://www.chess.com/game/daily/84604826", "win": 73, - Network accessline 155
"best_game": "https://www.chess.com/game/daily/84604826", - Network accessline 164
"best": 1489, "best_on": "2014-04-09T19:50Z", "best_game": "https://www.chess.com/game/daily/87191830", - Network accessline 165
"best_on": "2014-04-09T19:50Z", "best_game": "https://www.chess.com/game/daily/87191830", "win": 1, - Network accessline 166
"best_game": "https://www.chess.com/game/daily/87191830", - Network accessline 175
"best": 2927, "best_on": "2022-02-26T19:08Z", "best_game": "https://www.chess.com/game/live/141332265952", - Network accessline 176
"best_on": "2022-02-26T19:08Z", "best_game": "https://www.chess.com/game/live/141332265952", "win": 205, - Network accessline 177
"best_game": "https://www.chess.com/game/live/141332265952", - Network accessline 186
"best": 3570, "best_on": "2020-11-11T23:07Z", "best_game": "https://www.chess.com/game/live/5710095242", - Network accessline 187
"best_on": "2020-11-11T23:07Z", "best_game": "https://www.chess.com/game/live/5710095242", "win": 17232, - Network accessline 188
"best_game": "https://www.chess.com/game/live/5710095242", - Network accessline 197
"best": 3503, "best_on": "2026-10-06T16:21Z", "best_game": "https://www.chess.com/game/live/184580310677", - Network accessline 198
"best_on": "2026-10-06T16:21Z", "best_game": "https://www.chess.com/game/live/184580310677", "win": 36083, - Network accessline 199
"best_game": "https://www.chess.com/game/live/184580310677", - Network accessline 218
API = "https://api.chess.com/pub/" - Network accessline 223
def on_api_tab(): """All calls run as same-origin fetch() in a logged-out api.chess.com tab; reuse it if already there.""" - Network accessline 224
"""All calls run as same-origin fetch() in a logged-out api.chess.com tab; reuse it if already there.""" - Network accessline 225
try: if js("location.origin") == "https://api.chess.com": return - Network accessline 226
if js("location.origin") == "https://api.chess.com": - Network accessline 228
except Exception: pass new_tab("https://api.chess.com/robots.txt") # tiny page on the API host - Network accessline 229
pass new_tab("https://api.chess.com/robots.txt") # tiny page on the API host wait_for_load() - Network accessline 230
new_tab("https://api.chess.com/robots.txt") # tiny page on the API host - Network accessline 233
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); - Network accessline 234
try { const r = await fetch(%s, {credentials: 'omit'}); window.__cc = await r.text(); - Network accessline 235
const r = await fetch(%s, {credentials: 'omit'}); - Network accessline 339
2026/10: 583 games {"blitz": {"games": 549, "win": 473, "draw": 41, "loss": 35}, "bullet": {"games": 543, "win": 412, "draw": 45, "loss": 86}} {"url": "https://www.chess.com/game/live/186299800014", "end": "2026-10-31T19:39Z", "time_class": - Network accessline 340
{"blitz": {"games": 549, "win": 473, "draw": 41, "loss": 35}, "bullet": {"games": 543, "win": 412, "draw": 45, "loss": 86}} {"url": "https://www.chess.com/game/live/186299800014", "end": "2026-10-31T19:39Z", "time_class": "blitz", "time_con - Network accessline 341
{"url": "https://www.chess.com/game/live/186299800014", "end": "2026-10-31T19:39Z", "time_class": "blitz", "time_control": "180", "rules": "chess", "rated": true, "color": "white", "rating": 3453, "opponent": "Sina-Movahed", "opp_rating": 3 - Network accessline 350
[Timezone "UTC"] [ECO "B51"] [ECOUrl "https://www.chess.com/openings/Sicilian-Defense-Canal-Attack...10.h3-Bh5-11.g4-Bg6-12.Nh4"] - Network accessline 351
[ECO "B51"] [ECOUrl "https://www.chess.com/openings/Sicilian-Defense-Canal-Attack...10.h3-Bh5-11.g4-Bg6-12.Nh4"] [UTCDate "2026.10.31"] - Network accessline 352
[ECOUrl "https://www.chess.com/openings/Sicilian-Defense-Canal-Attack...10.h3-Bh5-11.g4-Bg6-12.Nh4"] - Network accessline 371
API = "https://api.chess.com/pub/" - Network accessline 376
def on_api_tab(): """All calls run as same-origin fetch() in a logged-out api.chess.com tab; reuse it if already there.""" - Network accessline 377
"""All calls run as same-origin fetch() in a logged-out api.chess.com tab; reuse it if already there.""" - Network accessline 378
try: if js("location.origin") == "https://api.chess.com": return - Network accessline 379
if js("location.origin") == "https://api.chess.com": - Network accessline 381
except Exception: pass new_tab("https://api.chess.com/robots.txt") # tiny page on the API host - Network accessline 382
pass new_tab("https://api.chess.com/robots.txt") # tiny page on the API host wait_for_load() - Network accessline 383
new_tab("https://api.chess.com/robots.txt") # tiny page on the API host - Network accessline 386
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); - Network accessline 387
try { const r = await fetch(%s, {credentials: 'omit'}); window.__cc = await r.text(); - Network accessline 388
const r = await fetch(%s, {credentials: 'omit'}); - Network accessline 475
[EndDate "2009.10.31"] [EndTime "17:53:17"] [Link "https://www.chess.com/game/daily/28103371"] - Network accessline 477
[Link "https://www.chess.com/game/daily/28103371"] - Network accessline 515
- **`rating` in a game row is the rating after that game**, not before it. - **Parallel requests:** not tested on purpose. The docs warn they may get 429 and that suspicious traffic can be blocked; keep calls serial. - **Browser User-Agent: - Network accessline 516
- **Parallel requests:** not tested on purpose. The docs warn they may get 429 and that suspicious traffic can be blocked; keep calls serial. - **Browser User-Agent:** the docs ask apps to send a recognizable User-Agent with contact info so - Network accessline 517
- **Browser User-Agent:** the docs ask apps to send a recognizable User-Agent with contact info so Chess.com can reach you before blocking. In-tab `fetch()` cannot set it; the browser's own UA goes out unchanged. Do not spoof it.
agent-workspace/domain-skills/claude-ai/extract-share-transcript.py
- Executable scriptline 1
Executable file - Network accessline 3
Usage (run inside browser-harness): CLAUDE_SHARE_URL=https://claude.ai/share/<uuid> \ - Network accessline 4
CLAUDE_SHARE_URL=https://claude.ai/share/<uuid> \ - Access to secretsline 17
[Credential-related source omitted] - Access to secretsline 18
[Credential-related source omitted]
agent-workspace/domain-skills/claude-ai/share-export.md
agent-workspace/domain-skills/claude/custom-connectors.md
- Network accessline 5
- Organization connectors are managed at `https://claude.ai/admin-settings/connectors`. Check the organization selector before changing settings.
agent-workspace/domain-skills/claude/skills.md
- Network accessline 5
- `https://claude.ai/customize/skills` opens Skills > Yours.
agent-workspace/domain-skills/clinicaltrials-gov/scraping.md
- Network accessline 9
- **Use the official API.** `GET https://clinicaltrials.gov/api/v2/studies` with `query.cond` (condition), `filter.overallStatus` (status list) and either `filter.geo=distance(lat,lon,25mi)` (radius) or `query.locn` (location text). `GET /a - Network accessline 24
API = "https://clinicaltrials.gov/api/v2" # official public API; robots.txt disallows /api/ (official-API exception) UA = "browser-harness-clinicaltrials-skill/1.0 Python-urllib" # truthful client name, no browser UA - Network accessline 34
_last[0] = time.time() try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json"}) - Network accessline 35
try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json"}) with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 36
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json"}) - Network accessline 37
with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 136
"site_statuses": {s: sum(1 for l in locs if l.get("status") == s) for s in sorted({l.get("status") for l in locs if l.get("status")})}, "has_results": d.get("hasResults"), "last_update": st.get("lastUpdatePostDateStruct", {}).get("d - Network accessline 137
"has_results": d.get("hasResults"), "last_update": st.get("lastUpdatePostDateStruct", {}).get("date"), "url": f"https://clinicaltrials.gov/study/{idm['nctId']}", } - Network accessline 138
"url": f"https://clinicaltrials.gov/study/{idm['nctId']}", - Network accessline 201
COMPLETED 151 TERMINATED 22 {"nct": "NCT06919354", "title": "A Study of GNTI-122 in Adults Recently Diagnosed With T1D", "official_title": "POLARIS: A Phase 1, Single Dose, Open-label Study of GNTI-122 in Adults W - Network accessline 202
TERMINATED 22 {"nct": "NCT06919354", "title": "A Study of GNTI-122 in Adults Recently Diagnosed With T1D", "official_title": "POLARIS: A Phase 1, Single Dose, Open-label Study of GNTI-122 in Adults With Recently Diagnosed Type 1 - Network accessline 203
{"nct": "NCT06919354", "title": "A Study of GNTI-122 in Adults Recently Diagnosed With T1D", "official_title": "POLARIS: A Phase 1, Single Dose, Open-label Study of GNTI-122 in Adults With Recently Diagnosed Type 1 Diabetes (T1D)", "status" - Network accessline 204
{"nct": "NCT04368728", "title": "Study to Describe the Safety, Tolerability, Immunogenicity, and Efficacy of RNA Vaccine Candidates Against COVID-19 in Healthy Individuals", "official_title": "A PHASE 1/2/3, PLACEBO-CONTROLLED, RANDOMIZED, - Network accessline 206
bad status -> HTTP 400 'Invalid value in parameter `overallStatus`: `OPEN`' on https://clinica - Network accessline 218
SITE = "https://clinicaltrials.gov" - Network accessline 256
.find(n => n.includes('/api/int/studies/' + nct)); if (!src) return {pending: true}; const r = await fetch(src); - Network accessline 257
if (!src) return {pending: true}; const r = await fetch(src); if (r.status === 404) return {missing: true, src}; - Network accessline 258
const r = await fetch(src); - Network accessline 328
robots: /study/NCT06919354 True | /api/int/studies/NCT06919354 True | /api/v2/studies False | /search?cond=x False {"src": "https://clinicaltrials.gov/api/int/studies/NCT06919354?history=true", "nct": "NCT06919354", "title": "A Study of GNT - Network accessline 329
{"src": "https://clinicaltrials.gov/api/int/studies/NCT06919354?history=true", "nct": "NCT06919354", "title": "A Study of GNTI-122 in Adults Recently Diagnosed With T1D", "status": "RECRUITING", "phases": ["PHASE1"], "type": "INTERVENTIONAL - Network accessline 330
{"src": "https://clinicaltrials.gov/api/int/studies/NCT04368728?history=true", "nct": "NCT04368728", "title": "Study to Describe the Safety, Tolerability, Immunogenicity, and Efficacy of RNA Vaccine Candidates Against COVID-19 in Healthy In
agent-workspace/domain-skills/coingecko/scraping.md
- Network accessline 3
`https://api.coingecko.com/api/v3` — no API key needed for free tier. Pure JSON REST API, no browser required. - Network accessline 10
import json data = json.loads(http_get("https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd")) - Network accessline 11
data = json.loads(http_get("https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd")) - Network accessline 54
# Resolve symbol to id coins_list = json.loads(http_get("https://api.coingecko.com/api/v3/coins/list")) - Network accessline 55
coins_list = json.loads(http_get("https://api.coingecko.com/api/v3/coins/list")) - Network accessline 67
import json data = json.loads(http_get( "https://api.coingecko.com/api/v3/simple/price" - Network accessline 68
data = json.loads(http_get( "https://api.coingecko.com/api/v3/simple/price" "?ids=bitcoin,ethereum,solana" - Network accessline 69
"https://api.coingecko.com/api/v3/simple/price" - Network accessline 88
import json data = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/markets" - Network accessline 89
data = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/markets" "?vs_currency=usd" - Network accessline 90
"https://api.coingecko.com/api/v3/coins/markets" - Network accessline 113
import json data = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/bitcoin" - Network accessline 114
data = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/bitcoin" "?localization=false" # skip 40+ language translations - Network accessline 115
"https://api.coingecko.com/api/v3/coins/bitcoin" - Network accessline 143
# 1d = 30-min candles, 7d = 4-hr candles, 14d+ = daily candles data = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/ethereum/ohlc?vs_currency=usd&days=7" - Network accessline 144
data = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/ethereum/ohlc?vs_currency=usd&days=7" )) - Network accessline 145
"https://api.coingecko.com/api/v3/coins/ethereum/ohlc?vs_currency=usd&days=7" - Network accessline 163
# interval='daily' gives one point per day; omit for auto (hourly for <=90 days) chart = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/bitcoin/market_chart" - Network accessline 164
chart = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/bitcoin/market_chart" "?vs_currency=usd&days=7&interval=daily" - Network accessline 165
"https://api.coingecko.com/api/v3/coins/bitcoin/market_chart" - Network accessline 180
thirty_days_ago = now - 30 * 86400 chart = json.loads(http_get( f"https://api.coingecko.com/api/v3/coins/bitcoin/market_chart/range" - Network accessline 181
chart = json.loads(http_get( f"https://api.coingecko.com/api/v3/coins/bitcoin/market_chart/range" f"?vs_currency=usd&from={thirty_days_ago}&to={now}" - Network accessline 182
f"https://api.coingecko.com/api/v3/coins/bitcoin/market_chart/range" - Network accessline 192
import json results = json.loads(http_get("https://api.coingecko.com/api/v3/search?query=solana")) - Network accessline 193
results = json.loads(http_get("https://api.coingecko.com/api/v3/search?query=solana")) - Network accessline 206
import json trending = json.loads(http_get("https://api.coingecko.com/api/v3/search/trending")) - Network accessline 207
trending = json.loads(http_get("https://api.coingecko.com/api/v3/search/trending")) - Network accessline 221
import json global_data = json.loads(http_get("https://api.coingecko.com/api/v3/global")) - Network accessline 222
global_data = json.loads(http_get("https://api.coingecko.com/api/v3/global")) - Network accessline 234
import json cats = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/categories?order=market_cap_desc" - Network accessline 235
cats = json.loads(http_get( "https://api.coingecko.com/api/v3/coins/categories?order=market_cap_desc" )) - Network accessline 236
"https://api.coingecko.com/api/v3/coins/categories?order=market_cap_desc" - Network accessline 252
[Credential-related source omitted] - Network accessline 253
[Credential-related source omitted] - Network accessline 254
"https://api.coingecko.com/api/v3/simple/token_price/ethereum" - Network accessline 275
currencies = json.loads(http_get("https://api.coingecko.com/api/v3/simple/supported_vs_currencies")) - Network accessline 292
import json ping = json.loads(http_get("https://api.coingecko.com/api/v3/ping")) - Network accessline 293
ping = json.loads(http_get("https://api.coingecko.com/api/v3/ping"))
agent-workspace/domain-skills/coinmarketcap/scraping.md
- Network accessline 3
`https://coinmarketcap.com` — crypto market data. Three access paths tested: internal JSON API (fastest, no auth required), `__NEXT_DATA__` from HTML pages, and browser DOM. All real-money price data confirmed accurate against displayed UI - Network accessline 31
resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listing" - Network accessline 32
"https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listing" - Network accessline 109
# Look up by CMC coin ID (BTC=1, ETH=1027, XRP=52, SOL=5426, BNB=1839) resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/detail?id=1" - Network accessline 110
resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/detail?id=1" )) - Network accessline 111
"https://api.coinmarketcap.com/data-api/v3/cryptocurrency/detail?id=1" - Network accessline 172
resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/global-metrics/quotes/latest" - Network accessline 173
"https://api.coinmarketcap.com/data-api/v3/global-metrics/quotes/latest" - Network accessline 206
# Daily candles for BTC over last 7 days resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/historical" - Network accessline 207
resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/historical" f"?id=1&convertId=2781&timeStart={now - 7*86400}&timeEnd={now}&interval=daily" - Network accessline 208
"https://api.coinmarketcap.com/data-api/v3/cryptocurrency/historical" - Network accessline 236
resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/market-pairs/latest" - Network accessline 237
"https://api.coinmarketcap.com/data-api/v3/cryptocurrency/market-pairs/latest" - Network accessline 259
resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/exchange/listing" - Network accessline 260
"https://api.coinmarketcap.com/data-api/v3/exchange/listing" - Network accessline 277
# Convert 1 BTC → USD resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/tools/price-conversion" - Network accessline 278
resp = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/tools/price-conversion" "?amount=1&id=1&convert_id=2781" - Network accessline 279
"https://api.coinmarketcap.com/data-api/v3/tools/price-conversion" - Network accessline 286
# Convert ETH → BTC resp2 = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/tools/price-conversion" - Network accessline 287
resp2 = json.loads(http_get( "https://api.coinmarketcap.com/data-api/v3/tools/price-conversion" "?amount=1&id=1027&convert_id=1" - Network accessline 288
"https://api.coinmarketcap.com/data-api/v3/tools/price-conversion" - Network accessline 304
# News for a specific coin resp = json.loads(http_get( "https://api.coinmarketcap.com/content/v3/news?coins=1&limit=10" - Network accessline 305
resp = json.loads(http_get( "https://api.coinmarketcap.com/content/v3/news?coins=1&limit=10" )) - Network accessline 306
"https://api.coinmarketcap.com/content/v3/news?coins=1&limit=10" - Network accessline 329
html = http_get("https://coinmarketcap.com/") - Network accessline 384
html = http_get("https://coinmarketcap.com/currencies/bitcoin/") - Access to secretsline 441
[Credential-related source omitted]
agent-workspace/domain-skills/costco/scraping.md
- Network accessline 9
- **Search results are not in the HTML.** `GET https://www.costco.com/s?keyword=...` from plain Python returned 200 (2.4 MB) with zero product ids and no JSON-LD. The grid is filled client-side by `POST https://gdx-api.costco.com/catalog/se - Network accessline 10
- **A normal browser session works.** Open the search page in a browser, record the response of the page's own search call, and move to the next page with the site's pager URL (`¤tPage=2`). Each response has 24 results (title, brands, - Network accessline 11
- **Product pages work with plain HTTP.** `GET https://www.costco.com/p/-/<slug>/<product_id>` returned 200 (about 2.7 MB) with a schema.org `Product` JSON-LD block (name, item number as `sku`, brand, rating, review count, price) and a `Bre - Network accessline 27
if n > 1: params["currentPage"] = n return "https://www.costco.com/s?" + urllib.parse.urlencode(params) - Network accessline 29
return "https://www.costco.com/s?" + urllib.parse.urlencode(params) - Network accessline 77
url = js_retry("location.href") or "" q = urllib.parse.parse_qs(urllib.parse.urlsplit(url).query) if url.startswith("https://www.costco.com/s?") and q.get("keyword") == [QUERY]: - Network accessline 78
q = urllib.parse.parse_qs(urllib.parse.urlsplit(url).query) if url.startswith("https://www.costco.com/s?") and q.get("keyword") == [QUERY]: seen = js_retry("(window.__costcoSearch || []).map((c, i) => ({i, status: c.stat - Network accessline 79
if url.startswith("https://www.costco.com/s?") and q.get("keyword") == [QUERY]: - Network accessline 181
"rating": 4.66, "review_count": 2706, "url": "https://www.costco.com/p/-/ninja-crispi-5-in-1-portable-glass-air-fry-cooking-system-3-containers--cover/4000376434", - Network accessline 182
"review_count": 2706, "url": "https://www.costco.com/p/-/ninja-crispi-5-in-1-portable-glass-air-fry-cooking-system-3-containers--cover/4000376434", "category": "Appliances > Small Kitchen Appliances > Air Fryers", - Network accessline 183
"url": "https://www.costco.com/p/-/ninja-crispi-5-in-1-portable-glass-air-fry-cooking-system-3-containers--cover/4000376434", - Network accessline 195
"rating": 4.4, "review_count": 5, "url": "https://www.costco.com/p/-/gourmia-9-qt-digital-air-fryer-with-ceramic-coating/4201032285", - Network accessline 196
"review_count": 5, "url": "https://www.costco.com/p/-/gourmia-9-qt-digital-air-fryer-with-ceramic-coating/4201032285", "category": "Appliances > Small Kitchen Appliances > Air Fryers", - Network accessline 197
"url": "https://www.costco.com/p/-/gourmia-9-qt-digital-air-fryer-with-ceramic-coating/4201032285", - Network accessline 211
import email.utils, html, http.client, json, re, sys, time, urllib.error, urllib.request - Network accessline 214
# Product URLs from the search rows (url field). Any https://www.costco.com/p/-/<slug>/<product_id> - Network accessline 215
# or <slug>.product.<product_id>.html URL works. URLS = [ "https://www.costco.com/p/-/t-fal-dual-window-infrared-air-fryer-73qt-dual-heating/4000430818", - Network accessline 216
URLS = [ "https://www.costco.com/p/-/t-fal-dual-window-infrared-air-fryer-73qt-dual-heating/4000430818", "https://www.costco.com/p/-/gourmia-9-qt-digital-air-fryer-with-ceramic-coating/4201032285", - Network accessline 217
"https://www.costco.com/p/-/t-fal-dual-window-infrared-air-fryer-73qt-dual-heating/4000430818", - Network accessline 218
"https://www.costco.com/p/-/gourmia-9-qt-digital-air-fryer-with-ceramic-coating/4201032285", - Network accessline 219
"https://www.costco.com/p/-/cuisinart-extra-large-26l-10-in-1-digital-air-fryer-oven/4000398962", - Network accessline 246
wait = None try: with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=30) as r: - Network accessline 247
try: with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=30) as r: return r.status, r.read().decode("utf-8", "replace") - Network accessline 248
with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=30) as r: - Network accessline 254
raise RuntimeError(f"{url}: HTTP {e.code}; stopping") # e.g. 403 = blocked: stop, do not work around it wait, last = retry_after_seconds(e.headers.get("Retry-After")), f"HTTP {e.code}" except (urllib.error.URLError, ht - Network accessline 255
wait, last = retry_after_seconds(e.headers.get("Retry-After")), f"HTTP {e.code}" except (urllib.error.URLError, http.client.IncompleteRead, TimeoutError, ConnectionError) as e: last = repr(e) - Network accessline 256
except (urllib.error.URLError, http.client.IncompleteRead, TimeoutError, ConnectionError) as e: - Network accessline 347
{ "url": "https://www.costco.com/p/-/gourmia-9-qt-digital-air-fryer-with-ceramic-coating/4201032285", - Network accessline 348
"url": "https://www.costco.com/p/-/gourmia-9-qt-digital-air-fryer-with-ceramic-coating/4201032285", - Network accessline 360
"specs": {"Brand": "Gourmia", "Capacity": "9 qt.", "Color": "Black", "Cord Length": "31.5 in.", "Dimensions - Depth": "16.2 in."}, "description": "Gourmia 9-Qt Digital Air Fryer with Ceramic Coating, Ceramic-Coated Basket and Crisper Tray, - Network accessline 361
"description": "Gourmia 9-Qt Digital Air Fryer with Ceramic Coating, Ceramic-Coated Basket and Crisper Tray, 9 Cooking Presets Plus 3 Cu", "image": "https://gdx-assets.costco.com/adobe/assets/urn:aaid:aem:859d2718-.../as/4201032285-847__1. - Network accessline 362
"image": "https://gdx-assets.costco.com/adobe/assets/urn:aaid:aem:859d2718-.../as/4201032285-847__1.avif" - Network accessline 380
| rating | `p.rating.averageRating`, rounded to 2 places | `4.4` | | review_count | `p.rating.ratingCount` | `5` | | url | `p.uri` | `https://www.costco.com/p/-/<slug>/<product_id>`; the tiles link to the equivalent `<slug>.product.<product - Network accessline 381
| review_count | `p.rating.ratingCount` | `5` | | url | `p.uri` | `https://www.costco.com/p/-/<slug>/<product_id>`; the tiles link to the equivalent `<slug>.product.<product_id>.html` | | category | `p.categories[-1]` | `"Appliances > Small - Network accessline 382
| url | `p.uri` | `https://www.costco.com/p/-/<slug>/<product_id>`; the tiles link to the equivalent `<slug>.product.<product_id>.html` | - Network accessline 431
- **Plain HTTP search**: `https://www.costco.com/s?keyword=air+fryer` returned 200 but no product ids, ratings or prices in the HTML; results load client-side.
agent-workspace/domain-skills/coursera/scraping.md
- Network accessline 24
resp = http_get( "https://api.coursera.org/api/courses.v1" - Network accessline 25
"https://api.coursera.org/api/courses.v1" - Network accessline 44
{"domainId": "business", "subdomainId": "marketing"} ], "photoUrl": "https://d3njjcbhbojbot.cloudfront.net/api/utilities/v1/imageproxy/https://coursera-course-photos.s3.amazonaws.com/...", - Network accessline 45
], "photoUrl": "https://d3njjcbhbojbot.cloudfront.net/api/utilities/v1/imageproxy/https://coursera-course-photos.s3.amazonaws.com/...", "id": "69Bku0KoEeWZtA4u62x6lQ", - Network accessline 46
"photoUrl": "https://d3njjcbhbojbot.cloudfront.net/api/utilities/v1/imageproxy/https://coursera-course-photos.s3.amazonaws.com/...", - Network accessline 59
Field notes: - `id` — opaque base64-ish string, stable identifier. Use for batch lookups and linking. - `slug` — URL-safe identifier. Course page: `https://www.coursera.org/learn/{slug}` - Network accessline 60
- `id` — opaque base64-ish string, stable identifier. Use for batch lookups and linking. - `slug` — URL-safe identifier. Course page: `https://www.coursera.org/learn/{slug}` - `courseType` — always `"v2.ondemand"` for self-paced courses in - Network accessline 61
- `slug` — URL-safe identifier. Course page: `https://www.coursera.org/learn/{slug}` - Network accessline 82
while True: url = ( f"https://api.coursera.org/api/courses.v1" - Network accessline 83
url = ( f"https://api.coursera.org/api/courses.v1" f"?fields={base_fields}&limit={page_size}&start={start}" - Network accessline 84
f"https://api.coursera.org/api/courses.v1" - Network accessline 106
resp = http_get( "https://api.coursera.org/api/partners.v1" - Network accessline 107
"https://api.coursera.org/api/partners.v1" - Network accessline 121
"shortName": "penn", "description": "The University of Pennsylvania (commonly referred to as Penn)...", "squareLogo": "http://coursera-university-assets.s3.amazonaws.com/.../logo.png" - Network accessline 122
"description": "The University of Pennsylvania (commonly referred to as Penn)...", "squareLogo": "http://coursera-university-assets.s3.amazonaws.com/.../logo.png" } - Network accessline 123
"squareLogo": "http://coursera-university-assets.s3.amazonaws.com/.../logo.png" - Network accessline 130
resp = http_get( "https://api.coursera.org/api/partners.v1" - Network accessline 131
"https://api.coursera.org/api/partners.v1" - Network accessline 144
resp = http_get( "https://api.coursera.org/api/onDemandSpecializations.v1" - Network accessline 145
"https://api.coursera.org/api/onDemandSpecializations.v1" - Network accessline 176
# Lookup specific instructors by ID resp = http_get( "https://api.coursera.org/api/instructors.v1" - Network accessline 177
resp = http_get( "https://api.coursera.org/api/instructors.v1" "?ids=226710&fields=fullName,bio,department,title,photo" - Network accessline 178
"https://api.coursera.org/api/instructors.v1" - Network accessline 192
"department": "Legal Studies and Business Ethics", "bio": "Kevin Werbach is professor of Legal Studies...", "photo": "https://d3njjcbhbojbot.cloudfront.net/api/utilities/v1/imageproxy/..." - Network accessline 193
"bio": "Kevin Werbach is professor of Legal Studies...", "photo": "https://d3njjcbhbojbot.cloudfront.net/api/utilities/v1/imageproxy/..." } - Network accessline 194
"photo": "https://d3njjcbhbojbot.cloudfront.net/api/utilities/v1/imageproxy/..." - Network accessline 205
ids = ",".join(["69Bku0KoEeWZtA4u62x6lQ", "hOzhxVNuEfCW8Q55q1kSNQ", "0HiU7Oe4EeWTAQ4yevf_oQ"]) resp = http_get( f"https://api.coursera.org/api/courses.v1" - Network accessline 206
resp = http_get( f"https://api.coursera.org/api/courses.v1" f"?ids={ids}&fields=name,slug,description,primaryLanguages,workload,partnerIds" - Network accessline 207
f"https://api.coursera.org/api/courses.v1" - Network accessline 233
new_tab("https://www.coursera.org/search?query=machine+learning") - Network accessline 248
html = http_get("https://www.coursera.org/learn/machine-learning") - Network accessline 281
# Get course data from slug (need ID first — get it from catalog or search) # Pattern: enumerate catalog, match by slug resp = http_get("https://api.coursera.org/api/courses.v1?fields=name,slug,description&limit=100&start=0") - Network accessline 282
# Pattern: enumerate catalog, match by slug resp = http_get("https://api.coursera.org/api/courses.v1?fields=name,slug,description&limit=100&start=0") data = json.loads(resp) - Network accessline 283
resp = http_get("https://api.coursera.org/api/courses.v1?fields=name,slug,description&limit=100&start=0")
agent-workspace/domain-skills/craigslist/scraping.md
- Network accessline 25
https://{city}.craigslist.org/search/{category_code}?query=... - Network accessline 94
# For-sale keyword search "https://sfbay.craigslist.org/search/sss?query=macbook&sort=rel" - Network accessline 95
"https://sfbay.craigslist.org/search/sss?query=macbook&sort=rel" - Network accessline 97
# Price-filtered electronics "https://sfbay.craigslist.org/search/ela?query=iphone&min_price=100&max_price=500" - Network accessline 98
"https://sfbay.craigslist.org/search/ela?query=iphone&min_price=100&max_price=500" - Network accessline 100
# Apartments, 2 bedrooms, price range "https://sfbay.craigslist.org/search/apa?bedrooms=2&min_price=1000&max_price=2500" - Network accessline 101
"https://sfbay.craigslist.org/search/apa?bedrooms=2&min_price=1000&max_price=2500" - Network accessline 103
# Cars by owner, Toyota "https://sfbay.craigslist.org/search/cto?auto_make_model=toyota" - Network accessline 104
"https://sfbay.craigslist.org/search/cto?auto_make_model=toyota" - Network accessline 106
# Jobs in another city "https://chicago.craigslist.org/search/jjj?query=python+developer" - Network accessline 107
"https://chicago.craigslist.org/search/jjj?query=python+developer" - Network accessline 115
<li class="cl-static-search-result" title="MacBook Air M2 256GB 8GB RAM"> <a href="https://sfbay.craigslist.org/sby/ele/d/san-jose-macbook-air-m2/7928508295.html"> - Network accessline 116
<a href="https://sfbay.craigslist.org/sby/ele/d/san-jose-macbook-air-m2/7928508295.html"> - Network accessline 133
URL pattern: `https://{city}.craigslist.org/{area}/{category_code}/d/{slug}/{post_id}.html` - Network accessline 143
if min_price: params += f"&min_price={min_price}" if max_price: params += f"&max_price={max_price}" url = f"https://{city}.craigslist.org/search/{category}?{params}" - Network accessline 144
if max_price: params += f"&max_price={max_price}" url = f"https://{city}.craigslist.org/search/{category}?{params}" headers = {"User-Agent": "Mozilla/5.0"} - Network accessline 145
url = f"https://{city}.craigslist.org/search/{category}?{params}" - Network accessline 228
# Images images = re.findall(r'https://images\.craigslist\.org/[^\s"\']+_600x450\.jpg', html) - Network accessline 229
images = re.findall(r'https://images\.craigslist\.org/[^\s"\']+_600x450\.jpg', html) - Network accessline 258
"posted": "2026-02-24T16:08:38-0800", "body": "I bought a new phone. These are brand new! Plz lmk if you are interested.", "images": ["https://images.craigslist.org/00e0e_xxx_600x450.jpg"], - Network accessline 259
"body": "I bought a new phone. These are brand new! Plz lmk if you are interested.", "images": ["https://images.craigslist.org/00e0e_xxx_600x450.jpg"], "attrs": {"condition": "like new", "make / manufacturer": "Apple", "mod - Network accessline 260
"images": ["https://images.craigslist.org/00e0e_xxx_600x450.jpg"], - Network accessline 289
html = http_get("https://sfbay.craigslist.org/search/sss?query=laptop", headers={"User-Agent": "Mozilla/5.0"})
agent-workspace/domain-skills/crossref/scraping.md
- Network accessline 3
`https://api.crossref.org` — scholarly DOI and citation metadata. **Never use the browser for CrossRef.** Completely free, no auth required. All workflows use `http_get`. - Network accessline 15
# Single DOI lookup — fastest way to get metadata for a known paper data = json.loads(http_get(f"https://api.crossref.org/works/10.1038/s41586-021-03819-2?{MAILTO}")) - Network accessline 16
data = json.loads(http_get(f"https://api.crossref.org/works/10.1038/s41586-021-03819-2?{MAILTO}")) - Network accessline 32
def fetch_work(doi): data = json.loads(http_get(f"https://api.crossref.org/works/{doi}?{MAILTO}")) - Network accessline 33
data = json.loads(http_get(f"https://api.crossref.org/works/{doi}?{MAILTO}")) - Network accessline 78
MAILTO = "mailto=your@email.com" data = json.loads(http_get(f"https://api.crossref.org/works/10.1038/s41586-021-03819-2?{MAILTO}")) - Network accessline 79
data = json.loads(http_get(f"https://api.crossref.org/works/10.1038/s41586-021-03819-2?{MAILTO}")) - Network accessline 83
name = f"{a.get('given', '')} {a.get('family', '')}".strip() # ORCID is a full URL, not a bare ID — strip the prefix orcid_url = a.get('ORCID') # e.g. 'https://orcid.org/0000-0001-6169-6580' - Network accessline 84
# ORCID is a full URL, not a bare ID — strip the prefix orcid_url = a.get('ORCID') # e.g. 'https://orcid.org/0000-0001-6169-6580' orcid_id = orcid_url.replace('https://orcid.org/', '') if orcid_url else None - Network accessline 85
orcid_url = a.get('ORCID') # e.g. 'https://orcid.org/0000-0001-6169-6580' - Network accessline 86
orcid_id = orcid_url.replace('https://orcid.org/', '') if orcid_url else None - Network accessline 105
def fetch_work(doi): try: data = json.loads(http_get(f"https://api.crossref.org/works/{doi}?{MAILTO}")) - Network accessline 106
try: data = json.loads(http_get(f"https://api.crossref.org/works/{doi}?{MAILTO}")) msg = data['message'] - Network accessline 107
data = json.loads(http_get(f"https://api.crossref.org/works/{doi}?{MAILTO}")) - Network accessline 149
# Broad keyword search data = json.loads(http_get( f"https://api.crossref.org/works?query=machine+learning&rows=5&{MAILTO}" - Network accessline 150
data = json.loads(http_get( f"https://api.crossref.org/works?query=machine+learning&rows=5&{MAILTO}" )) - Network accessline 151
f"https://api.crossref.org/works?query=machine+learning&rows=5&{MAILTO}" - Network accessline 172
data = json.loads(http_get( f"https://api.crossref.org/works?query.author=Lecun&query.title=deep+learning&rows=5&{MAILTO}" - Network accessline 173
f"https://api.crossref.org/works?query.author=Lecun&query.title=deep+learning&rows=5&{MAILTO}" - Network accessline 196
data = json.loads(http_get( f"https://api.crossref.org/works" - Network accessline 197
f"https://api.crossref.org/works" - Network accessline 221
# Only return works that have an abstract (useful since ~30-70% do not) data = json.loads(http_get( f"https://api.crossref.org/works" - Network accessline 222
data = json.loads(http_get( f"https://api.crossref.org/works" f"?filter=from-pub-date:2023-01-01,until-pub-date:2023-12-31" - Network accessline 223
f"https://api.crossref.org/works" - Network accessline 248
# First page: cursor=* data = json.loads(http_get( f"https://api.crossref.org/works?query=covid&rows=100&cursor=*&{MAILTO}" - Network accessline 249
data = json.loads(http_get( f"https://api.crossref.org/works?query=covid&rows=100&cursor=*&{MAILTO}" )) - Network accessline 250
f"https://api.crossref.org/works?query=covid&rows=100&cursor=*&{MAILTO}" - Network accessline 258
while next_cursor and items: data = json.loads(http_get( f"https://api.crossref.org/works?query=covid&rows=100" - Network accessline 259
data = json.loads(http_get( f"https://api.crossref.org/works?query=covid&rows=100" f"&cursor={quote(next_cursor)}&{MAILTO}" - Network accessline 260
f"https://api.crossref.org/works?query=covid&rows=100" - Network accessline 280
data = json.loads(http_get( f"https://api.crossref.org/works?query=cancer&rows=5" - Network accessline 281
f"https://api.crossref.org/works?query=cancer&rows=5" - Network accessline 298
data = json.loads(http_get( f"https://api.crossref.org/works?query=machine+learning&rows=0" - Network accessline 299
f"https://api.crossref.org/works?query=machine+learning&rows=0" - Network accessline 322
# Nature (ISSN 0028-0836) data = json.loads(http_get(f"https://api.crossref.org/journals/0028-0836?{MAILTO}")) - Network accessline 323
data = json.loads(http_get(f"https://api.crossref.org/journals/0028-0836?{MAILTO}")) - Network accessline 331
# Search journals by name data2 = json.loads(http_get(f"https://api.crossref.org/journals?query=nature&rows=3&{MAILTO}")) - Network accessline 332
data2 = json.loads(http_get(f"https://api.crossref.org/journals?query=nature&rows=3&{MAILTO}")) - Network accessline 348
data = json.loads(http_get( f"https://api.crossref.org/funders?query=national+science+foundation&rows=3&{MAILTO}" - Network accessline 349
f"https://api.crossref.org/funders?query=national+science+foundation&rows=3&{MAILTO}" - Network accessline 369
def doi_to_csl(doi): """Fetch CSL-JSON via DOI content negotiation. Same data as CrossRef API.""" req = urllib.request.Request( - Network accessline 370
"""Fetch CSL-JSON via DOI content negotiation. Same data as CrossRef API.""" req = urllib.request.Request( f"https://doi.org/{doi}", - Network accessline 371
req = urllib.request.Request( - Network accessline 372
f"https://doi.org/{doi}", - Network accessline 374
"User-Agent": "Mozilla/5.0"} ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 375
) with urllib.request.urlopen(req, timeout=20) as r: return json.loads(r.read().decode()) - Network accessline 376
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 379
def doi_to_bibtex(doi): """Fetch BibTeX via DOI content negotiation.""" req = urllib.request.Request( - Network accessline 380
"""Fetch BibTeX via DOI content negotiation.""" req = urllib.request.Request( f"https://doi.org/{doi}", - Network accessline 381
req = urllib.request.Request( - Network accessline 382
f"https://doi.org/{doi}", - Network accessline 383
headers={"Accept": "application/x-bibtex", "User-Agent": "Mozilla/5.0"} ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 384
) with urllib.request.urlopen(req, timeout=20) as r: return r.read().decode() - Network accessline 385
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 404
|---|---|---| | `DOI` (R) | string | e.g. `"10.1038/s41586-021-03819-2"` | | `URL` (R) | string | `"https://doi.org/10.1038/s41586-021-03819-2"` | - Network accessline 405
| `DOI` (R) | string | e.g. `"10.1038/s41586-021-03819-2"` | | `URL` (R) | string | `"https://doi.org/10.1038/s41586-021-03819-2"` | | `title` (R) | list[str] | Always a list; access `title[0]` | - Network accessline 406
| `URL` (R) | string | `"https://doi.org/10.1038/s41586-021-03819-2"` | - Network accessline 447
| `sequence` | `"first"` or `"additional"` | | `affiliation` | list of `{name, place}` — usually `[]` | | `ORCID` | Full URL `"https://orcid.org/0000-0001-..."` — strip prefix to get bare ID | - Network accessline 448
| `affiliation` | list of `{name, place}` — usually `[]` | | `ORCID` | Full URL `"https://orcid.org/0000-0001-..."` — strip prefix to get bare ID | | `authenticated-orcid` | `true` = verified via ORCID OAuth; `false` = self-reported | - Network accessline 449
| `ORCID` | Full URL `"https://orcid.org/0000-0001-..."` — strip prefix to get bare ID | - Network accessline 546
- **ORCID is a full URL, not just the ID.** `a['ORCID']` = `"https://orcid.org/0000-0001-6169-6580"`. Strip with `.replace('https://orcid.org/', '')` to get the bare ID. `authenticated-orcid: false` means self-asserted (not verified via OAu
agent-workspace/domain-skills/ctrip/hotels.md
- Network accessline 15
- Once on a valid list page, prices render as `¥<original> ¥<current> 起` pairs. No `¥?` placeholders and no `请登录` interstitial. - Detail URL `https://hotels.ctrip.com/hotel/<hotelId>.html?checkin=...` works - Network accessline 16
pairs. No `¥?` placeholders and no `请登录` interstitial. - Detail URL `https://hotels.ctrip.com/hotel/<hotelId>.html?checkin=...` works pre-login and shows full room-rate breakdown. - Network accessline 17
- Detail URL `https://hotels.ctrip.com/hotel/<hotelId>.html?checkin=...` works - Network accessline 27
List page (canonical, anonymous-friendly): https://hotels.ctrip.com/hotels/list - Network accessline 28
https://hotels.ctrip.com/hotels/list - Network accessline 37
Hotel detail (canonical): https://hotels.ctrip.com/hotel/<hotelId>.html?checkin=...&checkout=... - Network accessline 38
https://hotels.ctrip.com/hotel/<hotelId>.html?checkin=...&checkout=... - Network accessline 41
Login page (when reached unintentionally): https://passport.ctrip.com/user/login?backurl=<url-encoded-target> - Network accessline 42
https://passport.ctrip.com/user/login?backurl=<url-encoded-target> - Network accessline 45
**Critical:** the *simplified* form `https://hotels.ctrip.com/hotels/list?city=2&checkin=...&checkout=...` - Network accessline 59
import time url = ( "https://hotels.ctrip.com/hotels/list" - Network accessline 60
url = ( "https://hotels.ctrip.com/hotels/list" "?flexType=1&cityId=2&provinceId=0&districtId=0&countryId=1" - Network accessline 61
"https://hotels.ctrip.com/hotels/list" - Network accessline 80
new_tab("https://hotels.ctrip.com/") - Network accessline 160
https://hotels.ctrip.com/hotel/<hotelId>.html?checkin=YYYY-MM-DD&checkout=YYYY-MM-DD - Network accessline 182
https://passport.ctrip.com/user/login?backurl=... - Network accessline 260
url = ( "https://hotels.ctrip.com/hotels/list" - Network accessline 261
"https://hotels.ctrip.com/hotels/list"
agent-workspace/domain-skills/dev-to/scraping.md
- Network accessline 3
`https://dev.to` — developer blogging platform. Everything useful is available via a public REST API with no auth required. No browser needed for any read task. - Network accessline 10
import json articles = json.loads(http_get("https://dev.to/api/articles?per_page=10&tag=python")) - Network accessline 11
articles = json.loads(http_get("https://dev.to/api/articles?per_page=10&tag=python")) - Network accessline 30
"Accept": "application/vnd.forem.api-v1+json", } with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=20) as r: - Network accessline 31
} with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=20) as r: data = r.read() - Network accessline 32
with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=20) as r: - Network accessline 38
articles = json.loads(dev_get("https://dev.to/api/articles?per_page=10&tag=python")) - Network accessline 50
import json articles = json.loads(http_get("https://dev.to/api/articles?per_page=10&tag=python")) - Network accessline 51
articles = json.loads(http_get("https://dev.to/api/articles?per_page=10&tag=python")) - Network accessline 62
import json # top=N means "top articles from the last N days" top_day = json.loads(http_get("https://dev.to/api/articles?per_page=10&top=1")) - Network accessline 63
# top=N means "top articles from the last N days" top_day = json.loads(http_get("https://dev.to/api/articles?per_page=10&top=1")) top_week = json.loads(http_get("https://dev.to/api/articles?per_page=10&top=7")) - Network accessline 64
top_day = json.loads(http_get("https://dev.to/api/articles?per_page=10&top=1")) - Network accessline 65
top_week = json.loads(http_get("https://dev.to/api/articles?per_page=10&top=7")) - Network accessline 66
top_month = json.loads(http_get("https://dev.to/api/articles?per_page=10&top=30")) - Network accessline 67
top_year = json.loads(http_get("https://dev.to/api/articles?per_page=10&top=365")) - Network accessline 73
import json articles = json.loads(http_get("https://dev.to/api/articles?per_page=10&username=ben")) - Network accessline 74
articles = json.loads(http_get("https://dev.to/api/articles?per_page=10&username=ben")) - Network accessline 81
import json fresh = json.loads(http_get("https://dev.to/api/articles?per_page=10&state=fresh")) # very new - Network accessline 82
fresh = json.loads(http_get("https://dev.to/api/articles?per_page=10&state=fresh")) # very new - Network accessline 83
rising = json.loads(http_get("https://dev.to/api/articles?per_page=10&state=rising")) # gaining traction - Network accessline 90
import json article = json.loads(http_get("https://dev.to/api/articles/3442047")) - Network accessline 91
article = json.loads(http_get("https://dev.to/api/articles/3442047")) - Network accessline 101
import json # path field from list response is "/username/slug" article = json.loads(http_get("https://dev.to/api/articles/ben/some-article-slug")) - Network accessline 103
article = json.loads(http_get("https://dev.to/api/articles/ben/some-article-slug")) - Network accessline 109
import json tags = json.loads(http_get("https://dev.to/api/tags?per_page=10")) - Network accessline 110
tags = json.loads(http_get("https://dev.to/api/tags?per_page=10")) - Network accessline 123
import json user = json.loads(http_get("https://dev.to/api/users/by_username?url=ben")) - Network accessline 124
user = json.loads(http_get("https://dev.to/api/users/by_username?url=ben")) - Network accessline 136
import json comments = json.loads(http_get("https://dev.to/api/comments?a_id=3442047")) - Network accessline 137
comments = json.loads(http_get("https://dev.to/api/comments?a_id=3442047")) - Network accessline 150
import json comment = json.loads(http_get("https://dev.to/api/comments/36lnc")) - Network accessline 151
comment = json.loads(http_get("https://dev.to/api/comments/36lnc")) - Network accessline 155
### Bulk tag fetch (parallel) - Network accessline 164
def fetch_tag(tag): data = json.loads(http_get(f"https://dev.to/api/articles?per_page=5&tag={tag}")) - Network accessline 165
data = json.loads(http_get(f"https://dev.to/api/articles?per_page=5&tag={tag}")) - Network accessline 201
for page in range(1, max_pages + 1): batch = json.loads(http_get( f"https://dev.to/api/articles?per_page=30&tag={tag}&page={page}" - Network accessline 202
batch = json.loads(http_get( f"https://dev.to/api/articles?per_page=30&tag={tag}&page={page}" )) - Network accessline 203
f"https://dev.to/api/articles?per_page=30&tag={tag}&page={page}" - Access to secretsline 264
[Credential-related source omitted] - Network accessline 283
urls = [ f"https://dev.to/api/articles?per_page=10&tag={tag}" - Network accessline 284
f"https://dev.to/api/articles?per_page=10&tag={tag}"
agent-workspace/domain-skills/dexscreener/scraping.md
- Network accessline 3
Field-tested against dexscreener.com and api.dexscreener.com on 2026-11-02 using a Browser Use cloud browser, logged out. API calls are `fetch()` from an api.dexscreener.com tab; New Pairs is read from the dexscreener.com page. No CAPTCHA, - Network accessline 5
robots.txt (fetched 2026-11-02 in the browser): dexscreener.com is `User-agent: *` / `Allow: /`; api.dexscreener.com has no robots.txt (HTTP 404) and is used under the official-API exception: it is DEX Screener's documented public API (http - Network accessline 13
- `/latest/dex/pairs/<chainId>/<pair1>,<pair2>,...` - fresh numbers for known pairs; 30 per call worked. (300/min) - `/token-boosts/latest/v1` and `/token-boosts/top/v1` - 30 rows each. (60/min) - **New pairs have no API endpoint.** Read - Network accessline 14
- `/token-boosts/latest/v1` and `/token-boosts/top/v1` - 30 rows each. (60/min) - **New pairs have no API endpoint.** Read the site's table at `https://dexscreener.com/new-pairs?rankBy=pairAge&order=asc` (what its "Newest" button sets): 100 - Network accessline 15
- **New pairs have no API endpoint.** Read the site's table at `https://dexscreener.com/new-pairs?rankBy=pairAge&order=asc` (what its "Newest" button sets): 100 rows per page, `/new-pairs/page-2?...` for more, `/new-pairs/<chainId>?...` for - Network accessline 21
API blocks share the same helpers: `on_api_tab()` opens a tiny JSON answer on api.dexscreener.com once (later blocks reuse it), `get(path)` starts `fetch()` in that tab and polls for the result (big answers can take longer than `js()`'s 5 s - Network accessline 31
API = "https://api.dexscreener.com" PER_MIN = {"slow": 60, "fast": 300} # documented limits, requests per minute per endpoint group - Network accessline 38
def on_api_tab(): """All API calls run as same-origin fetch() in a logged-out api.dexscreener.com tab; reuse it if already there.""" - Network accessline 39
"""All API calls run as same-origin fetch() in a logged-out api.dexscreener.com tab; reuse it if already there.""" - Network accessline 44
pass # A tiny JSON answer ("[]"). Not the host root: its 'Cannot GET /' 404 page sends CSP default-src 'none', # which makes every fetch() from that tab fail with "Failed to fetch". - Network accessline 45
# A tiny JSON answer ("[]"). Not the host root: its 'Cannot GET /' 404 page sends CSP default-src 'none', # which makes every fetch() from that tab fail with "Failed to fetch". new_tab(API + "/token-pairs/v1/solana/x") - Network accessline 46
# which makes every fetch() from that tab fail with "Failed to fetch". - Network accessline 50
START_JS = """(() => { window.__dx = null; fetch(%s, {credentials: 'omit'}) - Network accessline 51
fetch(%s, {credentials: 'omit'}) - Network accessline 143
], "pair": "0xA43fe16908251ee70EF74718545e4FE6C5cCEc9f", "url": "https://dexscreener.com/ethereum/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f", - Network accessline 144
"pair": "0xA43fe16908251ee70EF74718545e4FE6C5cCEc9f", "url": "https://dexscreener.com/ethereum/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f", "base": "PEPE", - Network accessline 145
"url": "https://dexscreener.com/ethereum/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f", - Network accessline 179
API = "https://api.dexscreener.com" PER_MIN = {"slow": 60, "fast": 300} # documented limits, requests per minute per endpoint group - Network accessline 186
def on_api_tab(): """All API calls run as same-origin fetch() in a logged-out api.dexscreener.com tab; reuse it if already there.""" - Network accessline 187
"""All API calls run as same-origin fetch() in a logged-out api.dexscreener.com tab; reuse it if already there.""" - Network accessline 192
pass # A tiny JSON answer ("[]"). Not the host root: its 'Cannot GET /' 404 page sends CSP default-src 'none', # which makes every fetch() from that tab fail with "Failed to fetch". - Network accessline 193
# A tiny JSON answer ("[]"). Not the host root: its 'Cannot GET /' 404 page sends CSP default-src 'none', # which makes every fetch() from that tab fail with "Failed to fetch". new_tab(API + "/token-pairs/v1/solana/x") - Network accessline 194
# which makes every fetch() from that tab fail with "Failed to fetch". - Network accessline 198
START_JS = """(() => { window.__dx = null; fetch(%s, {credentials: 'omit'}) - Network accessline 199
fetch(%s, {credentials: 'omit'}) - Network accessline 308
], "pair": "C1MgLojNLWBKADvu9BHdtgzz1oZX4dZ5zGdGcgvvW8Wz", "url": "https://dexscreener.com/solana/c1mglojnlwbkadvu9bhdtgzz1ozx4dz5zgdgcgvvw8wz", - Network accessline 309
"pair": "C1MgLojNLWBKADvu9BHdtgzz1oZX4dZ5zGdGcgvvW8Wz", "url": "https://dexscreener.com/solana/c1mglojnlwbkadvu9bhdtgzz1ozx4dz5zgdgcgvvw8wz", "base": "JUP", - Network accessline 310
"url": "https://dexscreener.com/solana/c1mglojnlwbkadvu9bhdtgzz1ozx4dz5zgdgcgvvw8wz", - Network accessline 340
SITE = "https://dexscreener.com" - Network accessline 398
API = "https://api.dexscreener.com" PER_MIN = {"slow": 60, "fast": 300} # documented limits, requests per minute per endpoint group - Network accessline 405
def on_api_tab(): """All API calls run as same-origin fetch() in a logged-out api.dexscreener.com tab; reuse it if already there.""" - Network accessline 406
"""All API calls run as same-origin fetch() in a logged-out api.dexscreener.com tab; reuse it if already there.""" - Network accessline 411
pass # A tiny JSON answer ("[]"). Not the host root: its 'Cannot GET /' 404 page sends CSP default-src 'none', # which makes every fetch() from that tab fail with "Failed to fetch". - Network accessline 412
# A tiny JSON answer ("[]"). Not the host root: its 'Cannot GET /' 404 page sends CSP default-src 'none', # which makes every fetch() from that tab fail with "Failed to fetch". new_tab(API + "/token-pairs/v1/solana/x") - Network accessline 413
# which makes every fetch() from that tab fail with "Failed to fetch". - Network accessline 417
START_JS = """(() => { window.__dx = null; fetch(%s, {credentials: 'omit'}) - Network accessline 418
fetch(%s, {credentials: 'omit'}) - Network accessline 543
API = "https://api.dexscreener.com" PER_MIN = {"slow": 60, "fast": 300} # documented limits, requests per minute per endpoint group - Network accessline 550
def on_api_tab(): """All API calls run as same-origin fetch() in a logged-out api.dexscreener.com tab; reuse it if already there.""" - Network accessline 551
"""All API calls run as same-origin fetch() in a logged-out api.dexscreener.com tab; reuse it if already there.""" - Network accessline 556
pass # A tiny JSON answer ("[]"). Not the host root: its 'Cannot GET /' 404 page sends CSP default-src 'none', # which makes every fetch() from that tab fail with "Failed to fetch". - Network accessline 557
# A tiny JSON answer ("[]"). Not the host root: its 'Cannot GET /' 404 page sends CSP default-src 'none', # which makes every fetch() from that tab fail with "Failed to fetch". new_tab(API + "/token-pairs/v1/solana/x") - Network accessline 558
# which makes every fetch() from that tab fail with "Failed to fetch". - Network accessline 562
START_JS = """(() => { window.__dx = null; fetch(%s, {credentials: 'omit'}) - Network accessline 563
fetch(%s, {credentials: 'omit'}) - Network accessline 694
[Credential-related source omitted] - Network accessline 695
[Credential-related source omitted] - Network accessline 696
"url": "https://dexscreener.com/solana/8s4bnqezth1jp7mku747umr7ackcqdiv47fdqyndpump", - Network accessline 705
"market_cap": 1042595, "pair_created": "2026-11-01T22:28Z", "pair_url": "https://dexscreener.com/solana/hcgpz2exv8sfcmvq9fjpbd71brljvzutd2avvv86gwbk", - Network accessline 706
"pair_created": "2026-11-01T22:28Z", "pair_url": "https://dexscreener.com/solana/hcgpz2exv8sfcmvq9fjpbd71brljvzutd2avvv86gwbk", "links": [ - Network accessline 707
"pair_url": "https://dexscreener.com/solana/hcgpz2exv8sfcmvq9fjpbd71brljvzutd2avvv86gwbk", - Network accessline 708
"links": [ "https://anakin.meme", "https://x.com/AnakinMemeCoin" - Network accessline 709
"https://anakin.meme", - Network accessline 710
"https://x.com/AnakinMemeCoin" - Network accessline 741
- **30-row caps.** Search, token-pairs and both boost lists returned exactly 30 rows for busy inputs (PEPE, JUP, SOL). There is no page parameter; do not reshape queries to get around it. Use `/tokens/v1` or `/latest/dex/pairs` when you alr - Network accessline 742
- **Unknown inputs are not errors.** Unknown search text gives `{"pairs": []}`, an unknown token `[]`, an unknown pair `{"pairs": null, "pair": null}`, all HTTP 200. - **Do not open the API host root as the fetch tab.** `https://api.dexscre - Network accessline 743
- **Do not open the API host root as the fetch tab.** `https://api.dexscreener.com/` is an HTTP 404 page with `Content-Security-Policy: default-src 'none'`, so every `fetch()` from it fails with `TypeError: Failed to fetch`. `on_api_tab()` - Network accessline 747
- **Plain HTTP:** `curl` to api.dexscreener.com answered 200 today; dexscreener.com answered `curl` with a Cloudflare "Just a moment..." 403, so the New Pairs page needs the browser. If the browser gets a challenge page, `open_site()` stops - Network accessline 749
- **API terms** (https://docs.dexscreener.com/api/api-terms-and-conditions) forbid using the API to build a product that competes directly with DEX Screener. - Network accessline 753
- **New pairs via the API:** no documented endpoint lists new pairs; this skill reads the robots-allowed `/new-pairs` page and only enriches its rows through the API. - **More than 30 search or token-pairs results:** not available from the - Network accessline 755
- **Untested:** `/token-profiles/latest/v1`, `/token-profiles/recent-updates/v1`, `/community-takeovers/latest/v1`, `/ads/latest/v1`, `/metas/*` and `/orders/v1/<chainId>/<tokenAddress>` are documented at 60/min but were not exercised here;
agent-workspace/domain-skills/dice/scraping.md
- Network accessline 23
import http.client, json, re, time, urllib.error, urllib.parse, urllib.request - Network accessline 25
UA = "dice-jobs-research/1.0 (python-urllib; personal job search script)" BASE = "https://www.dice.com" - Network accessline 26
BASE = "https://www.dice.com" MAX_PAGE = 25 # Dice's cap: pages past 25 come back as page 25. Hard stop. PAUSE_S = 2.0 # polite gap between page requests - Network accessline 27
MAX_PAGE = 25 # Dice's cap: pages past 25 come back as page 25. Hard stop. PAUSE_S = 2.0 # polite gap between page requests DEADLINE_S = 120 # one budget per fetch(), across all attempts and backoff - Network accessline 28
PAUSE_S = 2.0 # polite gap between page requests DEADLINE_S = 120 # one budget per fetch(), across all attempts and backoff DELAYS = (5, 15, 40) # backoff between attempts, never after the last one - Network accessline 29
DEADLINE_S = 120 # one budget per fetch(), across all attempts and backoff - Network accessline 52
def fetch(url, attempts=4, deadline_s=DEADLINE_S): - Network accessline 64
raise TimeoutError(f"{deadline_s}s deadline used up for {url}") try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "text/html"}) - Network accessline 65
try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "text/html"}) with urllib.request.urlopen(req, timeout=min(30, left)) as r: - Network accessline 66
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "text/html"}) - Network accessline 67
with urllib.request.urlopen(req, timeout=min(30, left)) as r: - Network accessline 71
raise err = f"HTTP {e.code}" except (urllib.error.URLError, TimeoutError, ConnectionError, http.client.HTTPException) as e: - Network accessline 72
err = f"HTTP {e.code}" except (urllib.error.URLError, TimeoutError, ConnectionError, http.client.HTTPException) as e: if i == attempts - 1: - Network accessline 73
except (urllib.error.URLError, TimeoutError, ConnectionError, http.client.HTTPException) as e: - Network accessline 132
if page > 1: time.sleep(PAUSE_S) jl = parse_joblist(fetch(search_url(keyword, location, page, filters))) - Network accessline 133
time.sleep(PAUSE_S) jl = parse_joblist(fetch(search_url(keyword, location, page, filters))) meta = jl["meta"] - Network accessline 134
jl = parse_joblist(fetch(search_url(keyword, location, page, filters))) - Network accessline 184
{'status': 'partial', 'reason': 'max_pages=3 reached', 'total': 132, 'page_count': 7, 'pages_fetched': 3, 'collected': 60} {"title": "Python Developer - Houston, TX (Locals only)", "company": "Source Mantra Inc", "location": "Houston, Texas - Network accessline 185
{"title": "Python Developer - Houston, TX (Locals only)", "company": "Source Mantra Inc", "location": "Houston, Texas, USA", "workplace": "On-Site", "employment_type": "Third Party, Contract", "posted": "2026-10-23T19:05:49Z", "salary": "$$ - Network accessline 217
if not parts: raise ValueError("need a keyword or a location") url = "https://www.dice.com/jobs/" + "-".join(parts) + "-jobs" - Network accessline 218
raise ValueError("need a keyword or a location") url = "https://www.dice.com/jobs/" + "-".join(parts) + "-jobs" return url if page == 1 else f"{url}?page={page}" - Network accessline 219
url = "https://www.dice.com/jobs/" + "-".join(parts) + "-jobs" - Network accessline 310
{'status': 'partial', 'reason': 'max_pages=2 reached', 'total': 1588, 'pages_fetched': 2, 'collected': 40} {"title": "DevOps Engineer", "company": "Dexian DISYS", "location": "Charlotte, North Carolina, USA", "employment_type": "Contract", - Network accessline 311
{"title": "DevOps Engineer", "company": "Dexian DISYS", "location": "Charlotte, North Carolina, USA", "employment_type": "Contract", "posted": "2026-10-15T20:11:32Z", "url": "https://www.dice.com/job-detail/be07b58c-3595-4790-a5c4-fed0892f9 - Network accessline 324
import http.client, json, re, time, urllib.error, urllib.request - Network accessline 332
def fetch(url, attempts=4, deadline_s=120): - Network accessline 340
raise TimeoutError(f"{deadline_s}s deadline used up for {url}") try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "text/html"}) - Network accessline 341
try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "text/html"}) with urllib.request.urlopen(req, timeout=min(30, left)) as r: - Network accessline 342
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "text/html"}) - Network accessline 343
with urllib.request.urlopen(req, timeout=min(30, left)) as r: - Network accessline 346
if e.code not in (429, 500, 502, 503, 504) or i == attempts - 1: raise except (urllib.error.URLError, TimeoutError, ConnectionError, http.client.HTTPException): - Network accessline 347
raise except (urllib.error.URLError, TimeoutError, ConnectionError, http.client.HTTPException): if i == attempts - 1: - Network accessline 348
except (urllib.error.URLError, TimeoutError, ConnectionError, http.client.HTTPException): - Network accessline 361
def job_detail(detail_url): html = fetch(detail_url) - Network accessline 362
html = fetch(detail_url) - Network accessline 374
# Take a fresh URL from a search page so this does not depend on one posting staying live. first = re.search(r'href="(/job-detail/[0-9a-f-]{36})"', fetch("https://www.dice.com/jobs/q-Python+Developer-jobs")) - Network accessline 375
first = re.search(r'href="(/job-detail/[0-9a-f-]{36})"', fetch("https://www.dice.com/jobs/q-Python+Developer-jobs")) - Network accessline 376
if not first: raise RuntimeError("no job-detail link on the search page") jp = job_detail("https://www.dice.com" + first.group(1)) - Network accessline 377
raise RuntimeError("no job-detail link on the search page") jp = job_detail("https://www.dice.com" + first.group(1)) if jp is None: - Network accessline 378
jp = job_detail("https://www.dice.com" + first.group(1)) - Network accessline 387
print(job_detail("https://www.dice.com/job-detail/00000000-0000-0000-0000-000000000000")) # unknown guid - Network accessline 411
| `postedDate` | `"2026-10-23T19:05:49Z"` | ISO 8601 UTC; `modifiedDate` also present | | `salary` | `"Depends on Experience"` | free text, key missing on some jobs | | `detailsPageUrl` | `"https://www.dice.com/job-detail/<guid>"` | absolut - Network accessline 412
| `salary` | `"Depends on Experience"` | free text, key missing on some jobs | | `detailsPageUrl` | `"https://www.dice.com/job-detail/<guid>"` | absolute URL | | `guid` / `id` | UUID / 32-hex | `guid` is the detail-page id; use it to de-dup - Network accessline 413
| `detailsPageUrl` | `"https://www.dice.com/job-detail/<guid>"` | absolute URL |
agent-workspace/domain-skills/discogs/scraping.md
- Network accessline 9
- **Use the official API first:** `https://api.discogs.com/releases/<id>`, `/masters/<id>`, `/masters/<id>/versions`, `/artists/<id>`, `/artists/<id>/releases`. JSON, no key. One release call has tracklist, labels + catalog numbers, formats - Network accessline 22
API = "https://api.discogs.com" UA = f"browser-harness-discogs-skill/1.0 Python-urllib/{sys.version_info.major}.{sys.version_info.minor}" # truthful, names the client - Network accessline 26
def _robots_rules(base): """Rules of the `User-agent: *` group, Google-style wildcards.""" txt = urllib.request.urlopen(urllib.request.Request(base + "/robots.txt", headers={"User-Agent": UA}), timeout=20).read().decode() - Network accessline 27
"""Rules of the `User-agent: *` group, Google-style wildcards.""" txt = urllib.request.urlopen(urllib.request.Request(base + "/robots.txt", headers={"User-Agent": UA}), timeout=20).read().decode() rules, in_star, prev_ua = [], False - Network accessline 28
txt = urllib.request.urlopen(urllib.request.Request(base + "/robots.txt", headers={"User-Agent": UA}), timeout=20).read().decode() - Network accessline 64
_last[0] = time.time() try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/vnd.discogs.v2.discogs+json"}) - Network accessline 65
try: req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/vnd.discogs.v2.discogs+json"}) with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 66
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/vnd.discogs.v2.discogs+json"}) - Network accessline 67
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 167
{"id": 249504, "artist": "Rick Astley", "title": "Never Gonna Give You Up", "year": 1987, "released": "1987-07-00", "country": "UK", "labels": [["RCA", "PB 41447", 895]], "formats": [{"name": "Vinyl", "qty": "1", "descriptions": ["7\"", "45 - Network accessline 169
{'pos': 'A', 'type': 'track', 'title': 'Never Gonna Give You Up', 'duration': '3:32'} {'pos': 'B', 'type': 'track', 'title': 'Never Gonna Give You Up (Instrumental)', 'duration': '3:30'} {"id": 10398494, "artist": "Pink Floyd", "title": - Network accessline 170
{'pos': 'B', 'type': 'track', 'title': 'Never Gonna Give You Up (Instrumental)', 'duration': '3:30'} {"id": 10398494, "artist": "Pink Floyd", "title": "Pink Floyd", "year": 1988, "released": "1988", "country": "Australia", "labels": [["EMI" - Network accessline 171
{"id": 10398494, "artist": "Pink Floyd", "title": "Pink Floyd", "year": 1988, "released": "1988", "country": "Australia", "labels": [["EMI", "PFB1", 26126]], "formats": [{"name": "Vinyl", "qty": "12", "descriptions": ["LP"], "text": null}, - Network accessline 199
WWW = "https://www.discogs.com" - Network accessline 274
if any(s in low for s in ("just a moment", "verify you are human", "access denied", "attention required")): raise SystemExit(f"challenge on {href}: stop and back off, do not retry") final = re.sub(r"^https://www\.discogs - Network accessline 275
raise SystemExit(f"challenge on {href}: stop and back off, do not retry") final = re.sub(r"^https://www\.discogs\.com", "", href) if not robots_allowed(rules, final): - Network accessline 276
final = re.sub(r"^https://www\.discogs\.com", "", href) - Network accessline 314
robots: /release/249504 True | /release/add False | /release/stats/249504 False | /artist2 False {"id": 249504, "title": "Never Gonna Give You Up", "artists": [["Rick Astley", "", 72872]], "year": 1987, "released": "1987-07-00", "country": - Network accessline 315
{"id": 249504, "title": "Never Gonna Give You Up", "artists": [["Rick Astley", "", 72872]], "year": 1987, "released": "1987-07-00", "country": "UK", "labels": [["RCA", "PB 41447", 895]], "formats": [{"name": "Vinyl", "qty": "1", "descriptio - Network accessline 317
{'pos': 'A', 'type': 'track', 'title': 'Never Gonna Give You Up', 'seconds': 212} {'pos': 'B', 'type': 'track', 'title': 'Never Gonna Give You Up (Instrumental)', 'seconds': 210} {"id": 10398494, "title": "Pink Floyd", "artists": [["Pin - Network accessline 318
{'pos': 'B', 'type': 'track', 'title': 'Never Gonna Give You Up (Instrumental)', 'seconds': 210} {"id": 10398494, "title": "Pink Floyd", "artists": [["Pink Floyd", "", 45467]], "year": 1988, "released": "1988", "country": "Australia", "labe - Network accessline 319
{"id": 10398494, "title": "Pink Floyd", "artists": [["Pink Floyd", "", 45467]], "year": 1988, "released": "1988", "country": "Australia", "labels": [["EMI", "PFB1", 26126]], "formats": [{"name": "Vinyl", "qty": "12", "descriptions": ["LP"], - Network accessline 366
- Community counts can differ by a few between the API and the page (`want` 388 vs 385 for 10398494 in the same hour); they are cached separately. - `api.discogs.com/database/search?q=...` answered HTTP 200 without a token on 2026-11-01 (59 - Network accessline 367
[Credential-related source omitted] - Network accessline 368
- In-page `fetch("https://api.discogs.com/...")` from a www.discogs.com tab worked (CORS, HTTP 200), but the rate-limit headers are not readable cross-origin. Prefer block 1.
agent-workspace/domain-skills/doordash/search-and-product-pages.md
- Network accessline 3
The contributor tested `doordash.com` on 2026-09-26 through browser-harness with a logged-in desktop Chrome session. The contributor reports approximately 600 searches and 100 product pages. Each request uses in-page `fetch()` from an open - Network accessline 4
The contributor reports approximately 600 searches and 100 product pages. Each request uses in-page `fetch()` from an open `doordash.com` tab. The requests use the existing session and delivery address. - Network accessline 5
Each request uses in-page `fetch()` from an open `doordash.com` tab. - Network accessline 118
- `https://www.doordash.com/convenience/store/<store_id>/product/<item_id>` → redirects to - Network accessline 119
`/convenience/store/<store_id>?product_id=<item_id>` and opens that product's modal at that store. - `https://www.doordash.com/browse/products/<dd_sic>` → `/products/<slug>/<dd_sic>`, the cross-store page. - `/convenience/store/<store_id>/i - Network accessline 120
- `https://www.doordash.com/browse/products/<dd_sic>` → `/products/<slug>/<dd_sic>`, the cross-store page.
agent-workspace/domain-skills/duckduckgo/scraping.md
- Network accessline 3
`https://api.duckduckgo.com` — completely public, no auth, no API key. Returns Wikipedia-sourced abstracts, infoboxes, and instant answers for well-known entities, calculations, and utility queries. Not a search engine — it does not return - Network accessline 27
q = urllib.parse.quote(query) raw = http_get( f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&skip_disambig=1" - Network accessline 28
raw = http_get( f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&skip_disambig=1" ) - Network accessline 29
f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&skip_disambig=1" - Network accessline 36
print(data['Heading']) # 'OpenAI' print(data['AbstractText']) # 'OpenAI is an American artificial intelligence research...' print(data['AbstractURL']) # 'https://en.wikipedia.org/wiki/OpenAI' - Network accessline 37
print(data['AbstractText']) # 'OpenAI is an American artificial intelligence research...' print(data['AbstractURL']) # 'https://en.wikipedia.org/wiki/OpenAI' print(data['OfficialWebsite'])# 'https://openai.com/' - Network accessline 38
print(data['AbstractURL']) # 'https://en.wikipedia.org/wiki/OpenAI' - Network accessline 39
print(data['OfficialWebsite'])# 'https://openai.com/' - Network accessline 44
print(data['Type']) # 'A' (was 'D' without skip_disambig) print(data['AbstractText'][:100]) # 'Elon Reeve Musk is a businessman...' print(data['Image']) # '/i/be2a8644.jpg' — prepend https://duckduckgo.com - Network accessline 46
print(data['Image']) # '/i/be2a8644.jpg' — prepend https://duckduckgo.com - Network accessline 48
# Full image URL img_url = f"https://duckduckgo.com{data['Image']}" if data['Image'] else None - Network accessline 49
img_url = f"https://duckduckgo.com{data['Image']}" if data['Image'] else None - Network accessline 62
q = urllib.parse.quote(query) raw = http_get( f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&no_redirect=1" - Network accessline 63
raw = http_get( f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&no_redirect=1" ) - Network accessline 64
f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&no_redirect=1" - Network accessline 122
Entity # entity type: "company", "programming language", "person", etc. Heading # entity display name Image # relative path e.g. "/i/4d83768732377cf3.png" — prepend https://duckduckgo.com - Network accessline 123
Heading # entity display name Image # relative path e.g. "/i/4d83768732377cf3.png" — prepend https://duckduckgo.com ImageHeight # int or "" when no image - Network accessline 124
Image # relative path e.g. "/i/4d83768732377cf3.png" — prepend https://duckduckgo.com - Network accessline 128
Infobox # dict with "content" and "meta" lists, or "" if no infobox OfficialDomain # e.g. "openai.com" — only for entities with a known website OfficialWebsite # e.g. "https://openai.com/" — only when DDG knows it - Network accessline 129
OfficialDomain # e.g. "openai.com" — only for entities with a known website OfficialWebsite # e.g. "https://openai.com/" — only when DDG knows it Redirect # target URL when query is a bang (e.g. !g python) with no_redirect=1 - Network accessline 130
OfficialWebsite # e.g. "https://openai.com/" — only when DDG knows it - Network accessline 144
{ "FirstURL": "https://duckduckgo.com/Deep_learning", - Network accessline 145
"FirstURL": "https://duckduckgo.com/Deep_learning", - Network accessline 163
For A-type results, `RelatedTopics` are Wikipedia category links (e.g. `"American aerospace engineers"` pointing to `https://duckduckgo.com/c/...`). These are not web search results — they are DDG topic pages. - Network accessline 169
{ "FirstURL": "https://www.apple.com/", - Network accessline 170
"FirstURL": "https://www.apple.com/", - Network accessline 171
"Icon": {"Height": 16, "URL": "/i/apple.com.ico", "Width": 16}, "Result": "<a href=\"https://www.apple.com/\">Official site</a>...", "Text": "Official site" - Network accessline 172
"Result": "<a href=\"https://www.apple.com/\">Official site</a>...", - Network accessline 176
Icon URLs in `Results` are relative — prepend `https://duckduckgo.com`. - Network accessline 265
**Image and Icon URLs are relative.** `data['Image']` is `/i/abc123.png`. Prepend `https://duckduckgo.com` to make it absolute. Same for Icon URLs in `RelatedTopics` and `Results`. - Network accessline 300
q = urllib.parse.quote(query) raw = http_get( f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&skip_disambig=1" - Network accessline 301
raw = http_get( f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&skip_disambig=1" ) - Network accessline 302
f"https://api.duckduckgo.com/?q={q}&format=json&no_html=1&skip_disambig=1" - Network accessline 313
'entity': data['Entity'], 'official_website': data['OfficialWebsite'], 'image': f"https://duckduckgo.com{data['Image']}" if data['Image'] else None, - Network accessline 314
'official_website': data['OfficialWebsite'], 'image': f"https://duckduckgo.com{data['Image']}" if data['Image'] else None, 'answer': data['Answer'] if isinstance(data['Answer'], str) else None, - Network accessline 315
'image': f"https://duckduckgo.com{data['Image']}" if data['Image'] else None, - Network accessline 337
# r['abstract'][:50] == 'OpenAI is an American artificial intelligence res' # r['entity'] == 'company' # r['official_website']== 'https://openai.com/' - Network accessline 338
# r['entity'] == 'company' # r['official_website']== 'https://openai.com/' # r['image'] == 'https://duckduckgo.com/i/fb410946942ab334.png' - Network accessline 339
# r['official_website']== 'https://openai.com/' - Network accessline 340
# r['image'] == 'https://duckduckgo.com/i/fb410946942ab334.png' - Network accessline 345
# r['type'] == 'A' # r['entity'] == 'programming language' # r['official_website']== 'https://www.python.org/' - Network accessline 346
# r['entity'] == 'programming language' # r['official_website']== 'https://www.python.org/' # r['infobox']['Paradigm'] == 'Multi-paradigm: object-oriented,...' - Network accessline 347
# r['official_website']== 'https://www.python.org/'
agent-workspace/domain-skills/ebay/scraping.md
- Access to secretsline 4
[Credential-related source omitted] - Access to secretsline 8
[Credential-related source omitted] - Network accessline 58
html = safe_get("https://www.ebay.com/sch/i.html?_nkw=laptop&LH_BIN=1", HEADERS) - Network accessline 81
https://www.ebay.com/sch/i.html?_nkw={query}&{filters} - Network accessline 86
# Buy It Now only, sorted by lowest price "https://www.ebay.com/sch/i.html?_nkw=mechanical+keyboard&LH_BIN=1&_sop=15" - Network accessline 87
"https://www.ebay.com/sch/i.html?_nkw=mechanical+keyboard&LH_BIN=1&_sop=15" - Network accessline 89
# Auctions only "https://www.ebay.com/sch/i.html?_nkw=vintage+camera&LH_Auction=1" - Network accessline 90
"https://www.ebay.com/sch/i.html?_nkw=vintage+camera&LH_Auction=1" - Network accessline 92
# New condition only, page 2 "https://www.ebay.com/sch/i.html?_nkw=laptop&LH_ItemCondition=1000&_pgn=2" - Network accessline 93
"https://www.ebay.com/sch/i.html?_nkw=laptop&LH_ItemCondition=1000&_pgn=2" - Network accessline 135
https://www.ebay.com/itm/{listing_id} - Network accessline 151
|------|---------| | Listing ID | `data-listingid=(\d+)` on the `<li>` | | Item URL | `href=(https://(?:www\.)?ebay\.com/itm/(\d+))` | - Network accessline 152
| Listing ID | `data-listingid=(\d+)` on the `<li>` | | Item URL | `href=(https://(?:www\.)?ebay\.com/itm/(\d+))` | | Title | `s-card__title` > `su-styled-text primary` > text | - Network accessline 153
| Item URL | `href=(https://(?:www\.)?ebay\.com/itm/(\d+))` | - Network accessline 187
# Item URL (clean, no tracking params) url_m = re.search(r'href=["\']?(https://(?:www\.)?ebay\.com/itm/(\d+))', card) - Network accessline 188
url_m = re.search(r'href=["\']?(https://(?:www\.)?ebay\.com/itm/(\d+))', card) - Network accessline 233
html = safe_get("https://www.ebay.com/sch/i.html?_nkw=mechanical+keyboard&LH_BIN=1&_sop=15", headers=HEADERS) - Network accessline 352
html = safe_get("https://www.ebay.com/itm/167040158614", headers=HEADERS) - Network accessline 365
# 'shipping': 'Free', # 'return_days': 30, # 'images': ['https://i.ebayimg.com/images/g/vwsAAeSwEcFpw~hW/s-l1600.jpg', ...], # 5 images - Network accessline 366
# 'return_days': 30, # 'images': ['https://i.ebayimg.com/images/g/vwsAAeSwEcFpw~hW/s-l1600.jpg', ...], # 5 images # 'gtin13': '097855189066', - Network accessline 367
# 'images': ['https://i.ebayimg.com/images/g/vwsAAeSwEcFpw~hW/s-l1600.jpg', ...], # 5 images - Network accessline 404
for page in range(1, 4): url = f"https://www.ebay.com/sch/i.html?_nkw=laptop&LH_BIN=1&_sop=15&_pgn={page}" - Network accessline 405
url = f"https://www.ebay.com/sch/i.html?_nkw=laptop&LH_BIN=1&_sop=15&_pgn={page}" - Network accessline 443
# Step 1: Search html = safe_get( "https://www.ebay.com/sch/i.html?_nkw=mechanical+keyboard&LH_BIN=1&_sop=15&LH_ItemCondition=1000", - Network accessline 444
html = safe_get( "https://www.ebay.com/sch/i.html?_nkw=mechanical+keyboard&LH_BIN=1&_sop=15&LH_ItemCondition=1000", headers=HEADERS - Network accessline 445
"https://www.ebay.com/sch/i.html?_nkw=mechanical+keyboard&LH_BIN=1&_sop=15&LH_ItemCondition=1000", - Network accessline 480
- **Item URLs have tracking params** — Raw extracted URLs look like `https://www.ebay.com/itm/167040158614?_skw=...&epid=...&hash=...&itmprp=...`. Always strip to `itm/{id}` with `.split('?')[0]`. - Network accessline 488
- **Condition in JSON-LD is a schema.org URL** — `offers.itemCondition` returns `"https://schema.org/RefurbishedCondition"`, not a human label. Split on `/` and map the last segment using `CONDITION_MAP` (see `extract_item_detail` above).
agent-workspace/domain-skills/espn/scraping.md
- Network accessline 23
BASE = "https://www.espn.com" - Network accessline 26
# longest matching pattern wins, Allow wins a tie. def _robots_rules(): txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() - Network accessline 27
def _robots_rules(): txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() rules, in_star, prev_ua = [], False, False - Network accessline 28
txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode()
agent-workspace/domain-skills/etsy/scraping.md
- Network accessline 18
Etsy uses [DataDome](https://datadome.co/) for every user-facing HTML endpoint. - Network accessline 38
<script>var dd={'rt':'c','cid':'...','hsh':'D013AA...','t':'bv', 'host':'geo.captcha-delivery.com','cookie':'...'}</script> <script src="https://ct.captcha-delivery.com/c.js"></script> - Network accessline 39
'host':'geo.captcha-delivery.com','cookie':'...'}</script> <script src="https://ct.captcha-delivery.com/c.js"></script> </body> - Network accessline 40
<script src="https://ct.captcha-delivery.com/c.js"></script> - Network accessline 78
from helpers import http_get text = http_get("https://www.etsy.com/robots.txt") - Network accessline 79
text = http_get("https://www.etsy.com/robots.txt") - Network accessline 87
The `openapi.etsy.com/v3/` endpoint is NOT DataDome-protected. It returns structured JSON but requires a free API key from [developer.etsy.com](https://developer.etsy.com/). - Access to secretsline 93
[Credential-related source omitted] - Network accessline 96
from urllib.parse import urlencode qs = urlencode(params) url = f"https://openapi.etsy.com/v3/application/{path}?{qs}" - Network accessline 97
[Credential-related source omitted] - Network accessline 98
url = f"https://openapi.etsy.com/v3/application/{path}?{qs}" - Access to secretsline 99
[Credential-related source omitted] - Network accessline 141
results[i].shipping_profile_id → int results[i].shop_id → int results[i].url → "https://www.etsy.com/listing/..." - Network accessline 142
results[i].shop_id → int results[i].url → "https://www.etsy.com/listing/..." results[i].views → int - Network accessline 143
results[i].url → "https://www.etsy.com/listing/..." - Network accessline 166
# Always use new_tab() for the first Etsy navigation in a session tid = new_tab("https://www.etsy.com/search?q=handmade+candle&explicit=1") - Network accessline 167
tid = new_tab("https://www.etsy.com/search?q=handmade+candle&explicit=1") - Network accessline 175
https://www.etsy.com/search?q={query}&explicit=1 - Network accessline 226
# ld_json_str.itemListElement is a list of: # { '@type': 'ListItem', 'position': 1, # 'url': 'https://www.etsy.com/listing/...', 'name': 'Handmade Soy Candle' } - Network accessline 227
# { '@type': 'ListItem', 'position': 1, # 'url': 'https://www.etsy.com/listing/...', 'name': 'Handmade Soy Candle' } for item in ld_json_str.get('itemListElement', []): - Network accessline 228
# 'url': 'https://www.etsy.com/listing/...', 'name': 'Handmade Soy Candle' } - Network accessline 235
1 https://www.etsy.com/listing/1234567890/handmade-soy-candle "Handmade Soy Candle" - Network accessline 236
2 https://www.etsy.com/listing/0987654321/beeswax-pillar-candle "Beeswax Pillar Candle" - Network accessline 243
goto_url("https://www.etsy.com/listing/1234567890/product-slug") - Network accessline 264
# product['offers']['price'] → e.g. "25.99" # product['offers']['priceCurrency'] → "USD" # product['offers']['availability'] → "http://schema.org/InStock" - Network accessline 265
# product['offers']['priceCurrency'] → "USD" # product['offers']['availability'] → "http://schema.org/InStock" # product['brand']['name'] → shop name (seller) - Network accessline 266
# product['offers']['availability'] → "http://schema.org/InStock" - Network accessline 295
goto_url("https://www.etsy.com/shop/ShopName") - Network accessline 350
# Or construct directly: goto_url(f"https://www.etsy.com/search?q=handmade+candle&explicit=1&page={page_num}") - Network accessline 351
goto_url(f"https://www.etsy.com/search?q=handmade+candle&explicit=1&page={page_num}") - Network accessline 381
"description": "These beautiful hand-dipped candles...", "image": [ "https://i.etsystatic.com/12345678/r/il/abc123/1234567890/il_1588xN.1234567890.jpg" - Network accessline 382
"image": [ "https://i.etsystatic.com/12345678/r/il/abc123/1234567890/il_1588xN.1234567890.jpg" ], - Network accessline 383
"https://i.etsystatic.com/12345678/r/il/abc123/1234567890/il_1588xN.1234567890.jpg" - Network accessline 388
"price": "32.00", "priceCurrency": "USD", "availability": "http://schema.org/InStock", - Network accessline 389
"priceCurrency": "USD", "availability": "http://schema.org/InStock", "url": "https://www.etsy.com/listing/1234567890/..." - Network accessline 390
"availability": "http://schema.org/InStock", - Network accessline 391
"url": "https://www.etsy.com/listing/1234567890/..." - Network accessline 410
"@type": "ListItem", "position": 1, "url": "https://www.etsy.com/listing/1234567890/handmade-beeswax-candle", - Network accessline 411
"position": 1, "url": "https://www.etsy.com/listing/1234567890/handmade-beeswax-candle", "name": "Handmade Beeswax Taper Candles, Set of 12" - Network accessline 412
"url": "https://www.etsy.com/listing/1234567890/handmade-beeswax-candle", - Network accessline 425
The official API at `openapi.etsy.com/v3/` bypasses DataDome entirely. It requires a free API key from [developer.etsy.com](https://developer.etsy.com/) (no payment needed; approval is automatic for basic read access). - Access to secretsline 460
[Credential-related source omitted] - Network accessline 465
limit = 100 while offset < max_results: url = (f"https://openapi.etsy.com/v3/application/listings/active" - Network accessline 466
while offset < max_results: url = (f"https://openapi.etsy.com/v3/application/listings/active" f"?keywords={keywords}&limit={limit}&offset={offset}" - Network accessline 467
url = (f"https://openapi.etsy.com/v3/application/listings/active" - Access to secretsline 470
[Credential-related source omitted] - Network accessline 486
- **DataDome detects TLS fingerprint.** The challenge runs JavaScript at `geo.captcha-delivery.com`. Even curl with perfect browser headers returns 403 — the HTTP library's TLS handshake is fingerprinted. - Network accessline 492
- **Listing slug is optional.** `https://www.etsy.com/listing/1234567890` works without the slug; Etsy redirects to the canonical URL with the full slug.
agent-workspace/domain-skills/eventbrite/scraping.md
- Network accessline 3
`https://www.eventbrite.com` — public event listings and detail pages, no auth required for HTML scraping. REST API requires an OAuth token. - Network accessline 12
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"} html = http_get("https://www.eventbrite.com/d/ca--san-francisco/tech/", headers=headers) - Network accessline 13
html = http_get("https://www.eventbrite.com/d/ca--san-francisco/tech/", headers=headers) - Network accessline 33
https://www.eventbrite.com/d/{location}/{category}/ - Network accessline 34
https://www.eventbrite.com/d/{location}/{category}/?page=2 - Network accessline 35
https://www.eventbrite.com/d/{location}/{category}/?start_date=2026-05-01&end_date=2026-05-31 - Network accessline 71
https://www.eventbrite.com/e/{slug}-tickets-{event_id} - Network accessline 74
Example: `https://www.eventbrite.com/e/icontact-the-tactile-tech-opera-tickets-1982861003639` - Network accessline 92
"name": "iContact the tactile tech opera", "description": "An immersive performance...", "url": "https://www.eventbrite.com/e/icontact-the-tactile-tech-opera-tickets-1982861003639", - Network accessline 93
"description": "An immersive performance...", "url": "https://www.eventbrite.com/e/icontact-the-tactile-tech-opera-tickets-1982861003639", "image": "https://img.evbuc.com/...", - Network accessline 94
"url": "https://www.eventbrite.com/e/icontact-the-tactile-tech-opera-tickets-1982861003639", - Network accessline 95
"image": "https://img.evbuc.com/...", - Network accessline 96
"startDate": "2026-06-21", "endDate": "2026-06-21", "eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode", - Network accessline 97
"endDate": "2026-06-21", "eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode", "location": { - Network accessline 98
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode", - Network accessline 131
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"} html = http_get("https://www.eventbrite.com/e/icontact-the-tactile-tech-opera-tickets-1982861003639", headers=headers) - Network accessline 132
html = http_get("https://www.eventbrite.com/e/icontact-the-tactile-tech-opera-tickets-1982861003639", headers=headers) - Network accessline 143
print(event_data['startDate']) # "2026-06-21T17:05:00-07:00" (ISO 8601 with TZ) print(event_data['endDate']) # "2026-06-21T20:08:00-07:00" print(event_data['eventStatus']) # "https://schema.org/EventScheduled" - Network accessline 144
print(event_data['endDate']) # "2026-06-21T20:08:00-07:00" print(event_data['eventStatus']) # "https://schema.org/EventScheduled" print(event_data['eventAttendanceMode']) # "https://schema.org/OfflineEventAttendanceMode" - Network accessline 145
print(event_data['eventStatus']) # "https://schema.org/EventScheduled" - Network accessline 146
print(event_data['eventAttendanceMode']) # "https://schema.org/OfflineEventAttendanceMode" - Network accessline 148
print(event_data['location']['address']['streetAddress']) # "94107 1661 Tennessee Street, San Francisco, CA 94107" print(event_data['organizer']['name']) # "Beth McNamara" print(event_data['organizer']['url']) # "https://www.eventbrite - Network accessline 150
print(event_data['organizer']['url']) # "https://www.eventbrite.com/o/beth-mcnamara-120755148166" - Network accessline 268
"""Returns list of event dicts with name, url, startDate, endDate, location.""" headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"} url = f"https://www.eventbrite.com/d/{location}/{category - Network accessline 269
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"} url = f"https://www.eventbrite.com/d/{location}/{category}/?page={page}" html = http_get(url, headers=headers) - Network accessline 270
url = f"https://www.eventbrite.com/d/{location}/{category}/?page={page}" - Network accessline 319
The Eventbrite REST API (`https://www.eventbriteapi.com/v3/`) requires an OAuth token for all endpoints: - Access to secretsline 329
[Credential-related source omitted] - Network accessline 332
[Credential-related source omitted] - Network accessline 334
data = json.loads(http_get(f"https://www.eventbriteapi.com/v3/events/{event_id}/", headers=headers)) - Network accessline 341
- **`re.findall(r'href="https://www.eventbrite.com/e/...')` returns 0 results** — Confirmed: event cards in the HTML do not have `https://www.eventbrite.com/e/` in href attributes. Use JSON-LD extraction only.
agent-workspace/domain-skills/expedia/api.md
- Network accessline 9
GET https://www.expedia.mx/api/v4/typeahead/{url-encoded query} - Network accessline 25
- Canonical shape: `https://www.expedia.mx/{slug}.h{hotelId}.Informacion-Hotel` - Network accessline 30
`rm1=a{adults}[:c{age}...]` (e.g. `rm1=a2:c8:c5`), `expediaPropertyId={id}`. These pre-fill dates and occupancy on the page. - Search fallback: `https://www.expedia.mx/Hotel-Search?destination={name}, - Network accessline 31
These pre-fill dates and occupancy on the page. - Search fallback: `https://www.expedia.mx/Hotel-Search?destination={name}, {city}&startDate=…&endDate=…&adults=N&rooms=1`. - Network accessline 32
- Search fallback: `https://www.expedia.mx/Hotel-Search?destination={name}, - Network accessline 37
`GET` on property pages returned HTTP 429 from a residential-but-curl client - Network accessline 59
- To mint these programmatically, don't reconstruct the chain — use the Travelpayouts links API: `POST https://api.travelpayouts.com/links/v1/create` with - Network accessline 60
Travelpayouts links API: `POST https://api.travelpayouts.com/links/v1/create` with `{"trs": <project id>, "marker": <partner id>, "shorten": true, - Network accessline 61
`POST https://api.travelpayouts.com/links/v1/create` with
agent-workspace/domain-skills/expedia/automation.md
agent-workspace/domain-skills/expedia/flights-search.md
- Network accessline 31
https://www.expedia.ca/Flights-Search?flight-type=roundtrip&mode=search&trip=roundtrip&leg1=from:YYZ,to:ICN,departure:2027/07/03TANYT&leg2=from:ICN,to:YYZ,departure:2027/07/25TANYT&passengers=adults:1&options=cabin:economy&sort=price%3Aa - Network accessline 47
search_url = "https://www.expedia.ca/Flights-Search?flight-type=roundtrip&mode=search&trip=roundtrip&leg1=from:YYZ,to:ICN,departure:2027/07/03TANYT&leg2=from:ICN,to:YYZ,departure:2027/07/25TANYT&passengers=adults:1&options=cabin:economy&sor - Network accessline 62
When navigating to `https://www.expedia.ca/Flights` directly, the page has:
agent-workspace/domain-skills/facebook/groups.md
- Network accessline 19
| What | URL | |------|-----| | Group main feed | `https://www.facebook.com/groups/{id_or_slug}` | - Network accessline 20
|------|-----| | Group main feed | `https://www.facebook.com/groups/{id_or_slug}` | | Group "Discussion" tab (canonical feed) | `https://www.facebook.com/groups/{id_or_slug}/?sorting_setting=CHRONOLOGICAL` | - Network accessline 21
| Group main feed | `https://www.facebook.com/groups/{id_or_slug}` | - Network accessline 22
| Group "Discussion" tab (canonical feed) | `https://www.facebook.com/groups/{id_or_slug}/?sorting_setting=CHRONOLOGICAL` | - Network accessline 23
| Single post (permalink) | `https://www.facebook.com/groups/{id_or_slug}/posts/{post_id}/` | - Network accessline 24
| User's joined-groups feed | `https://www.facebook.com/groups/feed/` | - Network accessline 25
| List of YOUR groups | `https://www.facebook.com/groups/joins/` | - Network accessline 41
| Post author | `h3 a, h4 a` (first inside the article) | Falls back to `strong a` | | Post timestamp | `a[href*="/posts/"] abbr, a[role="link"] > span > span` (relative time text) | Hover gets the absolute time but the relative string is f - Network accessline 42
| Post timestamp | `a[href*="/posts/"] abbr, a[role="link"] > span > span` (relative time text) | Hover gets the absolute time but the relative string is fine for sorting | | External link (FB redirector) | `a[href^="https://l.facebook.com/ - Network accessline 43
| External link (FB redirector) | `a[href^="https://l.facebook.com/l.php?u="]` | Decode the `u=` param to get the real URL | - Network accessline 65
const author = el.querySelector('h3 a, h4 a, strong a'); const time = el.querySelector('abbr, a[role="link"] > span > span'); const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')) - Network accessline 66
const time = el.querySelector('abbr, a[role="link"] > span > span'); const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')) .map(a => a.href); - Network accessline 67
const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')) - Network accessline 92
Every external link gets wrapped in `https://l.facebook.com/l.php?u={URL-encoded real URL}&h=...`. - Network accessline 96
from urllib.parse import urlparse, parse_qs, unquote def decode_fb_link(href): if not href.startswith("https://l.facebook.com/l.php"): - Network accessline 97
def decode_fb_link(href): if not href.startswith("https://l.facebook.com/l.php"): return href - Network accessline 98
if not href.startswith("https://l.facebook.com/l.php"): - Network accessline 154
body_preview_a: document.querySelectorAll('div[data-ad-preview="message"]').length, body_preview_b: document.querySelectorAll('div[data-ad-comet-preview="message"]').length, external_redirectors: document.querySelectorAll('a[href^=" - Network accessline 155
body_preview_b: document.querySelectorAll('div[data-ad-comet-preview="message"]').length, external_redirectors: document.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]').length, permalink_posts: document.querySelectorA - Network accessline 156
external_redirectors: document.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]').length, - Network accessline 178
goto_url(f"https://www.facebook.com/groups/{GROUP}/?sorting_setting=CHRONOLOGICAL") - Network accessline 193
const author = el.querySelector('h3 a, h4 a, strong a'); const time = el.querySelector('abbr, a[role="link"] > span > span'); const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')).ma - Network accessline 194
const time = el.querySelector('abbr, a[role="link"] > span > span'); const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')).map(a => a.href); return { url: link?.href, author: author? - Network accessline 195
const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')).map(a => a.href); - Network accessline 207
def decode(u): if not u.startswith("https://l.facebook.com/l.php"): return u - Network accessline 208
if not u.startswith("https://l.facebook.com/l.php"): return u
agent-workspace/domain-skills/facebook/pages.md
- Network accessline 28
| What | URL | |------|-----| | Page main feed (default tab) | `https://www.facebook.com/{vanity_or_id}` | - Network accessline 29
|------|-----| | Page main feed (default tab) | `https://www.facebook.com/{vanity_or_id}` | | Page Posts tab (canonical post feed) | `https://www.facebook.com/{vanity_or_id}/posts` | - Network accessline 30
| Page main feed (default tab) | `https://www.facebook.com/{vanity_or_id}` | - Network accessline 31
| Page Posts tab (canonical post feed) | `https://www.facebook.com/{vanity_or_id}/posts` | - Network accessline 32
| Page About | `https://www.facebook.com/{vanity_or_id}/about` | - Network accessline 33
| Page Reviews | `https://www.facebook.com/{vanity_or_id}/reviews` | - Network accessline 34
| Page Videos | `https://www.facebook.com/{vanity_or_id}/videos` | - Network accessline 35
| Page Events | `https://www.facebook.com/{vanity_or_id}/events` | - Network accessline 36
| Single post (vanity permalink) | `https://www.facebook.com/{vanity_or_id}/posts/pfbid{...}` | - Network accessline 37
| Single post (legacy permalink) | `https://www.facebook.com/permalink.php?story_fbid={story_id}&id={page_id}` | - Network accessline 38
| Single post (story permalink) | `https://www.facebook.com/story.php?story_fbid={story_id}&id={page_id}` | - Network accessline 39
| Page-search (find a Page by name) | `https://www.facebook.com/search/pages/?q={query}` | - Network accessline 55
| Follower/like count | `a[href$="/followers/"], a[href$="/friends_likes/"]` | Text node contains the count — parse with a regex | | Category line | `div[role="main"] span:has(a[href*="/pages/category/"])` | Sits under the name in the heade - Network accessline 56
| Category line | `div[role="main"] span:has(a[href*="/pages/category/"])` | Sits under the name in the header | | Website link in header | `a[href^="https://l.facebook.com/l.php"][href*="u="]` inside the About rail | Same redirector wrappe - Network accessline 57
| Website link in header | `a[href^="https://l.facebook.com/l.php"][href*="u="]` inside the About rail | Same redirector wrapper as post links — decode before using | - Network accessline 61
| Post author | `h3 a, h4 a, strong a` | On a Page, this is always the Page itself — useful only for sanity checking you're still on the right Page | | Post timestamp | `a[href*="/posts/"] abbr, a[role="link"] > span > span` | Hover returns - Network accessline 62
| Post timestamp | `a[href*="/posts/"] abbr, a[role="link"] > span > span` | Hover returns absolute time; relative string is fine for sorting | | External link (FB redirector) | `a[href^="https://l.facebook.com/l.php?u="]` | Decode the `u=` - Network accessline 63
| External link (FB redirector) | `a[href^="https://l.facebook.com/l.php?u="]` | Decode the `u=` param | - Network accessline 83
.find(a => /friends_likes$/.test(a.getAttribute('href')||''))?.innerText) || null, category: (Array.from(document.querySelectorAll('a[href*="/pages/category/"]'))[0]?.innerText) || null, website_redirector: (Array.from(document.quer - Network accessline 84
category: (Array.from(document.querySelectorAll('a[href*="/pages/category/"]'))[0]?.innerText) || null, website_redirector: (Array.from(document.querySelectorAll('a[href^="https://l.facebook.com/l.php"]')) .find(a => !a.closest('d - Network accessline 85
website_redirector: (Array.from(document.querySelectorAll('a[href^="https://l.facebook.com/l.php"]')) - Network accessline 107
const body = el.querySelector('div[data-ad-preview="message"], div[data-ad-comet-preview="message"]'); const time = el.querySelector('abbr, a[role="link"] > span > span'); const externals = Array.from(el.querySelectorAll('a[ - Network accessline 108
const time = el.querySelector('abbr, a[role="link"] > span > span'); const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')) .map(a => a.href); - Network accessline 109
const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')) - Network accessline 136
Identical to groups.md — every outbound link is wrapped in `https://l.facebook.com/l.php?u={URL-encoded real URL}&h=...`. Strip the wrapper. - Network accessline 137
`https://l.facebook.com/l.php?u={URL-encoded real URL}&h=...`. Strip the wrapper. - Network accessline 140
from urllib.parse import urlparse, parse_qs, unquote def decode_fb_link(href): if not href.startswith("https://l.facebook.com/l.php"): - Network accessline 141
def decode_fb_link(href): if not href.startswith("https://l.facebook.com/l.php"): return href - Network accessline 142
if not href.startswith("https://l.facebook.com/l.php"): - Network accessline 183
body_preview_a: document.querySelectorAll('div[data-ad-preview="message"]').length, body_preview_b: document.querySelectorAll('div[data-ad-comet-preview="message"]').length, external_redirectors: document.querySelectorAll('a[href^=" - Network accessline 184
body_preview_b: document.querySelectorAll('div[data-ad-comet-preview="message"]').length, external_redirectors: document.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]').length, pfbid_posts: document.querySelectorAll(' - Network accessline 185
external_redirectors: document.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]').length, - Network accessline 208
goto_url(f"https://www.facebook.com/{PAGE}/posts") - Network accessline 222
followers: (Array.from(document.querySelectorAll('a')) .find(a => /followers$/.test(a.getAttribute('href')||''))?.innerText) || null, website_redirector: (Array.from(document.querySelectorAll('a[href^="https://l.facebook.com/l.php - Network accessline 223
.find(a => /followers$/.test(a.getAttribute('href')||''))?.innerText) || null, website_redirector: (Array.from(document.querySelectorAll('a[href^="https://l.facebook.com/l.php"]')) .find(a => !a.closest('div[role="article"]'))?.hr - Network accessline 224
website_redirector: (Array.from(document.querySelectorAll('a[href^="https://l.facebook.com/l.php"]')) - Network accessline 236
const body = el.querySelector('div[data-ad-preview="message"], div[data-ad-comet-preview="message"]'); const time = el.querySelector('abbr, a[role="link"] > span > span'); const externals = Array.from(el.querySelectorAll('a[ - Network accessline 237
const time = el.querySelector('abbr, a[role="link"] > span > span'); const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')).map(a => a.href); return { url: link?.href, time: time?.inn - Network accessline 238
const externals = Array.from(el.querySelectorAll('a[href^="https://l.facebook.com/l.php?u="]')).map(a => a.href); - Network accessline 252
def decode(u): if not u.startswith("https://l.facebook.com/l.php"): return u - Network accessline 253
if not u.startswith("https://l.facebook.com/l.php"): return u
agent-workspace/domain-skills/feishu/docx-scraping.md
- Possible obfuscationline 110
t = t.replace("<U+200B>","").replace("<U+FEFF>","").replace("<U+2060>","")
agent-workspace/domain-skills/figma/comments.md
- Network accessline 12
GET https://www.figma.com/api/file/<FILE_KEY>/comments - Network accessline 19
r = js(""" (async () => { const response = await fetch("/api/file/<FILE_KEY>/comments"); - Network accessline 20
(async () => { const response = await fetch("/api/file/<FILE_KEY>/comments"); if (!response.ok) throw new Error("Comments request failed: " + response.status); - Network accessline 21
const response = await fetch("/api/file/<FILE_KEY>/comments");
agent-workspace/domain-skills/finviz/scraping.md
- Network accessline 9
- **Stock page** `https://finviz.com/stock?t=<T>` is server-rendered: 6 `table.js-snapshot-table` tables hold 84 label/value cells (valuation, growth, ownership, margins, technicals, performance), plus a header with company, sector, industr - Network accessline 80
if not re.fullmatch(r"[A-Z0-9.\-]{1,10}", t): raise ValueError(f"bad ticker {ticker!r}") url = "https://finviz.com/stock?" + urllib.parse.urlencode({"t": t}) - Network accessline 81
raise ValueError(f"bad ticker {ticker!r}") url = "https://finviz.com/stock?" + urllib.parse.urlencode({"t": t}) landed = urllib.parse.urlparse(fv_open(url)) - Network accessline 82
url = "https://finviz.com/stock?" + urllib.parse.urlencode({"t": t}) - Network accessline 214
raise ValueError(f"{signal}: not a robots.txt-allowed preset") v = ALLOWED_PRESETS[signal] url = f"https://finviz.com/screener/stocks?v={v}&s={signal}" + (f"&r={row}" if row > 1 else "") - Network accessline 215
v = ALLOWED_PRESETS[signal] url = f"https://finviz.com/screener/stocks?v={v}&s={signal}" + (f"&r={row}" if row > 1 else "") landed = fv_open(url) - Network accessline 216
url = f"https://finviz.com/screener/stocks?v={v}&s={signal}" + (f"&r={row}" if row > 1 else "")
agent-workspace/domain-skills/flighthub/flights-search.md
- Network accessline 30
https://www.flighthub.com/flight/search?seg0_from={ORIGIN}&seg0_to={DEST}&seg1_to={ORIGIN}&seg1_from={DEST}&seg0_date={YYYY-MM-DD}&seg1_date={YYYY-MM-DD}&order_by=cheapest¤cy=cad&num_adults=1&num_children=0&num_infants=0&num_infants_l - Network accessline 53
https://www.flighthub.com/flight/search?seg0_from=YYZ&seg0_to=ICN&seg1_to=YYZ&seg1_from=ICN&seg0_date=2027-07-03&seg1_date=2027-07-25&order_by=cheapest¤cy=cad&num_adults=1&num_children=0&num_infants=0&num_infants_lap=0&type=roundtrip& - Network accessline 60
When navigating to `https://www.flighthub.com/` directly, the page has an
agent-workspace/domain-skills/flipkart/shopping.md
- Network accessline 22
https://www.flipkart.com/search?q={query}&marketplace=FLIPKART&p%5B%5D=facets.price_range.from%3DMin&p%5B%5D=facets.price_range.to%3D{max_price} - Network accessline 28
goto_url("https://www.flipkart.com/search?" - Network accessline 38
goto_url("https://www.flipkart.com/search?" - Network accessline 236
price: card.querySelector('div._30jeq3')?.innerText?.trim(), rating: card.querySelector('div._3LWZlK')?.innerText?.trim(), url: 'https://www.flipkart.com' + href, - Network accessline 237
rating: card.querySelector('div._3LWZlK')?.innerText?.trim(), url: 'https://www.flipkart.com' + href, }; - Network accessline 238
url: 'https://www.flipkart.com' + href, - Network accessline 278
9. **Category browse pages** — Use `sid` parameter for category navigation: `https://www.flipkart.com/toys/pr?sid=tng` for toys. Combine with price - Network accessline 279
`https://www.flipkart.com/toys/pr?sid=tng` for toys. Combine with price
agent-workspace/domain-skills/framer/editor.md
- Network accessline 10
URL shape: `https://framer.com/projects/<project-slug>-<id>` (teamId query param after login). The left rail is tab-driven; the right rail is context-sensitive. - Network accessline 80
- **Drag-drop** — component insertion, layer reordering, cross-hierarchy moves. - **Smart Component variant switching** — the On Tap → Change Variant setup lives in a modal nested panel; no stable selector path. - **Property binding** (the - Network accessline 81
- **Smart Component variant switching** — the On Tap → Change Variant setup lives in a modal nested panel; no stable selector path. - **Property binding** (the chain icon on a code-component prop) — exposes only `Fetch (HTTP)` and `Create V - Network accessline 82
- **Property binding** (the chain icon on a code-component prop) — exposes only `Fetch (HTTP)` and `Create Variable`; no CMS-field binding available from the UI, let alone scriptable.
agent-workspace/domain-skills/fred/scraping.md
- Network accessline 3
`https://fred.stlouisfed.org` / `https://api.stlouisfed.org` — the canonical source for US macroeconomic time series (800,000+ series). The REST API at `api.stlouisfed.org` requires a free registered key. The web endpoints at `fred.stlouisf - Network accessline 17
# ALL OF THESE TIMEOUT — confirmed dead from headless HTTP: # https://fred.stlouisfed.org/graph/fredgraph.csv?id=GDP ← timeout - Network accessline 18
# https://fred.stlouisfed.org/graph/fredgraph.csv?id=GDP ← timeout - Network accessline 19
# https://fred.stlouisfed.org/graph/fredgraph.json?id=GDP ← timeout - Network accessline 20
# https://fred.stlouisfed.org/data/GDP.txt ← timeout - Network accessline 21
# https://fred.stlouisfed.org/series/GDP ← timeout - Network accessline 26
[Credential-related source omitted] - Access to secretsline 26
[Credential-related source omitted] - Network accessline 40
import json, os FRED_KEY = os.environ["FRED_KEY"] # 32-char lowercase alphanumeric BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 41
[Credential-related source omitted] - Network accessline 42
BASE = "https://api.stlouisfed.org/fred" - Network accessline 48
import json, os FRED_KEY = os.environ["FRED_KEY"] BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 49
[Credential-related source omitted] - Network accessline 50
BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 52
[Credential-related source omitted] - Network accessline 69
import json, os FRED_KEY = os.environ["FRED_KEY"] BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 70
[Credential-related source omitted] - Network accessline 71
BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 77
[Credential-related source omitted] - Network accessline 98
import json, os FRED_KEY = os.environ["FRED_KEY"] BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 99
[Credential-related source omitted] - Network accessline 100
BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 105
[Credential-related source omitted] - Network accessline 144
import json, os FRED_KEY = os.environ["FRED_KEY"] BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 145
[Credential-related source omitted] - Network accessline 146
BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 151
[Credential-related source omitted] - Network accessline 167
from concurrent.futures import ThreadPoolExecutor FRED_KEY = os.environ["FRED_KEY"] BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 168
[Credential-related source omitted] - Network accessline 169
BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 174
[Credential-related source omitted] - Network accessline 197
import json, os FRED_KEY = os.environ["FRED_KEY"] BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 198
[Credential-related source omitted] - Network accessline 199
BASE = "https://api.stlouisfed.org/fred" - Access to secretsline 202
[Credential-related source omitted] - Network accessline 221
[Credential-related source omitted] - Network accessline 222
[Credential-related source omitted] - Access to secretsline 222
[Credential-related source omitted] - Network accessline 235
Bureau of Labor Statistics. Covers unemployment, CPI, payrolls — the most-queried FRED series. **Without a key: 10 requests/day limit.** Free key registration at `https://www.bls.gov/developers/` gives 500 req/day and 10 years of data per c - Network accessline 238
import json # Single series GET — no auth needed r = http_get("https://api.bls.gov/publicAPI/v2/timeseries/data/LNS14000000?startyear=2024&endyear=2024") - Network accessline 239
# Single series GET — no auth needed r = http_get("https://api.bls.gov/publicAPI/v2/timeseries/data/LNS14000000?startyear=2024&endyear=2024") data = json.loads(r) - Network accessline 240
r = http_get("https://api.bls.gov/publicAPI/v2/timeseries/data/LNS14000000?startyear=2024&endyear=2024") - Network accessline 263
req = urllib.request.Request( - Network accessline 264
"https://api.bls.gov/publicAPI/v2/timeseries/data/", - Network accessline 266
headers={"Content-Type": "application/json"} ) with urllib.request.urlopen(req, timeout=20) as resp: - Network accessline 267
) with urllib.request.urlopen(req, timeout=20) as resp: data = json.loads(resp.read().decode()) - Network accessline 268
with urllib.request.urlopen(req, timeout=20) as resp: - Network accessline 309
# Single country, single indicator r = http_get("https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD?format=json&per_page=5&mrv=5") - Network accessline 310
r = http_get("https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD?format=json&per_page=5&mrv=5") - Network accessline 328
# Historical range: date=YYYY:YYYY r = http_get("https://api.worldbank.org/v2/country/US/indicator/FP.CPI.TOTL.ZG?format=json&date=2015:2024&per_page=15") - Network accessline 329
r = http_get("https://api.worldbank.org/v2/country/US/indicator/FP.CPI.TOTL.ZG?format=json&date=2015:2024&per_page=15") - Network accessline 339
# Multi-country: semicolon-separated ISO codes r = http_get("https://api.worldbank.org/v2/country/US;CN;DE;JP;GB/indicator/NY.GDP.MKTP.CD?format=json&date=2023&per_page=10") - Network accessline 340
r = http_get("https://api.worldbank.org/v2/country/US;CN;DE;JP;GB/indicator/NY.GDP.MKTP.CD?format=json&date=2023&per_page=10") - Network accessline 366
Some economic indicators work with the `demo` key (no registration); most require a free registered key (25 requests/day, instant signup at `https://www.alphavantage.co/support/#api-key`). - Network accessline 372
[Credential-related source omitted] - Network accessline 373
[Credential-related source omitted] - Network accessline 405
[Credential-related source omitted] - Network accessline 406
[Credential-related source omitted] - Network accessline 414
[Credential-related source omitted] - Network accessline 415
[Credential-related source omitted] - Network accessline 427
# Navigate to a series page goto_url("https://fred.stlouisfed.org/series/GDP") - Network accessline 428
goto_url("https://fred.stlouisfed.org/series/GDP")
agent-workspace/domain-skills/frontier/checkout.md
- Network accessline 9
1. `https://www.flyfrontier.com/` — search widget (not a `<form>`; submit happens via `#btnSearch`). - Network accessline 10
2. `https://booking.flyfrontier.com/Flight/Select` — fare grid + sticky "CONTINUE" summary footer. - Network accessline 11
3. `https://booking.flyfrontier.com/Passengers/Edit` — passenger details + contact. - Network accessline 12
4. `https://booking.flyfrontier.com/Bundles/Index` — upsell grid + "BUNDLE AND SAVE" confirmation modal. - Network accessline 13
5. `https://booking.flyfrontier.com/SeatMap/Index` — seat map + "SELECT YOUR SEAT NOW" upsell. - Network accessline 14
6. `https://booking.flyfrontier.com/Bags/Index` — carry-on / checked bag radios + carry-on upsell modal. - Network accessline 15
7. `https://booking.flyfrontier.com/Extras/Add` — disruption assistance (Hopper iframe) + agent-assist radios. - Network accessline 16
8. `https://booking.flyfrontier.com/Payment/New` — credit card + billing form.
agent-workspace/domain-skills/furnishedfinder/search.md
- Network accessline 3
Next.js App Router site. Listing search results are **server-rendered into the RSC payload** (`self.__next_f.push(...)` script tags). There is no XHR to intercept on first load, and the GraphQL endpoint (`https://cfw-edge-auth.furnishedfind - Network accessline 4
(`self.__next_f.push(...)` script tags). There is no XHR to intercept on first load, and the GraphQL endpoint (`https://cfw-edge-auth.furnishedfinder.com/graphql`) rejects a plain in-page `fetch()` (CORS/auth). Read the payload instead. - Network accessline 5
GraphQL endpoint (`https://cfw-edge-auth.furnishedfinder.com/graphql`) rejects a plain - Network accessline 6
in-page `fetch()` (CORS/auth). Read the payload instead. - Network accessline 10
- City page: `https://www.furnishedfinder.com/housing/us--ca--san-francisco` (region id
agent-workspace/domain-skills/g2/scraping.md
- Network accessline 9
Tested URLs (all 403): - `https://www.g2.com/products/slack/reviews` - Network accessline 10
- `https://www.g2.com/products/slack/reviews` - Network accessline 11
- `https://www.g2.com/categories/team-collaboration` - Network accessline 12
- `https://www.g2.com/products/slack` - Network accessline 13
- `https://www.g2.com/products/slack/reviews.json` - Network accessline 14
- `https://www.g2.com/blog/` (and most `www.g2.com/*`) - Network accessline 32
[Credential-related source omitted] - Access to secretsline 37
[Credential-related source omitted] - Network accessline 39
def g2_api_get(path, params=""): url = f"https://data.g2.com/api/v1/{path}?{params}" req = urllib.request.Request(url, headers={ - Network accessline 40
[Credential-related source omitted] - Network accessline 41
req = urllib.request.Request(url, headers={ - Access to secretsline 42
[Credential-related source omitted] - Network accessline 44
"Accept": "application/json", }) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 45
}) with urllib.request.urlopen(req, timeout=20) as r: return json.loads(r.read()) - Network accessline 46
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 56
# avg_rating: string e.g. "4.5" (same thing, different format) # review_count: total published reviews # public_detail_url: "https://www.g2.com/products/slack/reviews" - Network accessline 58
# public_detail_url: "https://www.g2.com/products/slack/reviews" - Network accessline 145
new_tab("https://www.g2.com/products/slack/reviews") - Network accessline 189
goto_url("https://www.g2.com/products/slack/reviews") - Network accessline 232
goto_url("https://www.g2.com/products/slack/reviews") - Network accessline 293
goto_url("https://www.g2.com/products/slack/reviews") - Network accessline 406
for page_num in range(1, 6): # up to 5 pages (~10 reviews each) url = f"https://www.g2.com/products/{slug}/reviews?page={page_num}" - Network accessline 407
url = f"https://www.g2.com/products/{slug}/reviews?page={page_num}" - Network accessline 456
goto_url("https://www.g2.com/categories/team-collaboration") - Network accessline 506
# Usage new_tab("https://www.g2.com/products/slack/reviews") - Network accessline 507
new_tab("https://www.g2.com/products/slack/reviews") - Access to secretsline 558
[Credential-related source omitted] - Network accessline 576
[Credential-related source omitted]
agent-workspace/domain-skills/gemini/spark-skills.md
- Network accessline 5
- Open `https://gemini.google.com/spark/skills`. Locate the card whose title text exactly equals the intended skill name. Read the title separately from the description. A prefix match can select both `Foo` and `Foo Bar`. Stop if the title
agent-workspace/domain-skills/genius/scraping.md
- Network accessline 63
def genius_song(song_id): """Fetch full song metadata by Genius song ID.""" data = json.loads(genius_get(f"https://genius.com/api/songs/{song_id}")) - Network accessline 64
"""Fetch full song metadata by Genius song ID.""" data = json.loads(genius_get(f"https://genius.com/api/songs/{song_id}")) return data["response"]["song"] - Network accessline 65
data = json.loads(genius_get(f"https://genius.com/api/songs/{song_id}")) - Network accessline 73
# song["primary_artist"]["name"] → "Queen" # song["primary_artist"]["id"] → 563 # song["primary_artist"]["url"] → "https://genius.com/artists/Queen" - Network accessline 74
# song["primary_artist"]["id"] → 563 # song["primary_artist"]["url"] → "https://genius.com/artists/Queen" # song["release_date"] → "1975-10-31" - Network accessline 75
# song["primary_artist"]["url"] → "https://genius.com/artists/Queen" - Network accessline 85
# song["album"]["name"] → "Studio Collection" (varies by region) # song["albums"][0]["name"] → "A Night at the Opera" (first = original) # song["url"] → "https://genius.com/Queen-bohe - Network accessline 86
# song["albums"][0]["name"] → "A Night at the Opera" (first = original) # song["url"] → "https://genius.com/Queen-bohemian-rhapsody-lyrics" # song["path"] → "/Queen-bohemian-rh - Network accessline 87
# song["url"] → "https://genius.com/Queen-bohemian-rhapsody-lyrics" - Network accessline 88
# song["path"] → "/Queen-bohemian-rhapsody-lyrics" # song["song_art_image_url"] → "https://images.genius.com/718de9d..." # song["explicit"] → False - Network accessline 89
# song["song_art_image_url"] → "https://images.genius.com/718de9d..." - Network accessline 93
# song["lyrics_verified"] → False # song["spotify_uuid"] → "7tFiyTwD0nx5a1eklYtX2J" # song["youtube_url"] → "https://www.youtube.com/watch?v=fJ9rUzIMcZQ" - Network accessline 94
# song["spotify_uuid"] → "7tFiyTwD0nx5a1eklYtX2J" # song["youtube_url"] → "https://www.youtube.com/watch?v=fJ9rUzIMcZQ" # song["writer_artists"] → [{"name": "Freddie Mercury", ...}] - Network accessline 95
# song["youtube_url"] → "https://www.youtube.com/watch?v=fJ9rUzIMcZQ" - Network accessline 107
def genius_search(query, per_page=5): """Search Genius. Returns sections: top_hit, song, lyric, artist, album, video, article, user.""" url = f"https://genius.com/api/search/multi?per_page={per_page}&q={urllib.parse.quote(query)}" - Network accessline 108
"""Search Genius. Returns sections: top_hit, song, lyric, artist, album, video, article, user.""" url = f"https://genius.com/api/search/multi?per_page={per_page}&q={urllib.parse.quote(query)}" data = json.loads(genius_get(url)) - Network accessline 109
url = f"https://genius.com/api/search/multi?per_page={per_page}&q={urllib.parse.quote(query)}" - Network accessline 122
r = hit["result"] print(r["full_title"], r["url"], r["id"]) # Bohemian Rhapsody by Queen https://genius.com/Queen-bohemian-rhapsody-lyrics 1063 - Network accessline 123
print(r["full_title"], r["url"], r["id"]) # Bohemian Rhapsody by Queen https://genius.com/Queen-bohemian-rhapsody-lyrics 1063 break - Network accessline 124
# Bohemian Rhapsody by Queen https://genius.com/Queen-bohemian-rhapsody-lyrics 1063 - Network accessline 141
page = 1 while True: url = (f"https://genius.com/api/artists/{artist_id}/songs" - Network accessline 142
while True: url = (f"https://genius.com/api/artists/{artist_id}/songs" f"?per_page={per_page}&page={page}&sort={sort}") - Network accessline 143
url = (f"https://genius.com/api/artists/{artist_id}/songs" - Network accessline 262
url: the canonical lyrics URL, e.g. 'https://genius.com/Queen-bohemian-rhapsody-lyrics' - Network accessline 275
lyrics = genius_lyrics("https://genius.com/Queen-bohemian-rhapsody-lyrics") - Network accessline 333
# Call 1: search for song sections = json.loads( genius_get(f"https://genius.com/api/search/multi?per_page=3&q={urllib.parse.quote(query)}") - Network accessline 334
sections = json.loads( genius_get(f"https://genius.com/api/search/multi?per_page=3&q={urllib.parse.quote(query)}") )["response"]["sections"] - Network accessline 335
genius_get(f"https://genius.com/api/search/multi?per_page=3&q={urllib.parse.quote(query)}") - Network accessline 348
# Call 2: full metadata from internal API meta = json.loads(genius_get(f"https://genius.com/api/songs/{song_id}"))["response"]["song"] - Network accessline 349
meta = json.loads(genius_get(f"https://genius.com/api/songs/{song_id}"))["response"]["song"] - Network accessline 383
# "producers": ["Roy Thomas Baker", "Queen"], # "spotify_uuid": "7tFiyTwD0nx5a1eklYtX2J", # "youtube_url": "https://www.youtube.com/watch?v=fJ9rUzIMcZQ", - Network accessline 384
# "spotify_uuid": "7tFiyTwD0nx5a1eklYtX2J", # "youtube_url": "https://www.youtube.com/watch?v=fJ9rUzIMcZQ", # "song_art_url": "https://images.genius.com/718de9d1fbcaae9f3c9b1bf483bfa8f1.1000x1000x1.png", - Network accessline 385
# "youtube_url": "https://www.youtube.com/watch?v=fJ9rUzIMcZQ", - Network accessline 386
# "song_art_url": "https://images.genius.com/718de9d1fbcaae9f3c9b1bf483bfa8f1.1000x1000x1.png", - Network accessline 387
# "lyrics_url": "https://genius.com/Queen-bohemian-rhapsody-lyrics", - Network accessline 416
# Or from search API (no HTML required): sections = json.loads(genius_get(f"https://genius.com/api/search/multi?per_page=1&q={query}")) - Network accessline 417
sections = json.loads(genius_get(f"https://genius.com/api/search/multi?per_page=1&q={query}")) - Network accessline 452
import json from helpers import http_get url = f"https://api.genius.com{path}" - Network accessline 453
[Credential-related source omitted] - Network accessline 454
url = f"https://api.genius.com{path}" - Access to secretsline 460
[Credential-related source omitted]
agent-workspace/domain-skills/github/repo-actions.md
- Network accessline 3
`https://github.com/{owner}/{repo}` — user-triggered actions on the repo header (Star, Unstar, Watch, Unwatch) are HTML forms that POST back to GitHub with the session's CSRF token already rendered inline. **Submit the form — do not click t - Network accessline 65
- **For read-only star counts, don't touch the DOM — use the API.** `http_get("https://api.github.com/repos/{owner}/{repo}")` returns `stargazers_count` without any browser interaction. See `scraping.md`. Only use the form-submit pattern wh
agent-workspace/domain-skills/github/scraping.md
- Network accessline 3
`https://github.com` — public data, mix of REST API (fast, rate-limited) and browser (trending page only). - Network accessline 10
import json data = json.loads(http_get("https://api.github.com/repos/{owner}/{repo}")) - Network accessline 11
data = json.loads(http_get("https://api.github.com/repos/{owner}/{repo}")) - Network accessline 21
readme = http_get("https://raw.githubusercontent.com/owner/repo/main/README.md") - Network accessline 22
content = http_get("https://raw.githubusercontent.com/owner/repo/main/pyproject.toml") - Network accessline 32
import json data = json.loads(http_get("https://api.github.com/repos/browser-use/browser-use")) - Network accessline 33
data = json.loads(http_get("https://api.github.com/repos/browser-use/browser-use")) - Network accessline 41
import json user = json.loads(http_get("https://api.github.com/users/browser-use")) - Network accessline 42
user = json.loads(http_get("https://api.github.com/users/browser-use")) - Network accessline 44
# returns: 'Organization' 3046 39 'https://browser-use.com' - Network accessline 52
import json goto_url("https://github.com/trending") # or /trending/python?since=weekly - Network accessline 53
goto_url("https://github.com/trending") # or /trending/python?since=weekly - Network accessline 67
return { name: h2link ? h2link.innerText.trim().replace(/\\s+/g,' ') : null, url: h2link ? 'https://github.com' + h2link.getAttribute('href') : null, - Network accessline 68
name: h2link ? h2link.innerText.trim().replace(/\\s+/g,' ') : null, url: h2link ? 'https://github.com' + h2link.getAttribute('href') : null, stars_total: starLink ? starLink.innerText.trim() : null, - Network accessline 69
url: h2link ? 'https://github.com' + h2link.getAttribute('href') : null, - Network accessline 92
import json results = json.loads(http_get( "https://api.github.com/search/repositories?q=browser+automation+language:python&sort=stars&per_page=10" - Network accessline 93
results = json.loads(http_get( "https://api.github.com/search/repositories?q=browser+automation+language:python&sort=stars&per_page=10" )) - Network accessline 94
"https://api.github.com/search/repositories?q=browser+automation+language:python&sort=stars&per_page=10" - Network accessline 106
import json # Commits commits = json.loads(http_get("https://api.github.com/repos/owner/repo/commits?per_page=10")) - Network accessline 107
# Commits commits = json.loads(http_get("https://api.github.com/repos/owner/repo/commits?per_page=10")) # Fields: sha, commit.message, commit.author.date, author.login - Network accessline 108
commits = json.loads(http_get("https://api.github.com/repos/owner/repo/commits?per_page=10")) - Network accessline 111
# Releases releases = json.loads(http_get("https://api.github.com/repos/owner/repo/releases?per_page=5")) - Network accessline 112
releases = json.loads(http_get("https://api.github.com/repos/owner/repo/releases?per_page=5")) - Network accessline 115
# Issues issues = json.loads(http_get("https://api.github.com/repos/owner/repo/issues?state=open&per_page=10")) - Network accessline 116
issues = json.loads(http_get("https://api.github.com/repos/owner/repo/issues?state=open&per_page=10")) - Network accessline 119
# Contributors contribs = json.loads(http_get("https://api.github.com/repos/owner/repo/contributors?per_page=10")) - Network accessline 120
contribs = json.loads(http_get("https://api.github.com/repos/owner/repo/contributors?per_page=10")) - Network accessline 127
import json, base64 resp = json.loads(http_get("https://api.github.com/repos/owner/repo/contents/path/to/file.py")) - Network accessline 128
resp = json.loads(http_get("https://api.github.com/repos/owner/repo/contents/path/to/file.py")) - Possible obfuscationline 129
content = base64.b64decode(resp['content']).decode() - Network accessline 140
def fetch_repo(name): data = json.loads(http_get(f"https://api.github.com/repos/{name}")) - Network accessline 141
data = json.loads(http_get(f"https://api.github.com/repos/{name}")) - Network accessline 152
- **Rate limits are per IP, unauthenticated** — Core API: 60 req/hour. Search API: 10 req/min. These are separate pools. Check `/rate_limit` endpoint: `http_get("https://api.github.com/rate_limit")`. With a `GITHUB_TOKEN`, both limits incre - Network accessline 157
[Credential-related source omitted] - Access to secretsline 157
[Credential-related source omitted] - Network accessline 159
data = json.loads(http_get("https://api.github.com/repos/owner/repo", headers=headers)) - Network accessline 164
try: data = json.loads(http_get("https://api.github.com/repos/owner/repo")) - Network accessline 165
data = json.loads(http_get("https://api.github.com/repos/owner/repo"))
agent-workspace/domain-skills/glassdoor/scraping.md
- Access to secretsline 21
[Credential-related source omitted] - Network accessline 33
new_tab("https://www.glassdoor.com/Reviews/Google-Reviews-E9079.htm") - Network accessline 82
query = "software engineer" new_tab(f"https://www.glassdoor.com/Job/jobs.htm?sc.keyword={quote_plus(query)}") - Network accessline 83
new_tab(f"https://www.glassdoor.com/Job/jobs.htm?sc.keyword={quote_plus(query)}") - Network accessline 148
for page in range(1, 4): # pages 1-3, ~10 cards each url = f"https://www.glassdoor.com/Job/jobs.htm?sc.keyword={quote_plus(query)}&p={page}" - Network accessline 149
url = f"https://www.glassdoor.com/Job/jobs.htm?sc.keyword={quote_plus(query)}&p={page}" - Network accessline 204
goto_url(f"https://www.glassdoor.com/Overview/Working-at-{company_slug}-EI_IE{employer_id}.htm") - Network accessline 253
goto_url(f"https://www.glassdoor.com/Reviews/{company_slug}-Reviews-E{employer_id}.htm") - Network accessline 319
goto_url(f"https://www.glassdoor.com/Salaries/{role}-salary-SRCH_KO0,{n}.htm") - Network accessline 430
# Usage goto_url("https://www.glassdoor.com/Reviews/Google-Reviews-E9079.htm") - Network accessline 431
goto_url("https://www.glassdoor.com/Reviews/Google-Reviews-E9079.htm") - Network accessline 452
company_name = "OpenAI" goto_url(f"https://www.glassdoor.com/Search/results.htm?keyword={quote_plus(company_name)}&locT=N") - Network accessline 453
goto_url(f"https://www.glassdoor.com/Search/results.htm?keyword={quote_plus(company_name)}&locT=N")
agent-workspace/domain-skills/gmail/compose.md
- Network accessline 3
URL: `https://mail.google.com`
agent-workspace/domain-skills/goodreads/scraping.md
- Network accessline 22
URL pattern: `https://www.goodreads.com/book/show/{book_id}` or `/{book_id}.{Slug}` - Network accessline 30
def parse_book(book_id): html = http_get(f"https://www.goodreads.com/book/show/{book_id}") - Network accessline 31
html = http_get(f"https://www.goodreads.com/book/show/{book_id}") - Network accessline 108
def parse_book_fast(book_id): html = http_get(f"https://www.goodreads.com/book/show/{book_id}") - Network accessline 109
html = http_get(f"https://www.goodreads.com/book/show/{book_id}") - Network accessline 139
URL: `https://www.goodreads.com/search?q={query}&search_type=books&page={n}` - Network accessline 147
def search_books(query, page=1): from urllib.parse import quote_plus url = f"https://www.goodreads.com/search?q={quote_plus(query)}&search_type=books&page={page}" - Network accessline 148
from urllib.parse import quote_plus url = f"https://www.goodreads.com/search?q={quote_plus(query)}&search_type=books&page={page}" html = http_get(url) - Network accessline 149
url = f"https://www.goodreads.com/search?q={quote_plus(query)}&search_type=books&page={page}" - Network accessline 152
rows = re.findall( r'<tr itemscope itemtype="http://schema.org/Book">(.*?)</tr>', - Network accessline 153
r'<tr itemscope itemtype="http://schema.org/Book">(.*?)</tr>', - Network accessline 172
'ratings_count':cnt.group(1).replace(',', '') if cnt else None, 'cover_url': cover.group(1) if cover else None, 'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", - Network accessline 173
'cover_url': cover.group(1) if cover else None, 'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", }) - Network accessline 174
'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", - Network accessline 199
URL: `https://www.goodreads.com/author/show/{author_id}.{Slug}` - Network accessline 208
def parse_author(author_id_and_slug): # author_id_and_slug e.g. "58.Frank_Patrick_Herbert" html = http_get(f"https://www.goodreads.com/author/show/{author_id_and_slug}") - Network accessline 210
html = http_get(f"https://www.goodreads.com/author/show/{author_id_and_slug}") - Network accessline 224
# Top books listed on the page (10 rows, same microdata format as search) rows = re.findall( r'<tr itemscope itemtype="http://schema.org/Book">(.*?)</tr>', - Network accessline 225
rows = re.findall( r'<tr itemscope itemtype="http://schema.org/Book">(.*?)</tr>', html, re.DOTALL - Network accessline 226
r'<tr itemscope itemtype="http://schema.org/Book">(.*?)</tr>', - Network accessline 239
'avg_rating': float(avg.group(1)) if avg else None, 'ratings_count':cnt.group(1).replace(',', '') if cnt else None, 'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", - Network accessline 240
'ratings_count':cnt.group(1).replace(',', '') if cnt else None, 'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", }) - Network accessline 241
'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", - Network accessline 271
URL: `https://www.goodreads.com/list/show/{list_id}.{Slug}?page={n}` - Network accessline 279
def parse_list(list_id_and_slug, page=1): url = f"https://www.goodreads.com/list/show/{list_id_and_slug}?page={page}" - Network accessline 280
url = f"https://www.goodreads.com/list/show/{list_id_and_slug}?page={page}" - Network accessline 283
rows = re.findall( r'<tr itemscope itemtype="http://schema.org/Book">(.*?)</tr>', - Network accessline 284
r'<tr itemscope itemtype="http://schema.org/Book">(.*?)</tr>', - Network accessline 303
'avg_rating': float(avg.group(1)) if avg else None, 'ratings_count':cnt.group(1).replace(',', '') if cnt else None, 'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", - Network accessline 304
'ratings_count':cnt.group(1).replace(',', '') if cnt else None, 'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", }) - Network accessline 305
'url': f"https://www.goodreads.com/book/show/{bid.group(1)}", - Network accessline 337
def ol_search(query, limit=10): url = f"https://openlibrary.org/search.json?q={quote_plus(query)}&limit={limit}" - Network accessline 338
url = f"https://openlibrary.org/search.json?q={quote_plus(query)}&limit={limit}" - Network accessline 349
'edition_count': doc.get('edition_count'), 'series': doc.get('series_name'), 'cover_url': f"https://covers.openlibrary.org/b/id/{cover_id}-M.jpg" if cover_id else None, - Network accessline 350
'series': doc.get('series_name'), 'cover_url': f"https://covers.openlibrary.org/b/id/{cover_id}-M.jpg" if cover_id else None, }) - Network accessline 351
'cover_url': f"https://covers.openlibrary.org/b/id/{cover_id}-M.jpg" if cover_id else None, - Network accessline 364
# ol_key like "/works/OL893415W" or just "OL893415W" key = ol_key if ol_key.startswith('/') else f'/works/{ol_key}' data = json.loads(http_get(f"https://openlibrary.org{key}.json")) - Network accessline 365
key = ol_key if ol_key.startswith('/') else f'/works/{ol_key}' data = json.loads(http_get(f"https://openlibrary.org{key}.json")) desc = data.get('description', '') - Network accessline 366
data = json.loads(http_get(f"https://openlibrary.org{key}.json")) - Network accessline 387
def ol_ratings(ol_key): key = ol_key if ol_key.startswith('/') else f'/works/{ol_key}' data = json.loads(http_get(f"https://openlibrary.org{key}/ratings.json")) - Network accessline 388
key = ol_key if ol_key.startswith('/') else f'/works/{ol_key}' data = json.loads(http_get(f"https://openlibrary.org{key}/ratings.json")) return data.get('summary', {}) - Network accessline 389
data = json.loads(http_get(f"https://openlibrary.org{key}/ratings.json")) - Network accessline 398
def ol_author(author_key): # author_key like "OL79034A" data = json.loads(http_get(f"https://openlibrary.org/authors/{author_key}.json")) - Network accessline 399
# author_key like "OL79034A" data = json.loads(http_get(f"https://openlibrary.org/authors/{author_key}.json")) bio = data.get('bio', '') - Network accessline 400
data = json.loads(http_get(f"https://openlibrary.org/authors/{author_key}.json")) - Network accessline 451
- **Search has no `__NEXT_DATA__`**: Search result pages (`/search`) are classic server-rendered HTML. JSON-LD is absent. Use the `<tr itemscope itemtype="http://schema.org/Book">` microdata rows. - Network accessline 455
- **Open Library cover URLs return binary JPEG**: `http_get()` will raise a `UnicodeDecodeError` on cover image URLs. Use `urllib.request.urlopen()` directly and read bytes, or just store the URL string without fetching.
agent-workspace/domain-skills/google-maps/scraping.md
- Network accessline 10
- Observed: "coffee shops in Austin TX" -> 9 requests (offsets 0-160, 2 s apart) -> 175 result rows in the run that counted them -> **150 to 175 unique places** across nine runs (175 in the run shown below: 145 with a phone, 167 with a webs - Network accessline 11
- **Browser fallback: scroll the results feed** (`div[role=feed]`) and read the cards. Card-level fields only (name, rating, reviews, category, short address, open status, place_id, lat/lng). The feed only lazy-loads in a visible tab, so br - Network accessline 12
- **Phone, website, hours for one place in the browser:** open `https://www.google.com/maps/place/?q=place_id:<id>` and read `[data-item-id]` elements. - Network accessline 31
for i in range(tries): # retry transient errors with backoff, then raise try: with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=30) as r: - Network accessline 32
try: with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=30) as r: data = r.read() - Network accessline 33
with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS), timeout=30) as r: - Network accessline 78
"place_id": pid, "cid": cid, "maps_url": f"https://www.google.com/maps/place/?q=place_id:{pid}" if pid else None, - Network accessline 79
"cid": cid, "maps_url": f"https://www.google.com/maps/place/?q=place_id:{pid}" if pid else None, "open_now": (at(p, 203, 1, 4, 0) or "").replace(" ", " ") or None, - Network accessline 80
"maps_url": f"https://www.google.com/maps/place/?q=place_id:{pid}" if pid else None, - Network accessline 85
def search_places(query, max_results=200, pause=2.0): q = urllib.parse.quote_plus(query) page = get(f"https://www.google.com/maps/search/{q}?hl=en&gl=us") - Network accessline 86
q = urllib.parse.quote_plus(query) page = get(f"https://www.google.com/maps/search/{q}?hl=en&gl=us") m = re.search(r'<link href="(/search\?tbm=map[^"]+)"', page) - Network accessline 87
page = get(f"https://www.google.com/maps/search/{q}?hl=en&gl=us") - Network accessline 89
if not m: raise RuntimeError("no /search?tbm=map preload link (consent page or layout change?)") base = "https://www.google.com" + html.unescape(m.group(1)) - Network accessline 90
[Credential-related source omitted] - Network accessline 91
base = "https://www.google.com" + html.unescape(m.group(1)) - Network accessline 143
"phone": "(512) 852-2300", "phone_e164": "+15128522300", "website": "https://www.joscoffee.com/south-congress-jos", - Network accessline 144
"phone_e164": "+15128522300", "website": "https://www.joscoffee.com/south-congress-jos", "lat": 30.2510458, - Network accessline 145
"website": "https://www.joscoffee.com/south-congress-jos", - Network accessline 148
"place_id": "ChIJ1S_Bov20RIYRe7MiR8tYawY", "cid": "462561016830669691", "maps_url": "https://www.google.com/maps/place/?q=place_id:ChIJ1S_Bov20RIYRe7MiR8tYawY", - Network accessline 149
"cid": "462561016830669691", "maps_url": "https://www.google.com/maps/place/?q=place_id:ChIJ1S_Bov20RIYRe7MiR8tYawY", "open_now": "Open · Closes 7 PM", - Network accessline 150
"maps_url": "https://www.google.com/maps/place/?q=place_id:ChIJ1S_Bov20RIYRe7MiR8tYawY", - Network accessline 185
if FOREGROUND: activate_tab(tid) # make it visible BEFORE loading the search goto_url("https://www.google.com/maps/search/" + urllib.parse.quote_plus(query) + "?hl=en") - Network accessline 186
activate_tab(tid) # make it visible BEFORE loading the search goto_url("https://www.google.com/maps/search/" + urllib.parse.quote_plus(query) + "?hl=en") wait_for_load() - Network accessline 187
goto_url("https://www.google.com/maps/search/" + urllib.parse.quote_plus(query) + "?hl=en") - Network accessline 269
"lat": 30.2510458, "lng": -97.7493717, "maps_url": "https://www.google.com/maps/place/Jo%27s+Coffee+%E2%80%93+South+Congress/data=!4m7!3m6!1s0x8644b4fda2c12fd5:0x66b58cb4722b37b!8m2!3d30.2510458!4d-97.7493717!16s%2Fm%2F020z01l!19sChIJ1S - Network accessline 270
"lng": -97.7493717, "maps_url": "https://www.google.com/maps/place/Jo%27s+Coffee+%E2%80%93+South+Congress/data=!4m7!3m6!1s0x8644b4fda2c12fd5:0x66b58cb4722b37b!8m2!3d30.2510458!4d-97.7493717!16s%2Fm%2F020z01l!19sChIJ1S_Bov20RIYRe7MiR8tYawY - Network accessline 271
"maps_url": "https://www.google.com/maps/place/Jo%27s+Coffee+%E2%80%93+South+Congress/data=!4m7!3m6!1s0x8644b4fda2c12fd5:0x66b58cb4722b37b!8m2!3d30.2510458!4d-97.7493717!16s%2Fm%2F020z01l!19sChIJ1S_Bov20RIYRe7MiR8tYawY" - Network accessline 284
def place_details(place_id): goto_url(f"https://www.google.com/maps/place/?q=place_id:{place_id}&hl=en") - Network accessline 285
goto_url(f"https://www.google.com/maps/place/?q=place_id:{place_id}&hl=en") - Network accessline 314
"address": "1300 S Congress Ave, Austin, TX 78704", "phone": "(512) 852-2300", "website": "https://www.joscoffee.com/south-congress-jos", - Network accessline 315
"phone": "(512) 852-2300", "website": "https://www.joscoffee.com/south-congress-jos", "hours": ["Friday, 7 AM to 7 PM", "Saturday, 7 AM to 7 PM", ...] - Network accessline 316
"website": "https://www.joscoffee.com/south-congress-jos", - Network accessline 321
"address": "3908 Avenue B, Austin, TX 78751", "phone": null, "website": "http://terriblelovecoffee.com/", - Network accessline 322
"phone": null, "website": "http://terriblelovecoffee.com/", "hours": ["Friday, 7:30 AM to 2 PM", ...] - Network accessline 323
"website": "http://terriblelovecoffee.com/", - Network accessline 339
| neighborhood | `p[14]` | - | `Bouldin Creek` | | phone | `p[178][0][0]`, E.164 at `p[178][0][3]` | `[data-item-id^="phone:tel:"]` aria | `(512) 852-2300` | | website | `p[7][0]` (a `/url?q=<site>` redirect for non-browser UAs), domain at - Network accessline 340
| phone | `p[178][0][0]`, E.164 at `p[178][0][3]` | `[data-item-id^="phone:tel:"]` aria | `(512) 852-2300` | | website | `p[7][0]` (a `/url?q=<site>` redirect for non-browser UAs), domain at `p[7][1]` | `a[data-item-id=authority]` href | `h - Network accessline 341
| website | `p[7][0]` (a `/url?q=<site>` redirect for non-browser UAs), domain at `p[7][1]` | `a[data-item-id=authority]` href | `https://www.joscoffee.com/...` | - Network accessline 349
`https://www.google.com/maps/place/?q=place_id:<place_id>` opened the matching place page in the browser (checked for two places).
agent-workspace/domain-skills/google-patents/scraping.md
- Network accessline 9
- A patent page (`/patent/<publication number>/en`) is server-rendered HTML with schema.org microdata (`itemprop` attributes). Title, bibliographic data, every claim, every citation table and the family tables are all in that one document. - Network accessline 10
- The browser block opens one patent page so the tab is on `patents.google.com`, then for each number calls `fetch('/patent/<number>/en')` inside the tab and parses the response with `DOMParser`. It does not read the rendered page: the Poly - Network accessline 29
const url = `/patent/${encodeURIComponent(num)}/${lang}`; let r; try { r = await fetch(url); } - Network accessline 30
let r; try { r = await fetch(url); } catch (e) { return {error: `fetch failed (${e}); a cross-origin redirect here usually means a google.com/sorry challenge`}; } - Network accessline 31
try { r = await fetch(url); } - Network accessline 98
def gp_open(num): """Point the tab at a patent page (any /patent/ page works as the origin for gp_patent).""" goto_url(f"https://patents.google.com/patent/{num}/en") - Network accessline 99
"""Point the tab at a patent page (any /patent/ page works as the origin for gp_patent).""" goto_url(f"https://patents.google.com/patent/{num}/en") wait_for_load() - Network accessline 100
goto_url(f"https://patents.google.com/patent/{num}/en") - Network accessline 102
time.sleep(2) href = js("location.href") if not href.startswith("https://patents.google.com/patent/"): - Network accessline 103
href = js("location.href") if not href.startswith("https://patents.google.com/patent/"): raise RuntimeError(f"tab landed on {href}, not a patent page (challenge or redirect). Stop and tell the user.") - Network accessline 104
if not href.startswith("https://patents.google.com/patent/"): - Network accessline 107
def gp_patent(num, lang="en"): """Full record for one publication number ('US6285999B1'), or None when Google Patents returns 404. Runs fetch() inside the attached patents.google.com tab and parses the server-rendered page.""" - Network accessline 108
"""Full record for one publication number ('US6285999B1'), or None when Google Patents returns 404. Runs fetch() inside the attached patents.google.com tab and parses the server-rendered page.""" rec = js(f"{PATENT_JS}({json.dumps(n - Network accessline 109
Runs fetch() inside the attached patents.google.com tab and parses the server-rendered page.""" - Network accessline 179
Self-contained, Python standard library only. `html.parser` builds a small tree and the same `itemprop` lookups run on it, so the keys and values match block 1 (block 1 also has `pdf`, `assignee_current`, `application_number`, `abstract`, ` - Network accessline 249
def fetch(url): - Network accessline 250
"""HTML for a /patent/ page, None on 404. Any other status, or a redirect off /patent/, raises: stop, do not retry around it.""" try: with urllib.request.urlopen(urllib.request.Request(url, headers=UA), timeout=60) as r: - Network accessline 251
try: with urllib.request.urlopen(urllib.request.Request(url, headers=UA), timeout=60) as r: final = r.geturl() - Network accessline 252
with urllib.request.urlopen(urllib.request.Request(url, headers=UA), timeout=60) as r: - Network accessline 262
def gp_patent_http(num, lang="en"): html, final = fetch(f"https://patents.google.com/patent/{urllib.parse.quote(num)}/{lang}") - Network accessline 263
html, final = fetch(f"https://patents.google.com/patent/{urllib.parse.quote(num)}/{lang}") - Network accessline 360
| `country_status` | rows `countryStatus` (`countryCode`, `num`, `representativePublication`) | `[{"countryCode": "US", "num": "10", ...}]` | | `priority_applications` | rows `priorityApps` | 12 rows | | `url` | final URL of the fetch | `ht - Network accessline 362
| `url` | final URL of the fetch | `https://patents.google.com/patent/US6285999B1/en` | - Access to secretsline 374
[Credential-related source omitted]
agent-workspace/domain-skills/google-play/scraping.md
- Network accessline 41
def fetch(url, tries=4): - Network accessline 44
Other HTTP errors (404 included) raise urllib.error.HTTPError immediately.""" for i in range(tries): req = urllib.request.Request(url, headers=H) - Network accessline 45
for i in range(tries): req = urllib.request.Request(url, headers=H) try: - Network accessline 46
req = urllib.request.Request(url, headers=H) - Network accessline 47
try: with urllib.request.urlopen(req, timeout=20) as r: return r.read().decode() - Network accessline 48
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 125
"""Full detail record for one package name, or None if Play returns HTTP 404 or the page has neither app data nor JSON-LD for this id.""" url = "https://play.google.com/store/apps/details?" + urllib.parse.urlencode({"id": app_id, "h - Network accessline 126
or the page has neither app data nor JSON-LD for this id.""" url = "https://play.google.com/store/apps/details?" + urllib.parse.urlencode({"id": app_id, "hl": HL, "gl": GL}) try: - Network accessline 127
url = "https://play.google.com/store/apps/details?" + urllib.parse.urlencode({"id": app_id, "hl": HL, "gl": GL}) - Network accessline 128
try: html = fetch(url) except urllib.error.HTTPError as e: - Network accessline 129
html = fetch(url) - Network accessline 197
{"app_id": "com.spotify.music", "title": "Spotify: Music and Podcasts", "developer": "Spotify AB", "developer_id": "6523013212965523194", "rating": 4.3489933, "ratings_count": 36528069, "installs": "1,000,000,000+", "min_installs": 10000000 - Network accessline 198
{"app_id": "com.mojang.minecraftpe", "title": "Minecraft: Dream it, Build it!", "developer": "Mojang", "developer_id": "4772240228547998649", "rating": 4.303256, "ratings_count": 5866778, "installs": "50,000,000+", "min_installs": 50000000, - Network accessline 199
{"app_id": "org.videolan.vlc", "title": "VLC for Android", "developer": "Videolabs", "developer_id": "6364851808230428105", "rating": 4.042392, "ratings_count": 2009187, "installs": "500,000,000+", "min_installs": 500000000, "installs_exact - Network accessline 227
def open_play(path, params, ready_expr, timeout=30): """Navigate, then wait until the loaded document is THIS url (same path, same id) and ready_expr is true.""" url = "https://play.google.com" + path + "?" + urllib.parse.urlencode( - Network accessline 228
"""Navigate, then wait until the loaded document is THIS url (same path, same id) and ready_expr is true.""" url = "https://play.google.com" + path + "?" + urllib.parse.urlencode(params) _retry(goto_url, url) - Network accessline 229
url = "https://play.google.com" + path + "?" + urllib.parse.urlencode(params) - Network accessline 313
def open_play(path, params, ready_expr, timeout=30): """Navigate, then wait until the loaded document is THIS url (same path, same id) and ready_expr is true.""" url = "https://play.google.com" + path + "?" + urllib.parse.urlencode( - Network accessline 314
"""Navigate, then wait until the loaded document is THIS url (same path, same id) and ready_expr is true.""" url = "https://play.google.com" + path + "?" + urllib.parse.urlencode(params) _retry(goto_url, url) - Network accessline 315
url = "https://play.google.com" + path + "?" + urllib.parse.urlencode(params) - Network accessline 443
| `contains_ads` | `a[48]` is `["Contains ads"]` for apps with ads (Spotify) and null for apps without (Minecraft, VLC); `null` if the app array is missing or `a[48]` has another shape | `true` | | `in_app_purchases` | `a[19][0]` | `$4.99 - - Network accessline 445
| `url` | the detail URL that was fetched | `https://play.google.com/store/apps/details?id=com.spotify.music&hl=en_US&gl=US` | - Network accessline 456
- **Two kinds of developer page.** App pages link either to `/store/apps/developer?id=<name>` (Spotify) or to `/store/apps/dev?id=<numeric id>` (Microsoft Teams, Angry Birds 2, YouTube). The numeric page is a showcase of 10-11 apps. The nam - Network accessline 457
- **Country and language come from `gl` and `hl`.** With `GL = "DE"` Minecraft came back as `6.99 EUR`, `€6.99`. Set them explicitly; without them Play picks from the request. - **Missing apps return HTTP 404** (`com.example.does.not.exist` - Network accessline 458
- **Missing apps return HTTP 404** (`com.example.does.not.exist`). `fetch()` raises `urllib.error.HTTPError` at once for a 404 (only 429 and 5xx are retried); `play_app()` turns the 404 into `None`, and also returns `None` for any page with - Access to secretsline 459
[Credential-related source omitted]
agent-workspace/domain-skills/google-sheets/writing-cells.md
- Network accessline 36
https://docs.google.com/spreadsheets/d/<id>/export?format=csv&gid=<gid>
agent-workspace/domain-skills/google-trends/scraping.md
- Network accessline 9
- **RSS, no browser:** `https://trends.google.com/trending/rss?geo=<CC>` returns exactly 10 items: the 10 most recently started trends for that country or region (`US`, `GB`, `JP`, `US-CA`...), each with approximate traffic (`2000+`), start - Network accessline 10
- **/trending page, everything:** `https://trends.google.com/trending?geo=<CC>&hl=en-US&hours=<4|24|48|168>` ships every trend for that window in one inline script, `AF_initDataCallback({key: 'ds:0', ...})` (658 trends for US / 24 h on 2026 - Network accessline 26
BASE = "https://trends.google.com" - Network accessline 27
HT = "{https://trends.google.com/trending/rss}" # namespace of the ht:* tags - Network accessline 30
# longest matching pattern wins, Allow wins a tie. def _robots_rules(): txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() - Network accessline 31
def _robots_rules(): txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() rules, in_star, prev_ua = [], False, False - Network accessline 32
txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() - Network accessline 63
raise PermissionError(f"robots.txt disallows {path}") try: body = urllib.request.urlopen(BASE + path, timeout=20).read() - Network accessline 64
try: body = urllib.request.urlopen(BASE + path, timeout=20).read() except urllib.error.HTTPError as e: - Network accessline 65
body = urllib.request.urlopen(BASE + path, timeout=20).read() - Network accessline 125
BASE = "https://trends.google.com" - Network accessline 128
# longest matching pattern wins, Allow wins a tie. def _robots_rules(): txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() - Network accessline 129
def _robots_rules(): txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() rules, in_star, prev_ua = [], False, False - Network accessline 130
txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() - Network accessline 294
BASE = "https://trends.google.com" - Network accessline 296
# robots.txt, group "User-agent: *", wildcard rules matched Google-style (same parser as blocks 1 and 2). def _robots_rules(): txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() - Network accessline 297
def _robots_rules(): txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() rules, in_star, prev_ua = [], False, False - Network accessline 298
txt = urllib.request.urlopen(BASE + "/robots.txt", timeout=20).read().decode() - Network accessline 330
if not robots_allowed(path): raise PermissionError(f"robots.txt disallows {path}") html = urllib.request.urlopen(BASE + path, timeout=30).read().decode() - Network accessline 331
raise PermissionError(f"robots.txt disallows {path}") html = urllib.request.urlopen(BASE + path, timeout=30).read().decode() m = re.search(r"AF_initDataCallback\(\{key: 'ds:0', hash: '\d+', data:(\[.*?\]), sideChannel: \{\}\}\);", h - Network accessline 332
html = urllib.request.urlopen(BASE + path, timeout=30).read().decode()
agent-workspace/domain-skills/google/flights-multi-city.md
- Network accessline 7
https://www.google.com/travel/flights?tfs=<base64 protobuf>&hl=en&curr=USD
agent-workspace/domain-skills/gutenberg/scraping.md
- Network accessline 3
`https://www.gutenberg.org` — 78 000+ free public-domain ebooks. Every workflow here is pure `http_get` — no browser needed. - Network accessline 12
# Search by title/author keyword data = json.loads(http_get("https://gutendex.com/books/?search=pride+and+prejudice")) - Network accessline 13
data = json.loads(http_get("https://gutendex.com/books/?search=pride+and+prejudice")) - Network accessline 28
book = json.loads(http_get("https://gutendex.com/books/1342/")) - Network accessline 38
data = json.loads(http_get("https://gutendex.com/books/?search=frankenstein")) - Network accessline 53
data = json.loads(http_get("https://gutendex.com/books/?sort=popular")) - Network accessline 74
# 'topic' matches both subjects and bookshelves fields data = json.loads(http_get("https://gutendex.com/books/?topic=science+fiction")) - Network accessline 75
data = json.loads(http_get("https://gutendex.com/books/?topic=science+fiction")) - Network accessline 78
data = json.loads(http_get("https://gutendex.com/books/?topic=detective+fiction")) - Network accessline 82
# Filter by language (ISO 639-1 code) data = json.loads(http_get("https://gutendex.com/books/?languages=fr&topic=roman")) - Network accessline 83
data = json.loads(http_get("https://gutendex.com/books/?languages=fr&topic=roman")) - Network accessline 92
url = "https://gutendex.com/books/?topic=science+fiction" - Network accessline 97
url = data['next'] # None on last page # data['previous'] is also populated after page 1 # e.g. data['next'] = "https://gutendex.com/books/?page=3&topic=science+fiction" - Network accessline 98
# data['previous'] is also populated after page 1 # e.g. data['next'] = "https://gutendex.com/books/?page=3&topic=science+fiction" # All 3473 sci-fi books loaded across ~109 pages of 32 each - Network accessline 99
# e.g. data['next'] = "https://gutendex.com/books/?page=3&topic=science+fiction" - Network accessline 108
data = json.loads(http_get("https://gutendex.com/books/?ids=1342,11,84")) - Network accessline 120
raw = http_get("https://www.gutenberg.org/cache/epub/1342/pg1342.txt") - Network accessline 135
# Both of these return identical content (763 083 chars): http_get("https://www.gutenberg.org/ebooks/1342.txt.utf-8") # redirect - Network accessline 136
http_get("https://www.gutenberg.org/ebooks/1342.txt.utf-8") # redirect - Network accessline 137
http_get("https://www.gutenberg.org/cache/epub/1342/pg1342.txt") # direct cache - Network accessline 157
b = json.loads(http_get("https://gutendex.com/books/1342/")) - Network accessline 159
for mime, url in b['formats'].items(): print(mime, '->', url) # text/html -> https://www.gutenberg.org/ebooks/1342.html.images - Network accessline 160
print(mime, '->', url) # text/html -> https://www.gutenberg.org/ebooks/1342.html.images # application/epub+zip -> https://www.gutenberg.org/ebooks/1342.epub3.images - Network accessline 161
# text/html -> https://www.gutenberg.org/ebooks/1342.html.images - Network accessline 162
# application/epub+zip -> https://www.gutenberg.org/ebooks/1342.epub3.images - Network accessline 163
# application/x-mobipocket-ebook -> https://www.gutenberg.org/ebooks/1342.kf8.images - Network accessline 164
# application/rdf+xml -> https://www.gutenberg.org/ebooks/1342.rdf - Network accessline 165
# image/jpeg -> https://www.gutenberg.org/cache/epub/1342/pg1342.cover.medium.jpg - Network accessline 166
# application/octet-stream -> https://www.gutenberg.org/cache/epub/1342/pg1342-h.zip - Network accessline 167
# text/plain; charset=utf-8 -> https://www.gutenberg.org/ebooks/1342.txt.utf-8 - Network accessline 175
rdf = http_get("https://www.gutenberg.org/cache/epub/1342/pg1342.rdf") - Network accessline 176
# Also available as: http_get("https://www.gutenberg.org/ebooks/1342.rdf") - Network accessline 206
html = http_get( "https://www.gutenberg.org/ebooks/search/" - Network accessline 207
"https://www.gutenberg.org/ebooks/search/" - Network accessline 229
# Paginate with start_index (25 per page) html_p2 = http_get( "https://www.gutenberg.org/ebooks/search/" - Network accessline 230
html_p2 = http_get( "https://www.gutenberg.org/ebooks/search/" "?query=shakespeare&sort_order=downloads&start_index=26" - Network accessline 231
"https://www.gutenberg.org/ebooks/search/" - Network accessline 241
# Bookshelf 68 = Science Fiction html = http_get("https://www.gutenberg.org/ebooks/bookshelf/68") - Network accessline 242
html = http_get("https://www.gutenberg.org/ebooks/bookshelf/68") - Network accessline 253
feed = http_get("https://www.gutenberg.org/ebooks/search.opds/?query=dracula") - Network accessline 267
Validated against a real call to `GET https://gutendex.com/books/1342/`: - Network accessline 298
"media_type": "Text", "formats": { "text/html": "https://www.gutenberg.org/ebooks/1342.html.images", - Network accessline 299
"formats": { "text/html": "https://www.gutenberg.org/ebooks/1342.html.images", "application/epub+zip": "https://www.gutenberg.org/ebooks/1342.epub3.images", - Network accessline 300
"text/html": "https://www.gutenberg.org/ebooks/1342.html.images", - Network accessline 301
"application/epub+zip": "https://www.gutenberg.org/ebooks/1342.epub3.images", - Network accessline 302
"application/x-mobipocket-ebook": "https://www.gutenberg.org/ebooks/1342.kf8.images", - Network accessline 303
"application/rdf+xml": "https://www.gutenberg.org/ebooks/1342.rdf", - Network accessline 304
"image/jpeg": "https://www.gutenberg.org/cache/epub/1342/pg1342.cover.medium.jpg", - Network accessline 305
"application/octet-stream": "https://www.gutenberg.org/cache/epub/1342/pg1342-h.zip", - Network accessline 306
"text/plain; charset=utf-8": "https://www.gutenberg.org/ebooks/1342.txt.utf-8" - Network accessline 347
1. **Gutendex search** — returns `id` directly in JSON. 2. **Gutenberg HTML catalog** — `book_id = re.search(r'/ebooks/(\d+)', entry)`. IDs in the URL. 3. **URL pattern** — `https://www.gutenberg.org/ebooks/{id}` — if you already know the I - Network accessline 349
3. **URL pattern** — `https://www.gutenberg.org/ebooks/{id}` — if you already know the ID from any source. - Network accessline 360
url = "https://gutendex.com/books/?sort=popular" - Network accessline 369
For gutenberg.org file downloads (txt, epub, etc.) there is no documented rate limit but Gutenberg asks not to use automated bulk downloading; use their [offline catalogs](https://www.gutenberg.org/ebooks/offline_catalogs.html) for bulk acc - Network accessline 373
- **`.opf` 404**: `https://www.gutenberg.org/cache/epub/1342/pg1342.opf` returns 404. Use `.rdf` instead — same path prefix, same data in RDF/XML. - **`formats` URLs redirect**: URLs like `https://www.gutenberg.org/ebooks/1342.txt.utf-8` ar - Network accessline 374
- **`formats` URLs redirect**: URLs like `https://www.gutenberg.org/ebooks/1342.txt.utf-8` are redirect endpoints that resolve to `/cache/epub/1342/pg1342.txt`. Either form works with `http_get` (urllib follows redirects automatically), but
agent-workspace/domain-skills/hackernews/scraping.md
- Network accessline 3
`https://news.ycombinator.com` — YCombinator's link aggregator. Three access paths tested: `http_get` DOM scraping, Algolia search API, and the official HN Firebase API. All work without a browser. - Network accessline 26
page = http_get("https://news.ycombinator.com") - Network accessline 91
# Keyword search — sorted by relevance data = json.loads(http_get( "https://hn.algolia.com/api/v1/search" - Network accessline 92
data = json.loads(http_get( "https://hn.algolia.com/api/v1/search" "?query=llm&tags=story&hitsPerPage=20" - Network accessline 93
"https://hn.algolia.com/api/v1/search" - Network accessline 97
# Date-sorted (most recent first) data = json.loads(http_get( "https://hn.algolia.com/api/v1/search_by_date" - Network accessline 98
data = json.loads(http_get( "https://hn.algolia.com/api/v1/search_by_date" "?tags=story&hitsPerPage=20" - Network accessline 99
"https://hn.algolia.com/api/v1/search_by_date" - Network accessline 161
thread = json.loads(http_get( "https://hn.algolia.com/api/v1/items/47806725" - Network accessline 162
"https://hn.algolia.com/api/v1/items/47806725" - Network accessline 188
# Ranked story ID lists (no metadata — just IDs) top = json.loads(http_get("https://hacker-news.firebaseio.com/v0/topstories.json")) # 500 IDs - Network accessline 189
top = json.loads(http_get("https://hacker-news.firebaseio.com/v0/topstories.json")) # 500 IDs - Network accessline 190
new = json.loads(http_get("https://hacker-news.firebaseio.com/v0/newstories.json")) # 500 IDs - Network accessline 191
best = json.loads(http_get("https://hacker-news.firebaseio.com/v0/beststories.json")) # 200 IDs - Network accessline 192
ask = json.loads(http_get("https://hacker-news.firebaseio.com/v0/askstories.json")) # ~32 IDs - Network accessline 193
show = json.loads(http_get("https://hacker-news.firebaseio.com/v0/showstories.json")) # ~119 IDs - Network accessline 194
jobs = json.loads(http_get("https://hacker-news.firebaseio.com/v0/jobstories.json")) # ~31 IDs - Network accessline 196
# Fetch a single item item = json.loads(http_get( "https://hacker-news.firebaseio.com/v0/item/47806725.json" - Network accessline 197
item = json.loads(http_get( "https://hacker-news.firebaseio.com/v0/item/47806725.json" )) - Network accessline 198
"https://hacker-news.firebaseio.com/v0/item/47806725.json" - Network accessline 203
# Fetch a user profile user = json.loads(http_get( "https://hacker-news.firebaseio.com/v0/user/pg.json" - Network accessline 204
user = json.loads(http_get( "https://hacker-news.firebaseio.com/v0/user/pg.json" )) - Network accessline 205
"https://hacker-news.firebaseio.com/v0/user/pg.json" - Network accessline 209
# Highest current item ID (useful for polling new items) maxid = json.loads(http_get("https://hacker-news.firebaseio.com/v0/maxitem.json")) - Network accessline 210
maxid = json.loads(http_get("https://hacker-news.firebaseio.com/v0/maxitem.json")) - Network accessline 227
page = http_get("https://news.ycombinator.com/item?id=47806725")
agent-workspace/domain-skills/home-depot/scraping.md
- Network accessline 9
- **No search.** `/s/<query>` and the `NCNI-5` category redirect a search lands on are disallowed. Find a category instead: the site's own sitemap `https://www.homedepot.com/sitemap/B/PLPs.xml` points to `PLP_CORE_TAX-0.xml` with 5356 categ - Network accessline 11
- **Category page** (`/b/<slug>/N-<id>`) carries the product grid as JSON, not just HTML: - server-rendered Apollo cache `window.__APOLLO_STATE__` (`SearchModel` -> `products(...)` -> `base-searchNav-<itemId>` entries), and - the page's - Network accessline 12
- server-rendered Apollo cache `window.__APOLLO_STATE__` (`SearchModel` -> `products(...)` -> `base-searchNav-<itemId>` entries), and - the page's own `POST https://apionline.homedepot.com/federation-gateway/graphql?opname=searchModel`. - Network accessline 13
- the page's own `POST https://apionline.homedepot.com/federation-gateway/graphql?opname=searchModel`. - Network accessline 28
KEYWORDS = ["lawn", "mowers"] # words that must all appear in the category URL path UA = "browser-harness-domain-skill/1.0 (+https://github.com/browser-use/browser-harness)" # truthful client UA - Network accessline 29
UA = "browser-harness-domain-skill/1.0 (+https://github.com/browser-use/browser-harness)" # truthful client UA - Network accessline 48
for attempt in range(1, tries + 1): try: req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 49
try: req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 50
req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 51
with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 91
rules = robots_rules(get("https://www.homedepot.com/robots.txt")) - Network accessline 92
if not rules: raise RuntimeError("robots.txt has no User-agent: * rules (layout change?); stop") index = get("https://www.homedepot.com/sitemap/B/PLPs.xml") - Network accessline 93
raise RuntimeError("robots.txt has no User-agent: * rules (layout change?); stop") index = get("https://www.homedepot.com/sitemap/B/PLPs.xml") core = [u for u in re.findall(r"<loc>([^<]+)</loc>", index) if "/PLP_CORE_TAX/" in u] - Network accessline 94
index = get("https://www.homedepot.com/sitemap/B/PLPs.xml") - Network accessline 117
1 core category sitemap(s), 5356 category URLs 15 match ['lawn', 'mowers']; 0 dropped as disallowed by robots.txt https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Lawn-Mowers/N-5yc1vZc5ar - Network accessline 118
15 match ['lawn', 'mowers']; 0 dropped as disallowed by robots.txt https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Lawn-Mowers/N-5yc1vZc5ar https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Riding-Lawn-Mowers/N-5yc1v - Network accessline 119
https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Lawn-Mowers/N-5yc1vZc5ar - Network accessline 120
https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Riding-Lawn-Mowers/N-5yc1vZc5ax - Network accessline 121
https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Lawn-Mowers-Push-Mowers/N-5yc1vZc5ah - Network accessline 122
https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Lawn-Mowers-Reel-Lawn-Mowers/N-5yc1vZc5av - Network accessline 134
CATEGORY = "https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Lawn-Mowers/N-5yc1vZc5ar" # from block 1, no query string - Network accessline 135
MAX_PAGES = 3 # safety cap; the run prints when it stops because of it MAX_WAIT = 120 # longest backoff / Retry-After sleep in seconds; a longer ask stops the run UA = "browser-harness-domain-skill/1.0 (+https://githu - Network accessline 137
UA = "browser-harness-domain-skill/1.0 (+https://github.com/browser-use/browser-harness)" # robots.txt fetch only - Network accessline 201
for attempt in range(1, tries + 1): try: req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 202
try: req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 203
req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 204
with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 359
"rating": num(rr.get("averageRating")), "reviews": int(reviews) if reviews is not None else None, "url": "https://www.homedepot.com" + url if isinstance(url, str) and url.startswith("/") else None, - Network accessline 360
"reviews": int(reviews) if reviews is not None else None, "url": "https://www.homedepot.com" + url if isinstance(url, str) and url.startswith("/") else None, "sponsored": bool(obj(p.get("info")).get("isSponsored")), - Network accessline 361
"url": "https://www.homedepot.com" + url if isinstance(url, str) and url.startswith("/") else None, - Network accessline 366
if urllib.parse.urlsplit(CATEGORY).query or not re.match(r"https://www\.homedepot\.com/b/", CATEGORY): - Network accessline 367
raise ValueError("CATEGORY must be a https://www.homedepot.com/b/... URL without a query string") - Network accessline 368
RULES = robots_rules(get("https://www.homedepot.com/robots.txt")) - Network accessline 376
# A brand-new session is served a default store until the site's own script sets the # THD_LOCALIZER cookie. Open the home page first so every listing page uses the same store. open_page("https://www.homedepot.com/", lambda d: d["cookie"], - Network accessline 377
# THD_LOCALIZER cookie. Open the home page first so every listing page uses the same store. open_page("https://www.homedepot.com/", lambda d: d["cookie"], "home page warm-up") time.sleep(3) - Network accessline 378
open_page("https://www.homedepot.com/", lambda d: d["cookie"], "home page warm-up") - Network accessline 381
data = open_page(CATEGORY, grid_done(0), "category page 1") base = data["path"] if not re.match(r"https://www\.homedepot\.com/b/", base): - Network accessline 382
base = data["path"] if not re.match(r"https://www\.homedepot\.com/b/", base): raise RuntimeError(f"category landed on an unexpected page: {data['href']}") - Network accessline 383
if not re.match(r"https://www\.homedepot\.com/b/", base): - Network accessline 437
landed on: https://www.homedepot.com/b/Outdoors-Outdoor-Power-Equipment-Lawn-Mowers/N-5yc1vZc5ar | Lawn Mowers - The Home Depot - Network accessline 452
"rating": 4.5112, "reviews": 1254, "url": "https://www.homedepot.com/p/RYOBI-40V-HP-Brushless-20-in-Cordless-Battery-Walk-Behind-Push-Lawn-Mower-with-6-0-Ah-Battery-and-Charger-RY40HPLM06K/337561634", - Network accessline 453
"reviews": 1254, "url": "https://www.homedepot.com/p/RYOBI-40V-HP-Brushless-20-in-Cordless-Battery-Walk-Behind-Push-Lawn-Mower-with-6-0-Ah-Battery-and-Charger-RY40HPLM06K/337561634", "sponsored": false, - Network accessline 454
"url": "https://www.homedepot.com/p/RYOBI-40V-HP-Brushless-20-in-Cordless-Battery-Walk-Behind-Push-Lawn-Mower-with-6-0-Ah-Battery-and-Charger-RY40HPLM06K/337561634", - Network accessline 478
ITEM_ID = "320326875" # the digits at the end of any /p/ URL, or item_id from the block 2 rows UA = "browser-harness-domain-skill/1.0 (+https://github.com/browser-use/browser-harness)" # robots.txt fetch only - Network accessline 479
UA = "browser-harness-domain-skill/1.0 (+https://github.com/browser-use/browser-harness)" # robots.txt fetch only - Network accessline 511
for attempt in range(1, tries + 1): try: req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 512
try: req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 513
req = urllib.request.Request(url, headers={"User-Agent": UA}) - Network accessline 514
with urllib.request.urlopen(req, timeout=60) as r: - Network accessline 630
RULES = robots_rules(get("https://www.homedepot.com/robots.txt")) - Network accessline 636
cdp("Page.addScriptToEvaluateOnNewDocument", source=HOOK) # Warm-up: let the site pick a store (THD_LOCALIZER cookie) before the product page asks for stock. open_page("https://www.homedepot.com/", lambda d: d["cookie"], "home page warm-up" - Network accessline 637
# Warm-up: let the site pick a store (THD_LOCALIZER cookie) before the product page asks for stock. open_page("https://www.homedepot.com/", lambda d: d["cookie"], "home page warm-up") time.sleep(3) - Network accessline 638
open_page("https://www.homedepot.com/", lambda d: d["cookie"], "home page warm-up") - Network accessline 639
time.sleep(3) # /p/<id> redirects to the canonical /p/<slug>/<id>; wait for that page's own JSON-LD. d = open_page(f"https://www.homedepot.com/p/{ITEM_ID}", - Network accessline 640
# /p/<id> redirects to the canonical /p/<slug>/<id>; wait for that page's own JSON-LD. d = open_page(f"https://www.homedepot.com/p/{ITEM_ID}", lambda d: d["path"].rstrip("/").endswith("/" + ITEM_ID) and ld_product(d["ld"]) is - Network accessline 641
d = open_page(f"https://www.homedepot.com/p/{ITEM_ID}", - Network accessline 730
"rating": 4.7, "reviews": 2491, "url": "https://www.homedepot.com/p/Milwaukee-M18-FUEL-18V-Lithium-Ion-Brushless-Cordless-1-4-in-Hex-Impact-Driver-Tool-Only-2953-20/320326875", - Network accessline 731
"reviews": 2491, "url": "https://www.homedepot.com/p/Milwaukee-M18-FUEL-18V-Lithium-Ion-Brushless-Cordless-1-4-in-Hex-Impact-Driver-Tool-Only-2953-20/320326875", "image": "https://images.thdstatic.com/productImages/3ca82630-d888-44f5-bd56 - Network accessline 732
"url": "https://www.homedepot.com/p/Milwaukee-M18-FUEL-18V-Lithium-Ion-Brushless-Cordless-1-4-in-Hex-Impact-Driver-Tool-Only-2953-20/320326875", - Network accessline 733
"image": "https://images.thdstatic.com/productImages/3ca82630-d888-44f5-bd56-b2798a6d59f8/svn/milwaukee-impact-drivers-2953-20-64_100.jpg",
agent-workspace/domain-skills/howlongtobeat/scraping.md
- Network accessline 17
def get_token(): """Fetch a fresh session token. Token encodes IP+UA+timestamp, reusable for ~15 min.""" url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" - Network accessline 18
"""Fetch a fresh session token. Token encodes IP+UA+timestamp, reusable for ~15 min.""" url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" data = http_get(url, headers={"Referer": "https://howlongtobeat.com/" - Network accessline 19
url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" - Network accessline 20
data = http_get(url, headers={"Referer": "https://howlongtobeat.com/"}) - Network accessline 49
hp_key: hp_val # honeypot field — key and value vary per token } req = urllib.request.Request( - Network accessline 50
} req = urllib.request.Request( "https://howlongtobeat.com/api/find", - Network accessline 51
req = urllib.request.Request( - Network accessline 52
"https://howlongtobeat.com/api/find", - Network accessline 55
"User-Agent": UA, "Content-Type": "application/json", "Origin": "https://howlongtobeat.com", - Network accessline 56
"Content-Type": "application/json", "Origin": "https://howlongtobeat.com", "Referer": "https://howlongtobeat.com/", - Network accessline 57
"Origin": "https://howlongtobeat.com", - Network accessline 58
"Referer": "https://howlongtobeat.com/", - Network accessline 63
method="POST" ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 64
) with urllib.request.urlopen(req, timeout=20) as r: return json.loads(r.read().decode()) - Network accessline 65
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 97
def hltb_search(title, size=5): """One-shot: get token + search, return list of dicts with hours.""" url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" - Network accessline 98
"""One-shot: get token + search, return list of dicts with hours.""" url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" tok = json.loads(http_get(url, headers={"Referer": "https://howlongtobeat.com/"})) - Network accessline 99
url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" - Network accessline 100
tok = json.loads(http_get(url, headers={"Referer": "https://howlongtobeat.com/"})) - Network accessline 112
"useCache": True, hp_key: hp_val } req = urllib.request.Request( - Network accessline 113
} req = urllib.request.Request( "https://howlongtobeat.com/api/find", data=json.dumps(payload).encode(), - Network accessline 114
req = urllib.request.Request( - Network accessline 115
"https://howlongtobeat.com/api/find", data=json.dumps(payload).encode(), - Network accessline 116
[Credential-related source omitted] - Network accessline 117
"Origin": "https://howlongtobeat.com", "Referer": "https://howlongtobeat.com/", - Network accessline 119
method="POST" ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 120
) with urllib.request.urlopen(req, timeout=20) as r: data = json.loads(r.read().decode()) - Network accessline 121
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 140
"comp_count": g["comp_100_count"], "review_score": g["review_score"], # 0–100 "image_url": f"https://howlongtobeat.com/games/{g['game_image']}", - Network accessline 141
"review_score": g["review_score"], # 0–100 "image_url": f"https://howlongtobeat.com/games/{g['game_image']}", "page_url": f"https://howlongtobeat.com/game/{g['game_id']}", - Network accessline 142
"image_url": f"https://howlongtobeat.com/games/{g['game_image']}", - Network accessline 143
"page_url": f"https://howlongtobeat.com/game/{g['game_id']}", - Network accessline 171
Returns pageProps['game']['data'] with keys: 'game', 'individuality', 'relationships'. """ html = http_get(f"https://howlongtobeat.com/game/{game_id}") - Network accessline 172
""" html = http_get(f"https://howlongtobeat.com/game/{game_id}") nd = json.loads(re.search( - Network accessline 173
html = http_get(f"https://howlongtobeat.com/game/{game_id}") - Network accessline 252
def get_times(title): """Return Main/+Extras/100% hours for the top search match.""" tok_url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" - Network accessline 253
"""Return Main/+Extras/100% hours for the top search match.""" tok_url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" tok = json.loads(http_get(tok_url, headers={"Referer": "https://howlongtobeat.com/"})) - Network accessline 254
tok_url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" - Network accessline 255
tok = json.loads(http_get(tok_url, headers={"Referer": "https://howlongtobeat.com/"})) - Network accessline 267
"useCache": True, hp_key: hp_val } req = urllib.request.Request( - Network accessline 268
} req = urllib.request.Request( "https://howlongtobeat.com/api/find", data=json.dumps(payload).encode(), - Network accessline 269
req = urllib.request.Request( - Network accessline 270
"https://howlongtobeat.com/api/find", data=json.dumps(payload).encode(), - Network accessline 271
[Credential-related source omitted] - Network accessline 272
"Origin": "https://howlongtobeat.com", "Referer": "https://howlongtobeat.com/", - Network accessline 274
method="POST" ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 275
) with urllib.request.urlopen(req, timeout=20) as r: data = json.loads(r.read().decode()) - Network accessline 276
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 302
def search_all_pages(title, size=20): """Yield every search result for a query across all pages.""" tok_url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" - Network accessline 303
"""Yield every search result for a query across all pages.""" tok_url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" tok = json.loads(http_get(tok_url, headers={"Referer": "https://howlongtobeat.com/"})) - Network accessline 304
tok_url = f"https://howlongtobeat.com/api/find/init?t={int(time.time()*1000)}" - Network accessline 305
tok = json.loads(http_get(tok_url, headers={"Referer": "https://howlongtobeat.com/"})) - Network accessline 321
"useCache": True, hp_key: hp_val } req = urllib.request.Request( - Network accessline 322
} req = urllib.request.Request( "https://howlongtobeat.com/api/find", data=json.dumps(payload).encode(), - Network accessline 323
req = urllib.request.Request( - Network accessline 324
"https://howlongtobeat.com/api/find", data=json.dumps(payload).encode(), - Network accessline 325
[Credential-related source omitted] - Network accessline 326
"Origin": "https://howlongtobeat.com", "Referer": "https://howlongtobeat.com/", - Network accessline 328
method="POST" ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 329
) with urllib.request.urlopen(req, timeout=20) as r: data = json.loads(r.read().decode()) - Network accessline 330
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 349
def fetch_game(game_id): html = http_get(f"https://howlongtobeat.com/game/{game_id}") - Network accessline 350
html = http_get(f"https://howlongtobeat.com/game/{game_id}") - Network accessline 387
| `game_alias` | str | Alternate title / edition name | | `game_type` | str | `"game"` \| `"dlc"` \| `"expansion"` \| `"hack"` | | `game_image` | str | Image filename → `https://howlongtobeat.com/games/{game_image}` | - Network accessline 388
| `game_type` | str | `"game"` \| `"dlc"` \| `"expansion"` \| `"hack"` | | `game_image` | str | Image filename → `https://howlongtobeat.com/games/{game_image}` | | `release_world` | int | Release year (just the year integer, not a date) | - Network accessline 389
| `game_image` | str | Image filename → `https://howlongtobeat.com/games/{game_image}` | - Network accessline 439
- **Token system**: Every search requires a fresh token from `/api/find/init`. Token encodes `timestamp::IP|UA|hpKey|hmacHash`. The server validates that the UA used to fetch the token matches the UA used in the search POST. - **Honeypot fi - Network accessline 440
- **Honeypot field**: `hpKey` and `hpVal` from the init response must appear as a top-level field in the POST body (e.g., `{"ign_7671546b": "a6679ea54598d502", ...}`). The key name rotates per request. - **Required headers on search POST**: - Network accessline 441
- **Required headers on search POST**: `Origin: https://howlongtobeat.com` AND `Referer: https://howlongtobeat.com/` — missing either causes HTTP 403 or 404. `x-auth-token`, `x-hp-key`, `x-hp-val` are also required. - **Required header on i - Network accessline 442
- **Required header on init GET**: `Referer: https://howlongtobeat.com/` — missing causes HTTP 403. - **Token reuse**: A single token works for multiple searches and multiple pages. No per-request token fetch needed. - **No CAPTCHA** observ
agent-workspace/domain-skills/hubspot/private-app-webhooks.md
- Network accessline 7
- `https://app-<region>.hubspot.com/private-apps/{portalId}/{appId}/webhooks` — **read-only view** of current subscriptions. Useful for verification after a change. `<region>` is `na1`, `na2`, `eu1`, etc. - Network accessline 8
- `https://app-<region>.hubspot.com/private-apps/{portalId}/{appId}/edit` — drops you into the editor. From here, click the **Webhooks** tab in the left rail to reach the subscription editor.
agent-workspace/domain-skills/imdb/scraping.md
- Network accessline 3
`https://www.imdb.com` — the Internet Movie Database. Field-tested on 2026-04-24 against `chart/top`, `chart/moviemeter`, `find/?s=tt&q=`, and `title/tt{id}/` pages. - Network accessline 31
goto("https://www.imdb.com/chart/top/") - Network accessline 97
goto("https://www.imdb.com/chart/moviemeter/") - Network accessline 117
def imdb_search(keyword, limit=25): q = urllib.parse.quote(keyword) goto(f"https://www.imdb.com/find/?s=tt&q={q}") - Network accessline 118
q = urllib.parse.quote(keyword) goto(f"https://www.imdb.com/find/?s=tt&q={q}") wait_for_load() - Network accessline 119
goto(f"https://www.imdb.com/find/?s=tt&q={q}") - Network accessline 157
hits = imdb_search("shawshank") # [{'tt_id': 'tt0111161', 'title': 'The Shawshank Redemption', # 'url': 'https://www.imdb.com/title/tt0111161/', - Network accessline 158
# [{'tt_id': 'tt0111161', 'title': 'The Shawshank Redemption', # 'url': 'https://www.imdb.com/title/tt0111161/', # 'meta': ['1994', 'Feature', 'Tim Robbins, Morgan Freeman']}, ...] - Network accessline 159
# 'url': 'https://www.imdb.com/title/tt0111161/', - Network accessline 177
def more_like_this(tt_id, limit=12): goto(f"https://www.imdb.com/title/{tt_id}/") - Network accessline 178
goto(f"https://www.imdb.com/title/{tt_id}/") - Network accessline 265
**`http_get` works on title pages.** If you only need year, runtime, directors, cast, and the aggregate rating, a plain `http_get(f"https://www.imdb.com/title/{tt_id}/")` gives you the `<script type="application/ld+json">` Movie block in on
agent-workspace/domain-skills/itch-io/scraping.md
- Network accessline 33
Parse any itch.io RSS listing feed. url examples: https://itch.io/games/top-rated.xml - Network accessline 34
url examples: https://itch.io/games/top-rated.xml https://itch.io/games/newest.xml - Network accessline 35
https://itch.io/games/top-rated.xml - Network accessline 36
https://itch.io/games/newest.xml - Network accessline 37
https://itch.io/games/featured.xml - Network accessline 38
https://itch.io/games/on-sale.xml - Network accessline 39
https://itch.io/games/free.xml - Network accessline 40
https://itch.io/games/tag-puzzle.xml # any tag slug works - Network accessline 41
https://itch.io/games/top-rated.xml?page=2 - Network accessline 66
# Confirmed output: items = parse_rss("https://itch.io/games/top-rated.xml") - Network accessline 67
items = parse_rss("https://itch.io/games/top-rated.xml") - Network accessline 68
# items[0] -> { # 'url': 'https://gbpatch.itch.io/our-life', # 'title': 'Our Life: Beginnings & Always', - Network accessline 69
# 'url': 'https://gbpatch.itch.io/our-life', - Network accessline 73
# 'pub_date': 'Fri, 07 Jun 2019 23:47:57 GMT', # 'update_date': 'Sun, 22 May 2022 15:48:27 GMT', # 'image': 'https://img.itch.zone/aW1nLzcwMTIxNDMucG5n/315x250%23c/BalGQb.png', - Network accessline 74
# 'update_date': 'Sun, 22 May 2022 15:48:27 GMT', # 'image': 'https://img.itch.zone/aW1nLzcwMTIxNDMucG5n/315x250%23c/BalGQb.png', # 'platforms': {'windows': True, 'osx': True, 'linux': True, 'android': True}, - Network accessline 75
# 'image': 'https://img.itch.zone/aW1nLzcwMTIxNDMucG5n/315x250%23c/BalGQb.png', - Network accessline 92
Extract all game cards from any itch.io browse/listing/search/profile HTML page. Works on: https://itch.io/games/top-rated - Network accessline 93
Works on: https://itch.io/games/top-rated https://itch.io/games/newest - Network accessline 94
https://itch.io/games/top-rated - Network accessline 95
https://itch.io/games/newest - Network accessline 96
https://itch.io/games/featured - Network accessline 97
https://itch.io/games/on-sale - Network accessline 98
https://itch.io/games/free - Network accessline 99
https://itch.io/games/tag-puzzle (genre/tag path) - Network accessline 100
https://itch.io/search?q=platformer (search — 54 cards per page) - Network accessline 142
# Usage: html = http_get("https://itch.io/games/top-rated") - Network accessline 143
html = http_get("https://itch.io/games/top-rated") - Network accessline 144
games = parse_game_cards(html) # games[0] -> { # 'id': '434554', 'url': 'https://gbpatch.itch.io/our-life', - Network accessline 145
# games[0] -> { # 'id': '434554', 'url': 'https://gbpatch.itch.io/our-life', # 'title': 'Our Life: Beginnings & Always', - Network accessline 146
# 'id': '434554', 'url': 'https://gbpatch.itch.io/our-life', - Network accessline 153
# Paid game example: html = http_get("https://itch.io/games/top-rated?page=5") - Network accessline 154
html = http_get("https://itch.io/games/top-rated?page=5") - Network accessline 242
# Free game: r = extract_game_detail("https://gbpatch.itch.io/our-life") - Network accessline 243
r = extract_game_detail("https://gbpatch.itch.io/our-life") - Network accessline 247
# 'price': None, 'currency': None, <- no 'offers' block for free games # 'rating': '4.9', 'rating_count': 7191, # 'cover': 'https://img.itch.zone/aW1hZ2Uv.../347x500/7HqrvV.jpg', - Network accessline 248
# 'rating': '4.9', 'rating_count': 7191, # 'cover': 'https://img.itch.zone/aW1hZ2Uv.../347x500/7HqrvV.jpg', # 'info': { - Network accessline 249
# 'cover': 'https://img.itch.zone/aW1hZ2Uv.../347x500/7HqrvV.jpg', - Network accessline 261
# Paid game: r = extract_game_detail("https://adamgryu.itch.io/a-short-hike") - Network accessline 262
r = extract_game_detail("https://adamgryu.itch.io/a-short-hike") - Network accessline 308
""" Scrape multiple pages from any itch.io browse URL. base_url: https://itch.io/games/top-rated (no ?page= suffix) - Network accessline 309
Scrape multiple pages from any itch.io browse URL. base_url: https://itch.io/games/top-rated (no ?page= suffix) Returns flat list of game dicts. - Network accessline 310
base_url: https://itch.io/games/top-rated (no ?page= suffix) - Network accessline 341
BASE = "https://itch.io/games" - Network accessline 354
# Combine: tag + sort via separate pages (no combined URL that survives http_get) # Note: https://itch.io/games/top-rated/tag-puzzle -> HTTP 403 - Network accessline 355
# Note: https://itch.io/games/top-rated/tag-puzzle -> HTTP 403 - Network accessline 367
# Search (54 results/page, no server-side pagination beyond page 1 via http_get) "https://itch.io/search?q=platformer" - Network accessline 368
"https://itch.io/search?q=platformer" - Network accessline 378
itch.io has an official REST API. A free key is issued per-account with no rate limit published. Get one at: `https://itch.io/user/settings/api-keys` - Network accessline 379
Get one at: `https://itch.io/user/settings/api-keys` - Network accessline 381
Base URL: `https://itch.io/api/1/<key>/` - Network accessline 387
ITCH_KEY = "your_api_key_here" # from https://itch.io/user/settings/api-keys - Network accessline 389
def api(path): return json.loads(http_get(f"https://itch.io/api/1/{ITCH_KEY}/{path}")) - Network accessline 390
return json.loads(http_get(f"https://itch.io/api/1/{ITCH_KEY}/{path}")) - Network accessline 411
**No unauthenticated game lookup API.** `https://itch.io/api/1/x/games` -> HTTP 404. - Network accessline 428
6. **`?tag=` query param is ignored server-side.** `https://itch.io/games/top-rated?tag=puzzle` returns the same games as `?top-rated`. Use `/games/tag-puzzle` path instead. - Network accessline 432
8. **Search beyond page 1 is AJAX-only.** `https://itch.io/search?q=X&page=2` via `http_get` returns the same 54 results as page 1. To get more search results use the browser and scroll/click "load more". - Possible obfuscationline 436
10. **Unicode zero-width space in some titles.** `\u200b` (zero-width space) appears at the start of certain titles (e.g. "<U+200B>Our Life: Beginnings & Always"). Strip with `.replace('\u200b', '').strip()` or `.strip()` alone won't remove it — u
agent-workspace/domain-skills/jetblue/checkout.md
- Network accessline 9
- Home: `https://www.jetblue.com` - Network accessline 10
- Search results (deep link, skips home form): `https://www.jetblue.com/booking/flights?from={IATA}&to={IATA}&depart=YYYY-MM-DD&isMultiCity=false&noOfRoute=1&adults=1&children=0&infants=0&roundTripFaresFlag=false&sharedMarket=false&usePoint - Network accessline 11
- Cart: `https://www.jetblue.com/booking/cart` - Network accessline 12
- Checkout (all three steps share this URL; tabs rendered as sections): `https://www.jetblue.com/booking/checkout` (titles change: `Traveler Details` -> `Seats & Extras` -> `Review & Pay`)
agent-workspace/domain-skills/job-boards/indeed-glassdoor.md
- Network accessline 14
# Indeed — English (US) query, location = "Python developer", "San Francisco" goto_url(f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}") - Network accessline 15
query, location = "Python developer", "San Francisco" goto_url(f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}") wait_for_load() - Network accessline 16
goto_url(f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}") - Network accessline 20
# Indeed — last 24 hours goto_url(f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}&fromage=1") - Network accessline 21
goto_url(f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}&fromage=1") - Network accessline 25
# Glassdoor — public search (no login required for result cards) goto_url(f"https://www.glassdoor.com/Job/jobs.htm?sc.keyword={quote_plus(query)}") - Network accessline 26
goto_url(f"https://www.glassdoor.com/Job/jobs.htm?sc.keyword={quote_plus(query)}") - Network accessline 30
# Stepstone (Germany) keyword, city = "Data Scientist", "Berlin" goto_url(f"https://www.stepstone.de/jobs/{quote_plus(keyword)}/in-{quote_plus(city)}.html") - Network accessline 31
keyword, city = "Data Scientist", "Berlin" goto_url(f"https://www.stepstone.de/jobs/{quote_plus(keyword)}/in-{quote_plus(city)}.html") wait_for_load() - Network accessline 32
goto_url(f"https://www.stepstone.de/jobs/{quote_plus(keyword)}/in-{quote_plus(city)}.html") - Network accessline 53
| Page 2 (results 11-20) | append `&start=10` | | Page 3 (results 21-30) | append `&start=20` | | Job detail page | `https://www.indeed.com/viewjob?jk={job_key}` | - Network accessline 55
| Job detail page | `https://www.indeed.com/viewjob?jk={job_key}` | - Network accessline 79
kw_path = keyword.replace(" ", "-") city_path = city.replace(" ", "-") goto_url(f"https://www.stepstone.de/jobs/{kw_path}/in-{city_path}.html") - Network accessline 81
goto_url(f"https://www.stepstone.de/jobs/{kw_path}/in-{city_path}.html") - Network accessline 125
goto_url("https://www.indeed.co.uk/jobs?q=Python+developer&l=London") - Network accessline 142
query, location = "machine learning engineer", "New York" goto_url(f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}") - Network accessline 143
goto_url(f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}") - Network accessline 178
// Direct URL via job key var url = 'https://www.indeed.com/viewjob?jk=' + jk; - Network accessline 179
var url = 'https://www.indeed.com/viewjob?jk=' + jk; - Network accessline 205
query, location = "data scientist", "remote" base_url = f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}" - Network accessline 206
base_url = f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}" - Network accessline 238
salary: salEl ? salEl.innerText.trim() : '', posted: dateEl ? dateEl.innerText.trim() : '', url: 'https://www.indeed.com/viewjob?jk=' + jk, - Network accessline 239
posted: dateEl ? dateEl.innerText.trim() : '', url: 'https://www.indeed.com/viewjob?jk=' + jk, }); - Network accessline 240
url: 'https://www.indeed.com/viewjob?jk=' + jk, - Network accessline 257
base_url = f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}&fromage=1" - Network accessline 269
def get_indeed_job_detail(jk: str) -> dict: """Fetch full job details from an Indeed job key.""" goto_url(f"https://www.indeed.com/viewjob?jk={jk}") - Network accessline 270
"""Fetch full job details from an Indeed job key.""" goto_url(f"https://www.indeed.com/viewjob?jk={jk}") wait_for_load() - Network accessline 271
goto_url(f"https://www.indeed.com/viewjob?jk={jk}") - Network accessline 326
query = "product manager" goto_url(f"https://www.glassdoor.com/Job/jobs.htm?sc.keyword={quote_plus(query)}") - Network accessline 327
goto_url(f"https://www.glassdoor.com/Job/jobs.htm?sc.keyword={quote_plus(query)}") - Network accessline 370
// Canonical URL var linkEl = c.querySelector('a[href*="/job-listing/"], a[href*="glassdoor.com/job"]'); var url = linkEl ? linkEl.href : (jobId ? 'https://www.glassdoor.com/job-listing/glassdoor-jl' + jobId + '.htm' : ''); - Network accessline 372
var url = linkEl ? linkEl.href : (jobId ? 'https://www.glassdoor.com/job-listing/glassdoor-jl' + jobId + '.htm' : ''); - Network accessline 451
goto_url(f"https://www.stepstone.de/jobs/{kw_path}/in-{city_path}.html") - Network accessline 500
for page in range(1, 4): # pages 1-3 if page == 1: url = f"https://www.stepstone.de/jobs/{kw_path}/in-{city_path}.html" - Network accessline 501
if page == 1: url = f"https://www.stepstone.de/jobs/{kw_path}/in-{city_path}.html" else: - Network accessline 502
url = f"https://www.stepstone.de/jobs/{kw_path}/in-{city_path}.html" - Network accessline 504
url = f"https://www.stepstone.de/jobs/{kw_path}/in-{city_path}/page-{page}.html" - Network accessline 562
# Canonical job detail URL for any job key: for jk in jks: direct_url = f"https://www.indeed.com/viewjob?jk={jk}" - Network accessline 563
for jk in jks: direct_url = f"https://www.indeed.com/viewjob?jk={jk}" print(direct_url) - Network accessline 564
direct_url = f"https://www.indeed.com/viewjob?jk={jk}" - Network accessline 718
html = http_get( f"https://www.indeed.com/jobs?{params}", - Network accessline 719
f"https://www.indeed.com/jobs?{params}", - Network accessline 758
"salary": r.get("salarySnippet", {}).get("text", ""), "posted": r.get("formattedRelativeTime", ""), "url": f"https://www.indeed.com/viewjob?jk={jk}", - Network accessline 759
"posted": r.get("formattedRelativeTime", ""), "url": f"https://www.indeed.com/viewjob?jk={jk}", "snippet": r.get("snippet", ""), # short description preview - Network accessline 760
"url": f"https://www.indeed.com/viewjob?jk={jk}", - Network accessline 780
def get_application_type(jk: str) -> dict: """Returns {type: 'easy_apply'|'external'|'unknown', external_url: str|None}""" goto_url(f"https://www.indeed.com/viewjob?jk={jk}") - Network accessline 781
"""Returns {type: 'easy_apply'|'external'|'unknown', external_url: str|None}""" goto_url(f"https://www.indeed.com/viewjob?jk={jk}") wait_for_load() - Network accessline 782
goto_url(f"https://www.indeed.com/viewjob?jk={jk}") - Network accessline 887
start: int = 0, ) -> str: base = f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}" - Network accessline 888
) -> str: base = f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}" if fromage: - Network accessline 889
base = f"https://www.indeed.com/jobs?q={quote_plus(query)}&l={quote_plus(location)}" - Network accessline 955
salary: salEl ? salEl.innerText.trim() : '', posted: dateEl ? dateEl.innerText.trim() : '', url: 'https://www.indeed.com/viewjob?jk=' + jk, - Network accessline 956
posted: dateEl ? dateEl.innerText.trim() : '', url: 'https://www.indeed.com/viewjob?jk=' + jk, }); - Network accessline 957
url: 'https://www.indeed.com/viewjob?jk=' + jk, - Network accessline 987
- **Indeed redirect links are NOT stable URLs** — Anchor `href` values in search results go through `https://www.indeed.com/rc/clk?...` tracking redirects which expire. Always extract `data-jk` from the card and construct `https://www.indee
agent-workspace/domain-skills/kalshi/scraping.md
- Network accessline 3
Field-tested against kalshi.com and api.elections.kalshi.com on 2026-11-02 using a Browser Use cloud browser, logged out. Every browser call is a `fetch()` from a kalshi.com tab to Kalshi's public Trade API. No CAPTCHA, 403 or 429 across ab - Network accessline 5
robots.txt (kalshi.com, fetched 2026-11-02 in the browser): `User-agent: *` disallows only `/ideas` (except `/ideas/profiles/` and `/ideas/posts/`), `/sign-up?` and `/search`, so `/robots.txt` and `/markets/...` are allowed; api.elections.k - Network accessline 13
- `GET /trade-api/v2/markets/<TICKER>/orderbook?depth=<n>` - bids only, both sides, as `[price_dollars, contracts]` string pairs. - `GET /trade-api/v2/markets/trades?ticker=<TICKER>&limit=<n>` - recent fills. - **Base host:** `https://api - Network accessline 14
- `GET /trade-api/v2/markets/trades?ticker=<TICKER>&limit=<n>` - recent fills. - **Base host:** `https://api.elections.kalshi.com/trade-api/v2/` (Kalshi's AGENTS.md calls it production; the docs list `https://external-api.kalshi.com/trade-a - Network accessline 15
- **Base host:** `https://api.elections.kalshi.com/trade-api/v2/` (Kalshi's AGENTS.md calls it production; the docs list `https://external-api.kalshi.com/trade-api/v2` first and this one as "also supported"; both returned the same events to - Network accessline 16
- **Run `fetch()` from a kalshi.com tab.** The API's CORS answers `access-control-allow-origin: https://kalshi.com`. The blocks open `https://kalshi.com/robots.txt` (small, robots-allowed) once and reuse it. - Network accessline 22
All browser blocks share the same helpers: `on_kalshi_tab()` opens `https://kalshi.com/robots.txt` once and later blocks reuse that tab; it raises if Vercel's "Security Checkpoint" page appears instead. `get(path, params)` fetches `https:// - Network accessline 35
API = "https://api.elections.kalshi.com/trade-api/v2/" - Network accessline 38
def on_kalshi_tab(): """fetch() runs in a logged-out kalshi.com tab: the API's CORS allows that origin. Reuse the tab if already there.""" - Network accessline 39
"""fetch() runs in a logged-out kalshi.com tab: the API's CORS allows that origin. Reuse the tab if already there.""" - Network accessline 40
try: if js("location.origin") == "https://kalshi.com": return - Network accessline 41
if js("location.origin") == "https://kalshi.com": - Network accessline 43
except Exception: pass new_tab("https://kalshi.com/robots.txt") # small robots-allowed page on kalshi.com - Network accessline 44
pass new_tab("https://kalshi.com/robots.txt") # small robots-allowed page on kalshi.com wait_for_load() - Network accessline 45
new_tab("https://kalshi.com/robots.txt") # small robots-allowed page on kalshi.com - Network accessline 50
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, text: await r.text()}; } - Network accessline 51
try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, text: await r.text()}; } - Network accessline 96
"lead_last_cents": lead and cents(lead["last_price_dollars"]), "volume_24h": round(sum(float(m.get("volume_24h_fp") or 0) for m in ms), 2), "url": f"https://kalshi.com/markets/{e['series_ticker'].lower()}/{e[ - Network accessline 97
"volume_24h": round(sum(float(m.get("volume_24h_fp") or 0) for m in ms), 2), "url": f"https://kalshi.com/markets/{e['series_ticker'].lower()}/{e['event_ticker'].lower()}", }) - Network accessline 98
"url": f"https://kalshi.com/markets/{e['series_ticker'].lower()}/{e['event_ticker'].lower()}", - Network accessline 140
URLS = [ "https://kalshi.com/markets/kxfeddecision", # series page: soonest-closing open event - Network accessline 141
"https://kalshi.com/markets/kxfeddecision", # series page: soonest-closing open event - Network accessline 142
"https://kalshi.com/markets/kxhighny/highest-temperature-in-nyc/kxhighny-26nov01", # event page, settled - Network accessline 143
"https://kalshi.com/markets/kxhighny/kxhighny-25jan01", # settled before the historical cutoff - Network accessline 144
"https://kalshi.com/markets/kxnosuchseries", - Network accessline 147
API = "https://api.elections.kalshi.com/trade-api/v2/" - Network accessline 150
def on_kalshi_tab(): """fetch() runs in a logged-out kalshi.com tab: the API's CORS allows that origin. Reuse the tab if already there.""" - Network accessline 151
"""fetch() runs in a logged-out kalshi.com tab: the API's CORS allows that origin. Reuse the tab if already there.""" - Network accessline 152
try: if js("location.origin") == "https://kalshi.com": return - Network accessline 153
if js("location.origin") == "https://kalshi.com": - Network accessline 155
except Exception: pass new_tab("https://kalshi.com/robots.txt") - Network accessline 156
pass new_tab("https://kalshi.com/robots.txt") wait_for_load() - Network accessline 157
new_tab("https://kalshi.com/robots.txt") - Network accessline 162
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, text: await r.text()}; } - Network accessline 163
try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, text: await r.text()}; } - Network accessline 202
"category": ev.get("category"), "mutually_exclusive": ev.get("mutually_exclusive"), "settlement_sources": [s.get("name") for s in ev.get("settlement_sources") or []], "url": f"https://kalshi.com/markets/{ev['series_ticker']. - Network accessline 203
"settlement_sources": [s.get("name") for s in ev.get("settlement_sources") or []], "url": f"https://kalshi.com/markets/{ev['series_ticker'].lower()}/{ev['event_ticker'].lower()}", "markets": [{ - Network accessline 204
"url": f"https://kalshi.com/markets/{ev['series_ticker'].lower()}/{ev['event_ticker'].lower()}", - Network accessline 258
https://kalshi.com/markets/kxnosuchseries: no open event found - Network accessline 270
API = "https://api.elections.kalshi.com/trade-api/v2/" - Network accessline 273
def on_kalshi_tab(): """fetch() runs in a logged-out kalshi.com tab: the API's CORS allows that origin. Reuse the tab if already there.""" - Network accessline 274
"""fetch() runs in a logged-out kalshi.com tab: the API's CORS allows that origin. Reuse the tab if already there.""" - Network accessline 275
try: if js("location.origin") == "https://kalshi.com": return - Network accessline 276
if js("location.origin") == "https://kalshi.com": - Network accessline 278
except Exception: pass new_tab("https://kalshi.com/robots.txt") - Network accessline 279
pass new_tab("https://kalshi.com/robots.txt") wait_for_load() - Network accessline 280
new_tab("https://kalshi.com/robots.txt") - Network accessline 285
FETCH_JS = """(async () => { try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, text: await r.text()}; } - Network accessline 286
try { const r = await fetch(%s, {credentials: 'omit'}); return {status: r.status, text: await r.text()}; } - Network accessline 379
curl -s "https://api.elections.kalshi.com/trade-api/v2/markets/KXFEDDECISION-26DEC-H25/orderbook?depth=3"; echo - Dangerous shell operationline 380
curl -s "https://api.elections.kalshi.com/trade-api/v2/historical/markets?event_ticker=KXHIGHNY-25JAN01" | python3 -c 'import json, sys; [print(m["ticker"], m["result"], m["last_price_dollars"]) for m in json.load(sys.stdin)["markets"]]' - Network accessline 380
curl -s "https://api.elections.kalshi.com/trade-api/v2/historical/markets?event_ticker=KXHIGHNY-25JAN01" \ - Network accessline 414
- **Bids only in the order book.** A NO bid at p is a YES ask at 1 - p (Kalshi's "Orderbook Responses" doc). Today the computed best ask matched the market snapshot's `yes_ask_dollars` (0.73 / 0.73) and best bid matched `yes_bid_dollars` (0 - Network accessline 415
- **Unknown ticker on `/orderbook` is HTTP 200** with empty `yes_dollars` / `no_dollars`, not 404. Block 3 checks `/markets/<ticker>` first (that one returns 404 `{"error":{"code":"not_found",...}}`). - **Status filter values differ from st - Network accessline 416
- **Status filter values differ from status field values.** Filter with `status=open` (`unopened`, `open`, `closed`, `settled`); market objects say `active` / `finalized`. `status=active`, which kalshi.com/AGENTS.md shows in its `/markets` - Network accessline 421
- **Sum of YES asks exceeds 100c** in mutually exclusive events (on 2026-11-02: 105c for the Fed decision, 103c to 105c during the day for NYC high temperature on Nov 2): asks carry the spread. Use last or mid for an implied probability. - - Network accessline 422
- **Page vs API.** On the event page, "Yes NNc" is the YES ask, "No NNc" the NO ask, and the big percent matched `last_price_dollars` in the row checked (65° to 66°: 92% / Yes 92c / No 10c vs API last 0.92, yes_ask 0.92, no_ask 0.10). Anoth - Network accessline 423
- **URLs.** `https://kalshi.com/markets/<series>/<event>` (lowercase) redirects to the canonical `/markets/<series>/<slug>/<event>`, and `/markets/<series>` redirects to its current event, so a URL can be built from tickers alone. - **Rate - Network accessline 429
- **Same-origin `fetch()` from an api.elections.kalshi.com tab:** `TypeError: Failed to fetch` on every path today, although navigating to the same URL showed the JSON. Fetch from a kalshi.com tab instead. - Network accessline 430
- **Other origins:** a request with `Origin: https://example.com` got HTTP 403, so `fetch()` from a non-Kalshi page fails. - Network accessline 431
- **Plain HTTP to kalshi.com pages:** `curl https://kalshi.com/robots.txt` got HTTP 429 with a "Vercel Security Checkpoint" page. Not worked around; the browser loaded the same URL normally. The API host does not do this.
agent-workspace/domain-skills/letterboxd/scraping.md
- Network accessline 3
`https://letterboxd.com` — film logging, rating, and review site. Film pages and user profile root pages are publicly accessible via `http_get` (~200–350ms). Most sub-pages (reviews, ratings, user film lists, browse/genre pages) return 403 - Network accessline 40
slug examples: 'the-godfather', 'parasite-2019', 'inception', '2001-a-space-odyssey' """ html = http_get(f"https://letterboxd.com/film/{slug}/") - Network accessline 41
""" html = http_get(f"https://letterboxd.com/film/{slug}/") result = {} - Network accessline 42
html = http_get(f"https://letterboxd.com/film/{slug}/") - Network accessline 139
# 'og_title': 'The Godfather (1972)', # 'synopsis': 'Spanning the years 1945 to 1955...', # 'poster_url': 'https://a.ltrbxd.com/resized/film-poster/.../51818-the-godfather-0-230-0-345-crop.jpg...', - Network accessline 140
# 'synopsis': 'Spanning the years 1945 to 1955...', # 'poster_url': 'https://a.ltrbxd.com/resized/film-poster/.../51818-the-godfather-0-230-0-345-crop.jpg...', # 'og_image': 'https://a.ltrbxd.com/resized/sm/upload/.../the-godfather-12 - Network accessline 141
# 'poster_url': 'https://a.ltrbxd.com/resized/film-poster/.../51818-the-godfather-0-230-0-345-crop.jpg...', - Network accessline 142
# 'og_image': 'https://a.ltrbxd.com/resized/sm/upload/.../the-godfather-1200-1200-675-675-crop-000000.jpg...', - Network accessline 168
def extract_user_profile(username): html = http_get(f"https://letterboxd.com/{username}/") - Network accessline 169
html = http_get(f"https://letterboxd.com/{username}/") - Network accessline 224
def extract_activity_stream(): html = http_get("https://letterboxd.com/films/") - Network accessline 225
html = http_get("https://letterboxd.com/films/") - Network accessline 259
# Popular films goto_url("https://letterboxd.com/films/popular/") - Network accessline 260
goto_url("https://letterboxd.com/films/popular/") - Network accessline 278
# User watched films list (paginated, 72/page) goto_url("https://letterboxd.com/dave/films/") - Network accessline 279
goto_url("https://letterboxd.com/dave/films/") - Network accessline 296
# User diary entries goto_url("https://letterboxd.com/dave/diary/") - Network accessline 297
goto_url("https://letterboxd.com/dave/diary/")
agent-workspace/domain-skills/linkedin/invitation-manager.md
- Network accessline 3
Accept or ignore pending connection invitations in bulk from `https://www.linkedin.com/mynetwork/invitation-manager/received/<FILTER>/`. - Network accessline 4
`https://www.linkedin.com/mynetwork/invitation-manager/received/<FILTER>/`. - Network accessline 99
while True: cdp("Page.navigate", url="https://www.linkedin.com/mynetwork/invitation-manager/received/PEOPLE_WITH_MUTUAL_CONNECTION/") - Network accessline 100
cdp("Page.navigate", url="https://www.linkedin.com/mynetwork/invitation-manager/received/PEOPLE_WITH_MUTUAL_CONNECTION/")
agent-workspace/domain-skills/loom/folder-enumeration.md
- Access to secretsline 17
[Credential-related source omitted] - Network accessline 125
- `https://www.loom.com/v1/folders/<id>?limit=10000` — works for `/share/folder/...` IDs (this is what `LoomFolderIE` uses), returns `Forbidden` for library folder IDs even with the user's cookies. - Network accessline 126
- `https://www.loom.com/graphql` — fires hundreds of times during page load. A folder-listing operation almost certainly lives in there, but the `query` strings come from the bundled React app and would have to be reverse-engineered from th - Network accessline 137
[Credential-related source omitted] - Access to secretsline 137
[Credential-related source omitted] - Network accessline 139
"https://www.loom.com/share/<any-known-id>" >/dev/null - Network accessline 143
yt-dlp --cookies /tmp/loom_cookies.txt -f http-transcoded -o "%(title)s.%(ext)s" --no-progress --no-warnings --no-mtime --no-overwrites "https://www.loom.com/share/$1" - Network accessline 145
-o "%(title)s.%(ext)s" \ --no-progress --no-warnings --no-mtime --no-overwrites \ "https://www.loom.com/share/$1" - Network accessline 147
"https://www.loom.com/share/$1"
agent-workspace/domain-skills/loom/read-recording.md
agent-workspace/domain-skills/lulu/account-currency.md
- Network accessline 5
Lulu's official [account basics](https://help.lulu.com/en/support/solutions/articles/64000255301-lulu-account-the-basics) says that a preferred account currency cannot be changed through account settings; the account owner must contact supp - Network accessline 11
- Start at `https://help.lulu.com/en/support/tickets/new`. - Network accessline 19
`https://developers.lulu.com/api-keys` may render client credentials in accessible text fields. Avoid full accessibility/DOM dumps of that page. Retrieve only the required credential into private storage when authorized; do not include cred
agent-workspace/domain-skills/ly-com/hotels.md
- Network accessline 29
List page: https://www.ly.com/hotel/hotellist?city=<cityId>&inDate=YYYY-MM-DD&outDate=YYYY-MM-DD - Network accessline 30
https://www.ly.com/hotel/hotellist?city=<cityId>&inDate=YYYY-MM-DD&outDate=YYYY-MM-DD - Network accessline 32
Hotel detail page: https://www.ly.com/hotel/hoteldetail?hotelId=<hotelId>&inDate=YYYY-MM-DD&outDate=YYYY-MM-DD - Network accessline 33
https://www.ly.com/hotel/hoteldetail?hotelId=<hotelId>&inDate=YYYY-MM-DD&outDate=YYYY-MM-DD - Network accessline 35
Login page (with return URL): https://passport.ly.com/?pageurl=<urlencoded-target> - Network accessline 36
https://passport.ly.com/?pageurl=<urlencoded-target> - Network accessline 51
- `https://m.ly.com/scenery/hotel/<hotelId>` — 404 - Network accessline 52
- `https://hotelh5.ly.com/...` — not yet mapped - Network accessline 60
On `https://www.ly.com/hotel/`, the green "搜索" search button is a `<div>`, - Access to secretsline 115
[Credential-related source omitted] - Network accessline 188
new_tab(f"https://passport.ly.com/?pageurl={urllib.parse.quote(target_url)}") - Network accessline 253
HOTEL_ID = "92963586" # 和颐至尊酒店(上海新国际博览中心世博园店) url = f"https://www.ly.com/hotel/hoteldetail?hotelId={HOTEL_ID}&inDate=2026-04-29&outDate=2026-04-30" - Network accessline 254
url = f"https://www.ly.com/hotel/hoteldetail?hotelId={HOTEL_ID}&inDate=2026-04-29&outDate=2026-04-30"
agent-workspace/domain-skills/macrotrends/scraping.md
- Network accessline 3
`https://www.macrotrends.net` — long-term historical financial and economic charts. Three access patterns depending on page type; all work with plain `http_get`, no browser required. - Network accessline 36
Omit (None) to get ALL available history (AAPL goes back to 1980). """ url = f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/stock_price_history.php?t={ticker}" - Network accessline 37
""" url = f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/stock_price_history.php?t={ticker}" if years_back: - Network accessline 38
url = f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/stock_price_history.php?t={ticker}" - Network accessline 104
def get_market_cap(ticker: str, years_back: int = 15) -> list[dict]: url = f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/market_cap.php?t={ticker}&yb={years_back}" - Network accessline 105
url = f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/market_cap.php?t={ticker}&yb={years_back}" - Network accessline 132
""" url = ( f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/" - Network accessline 133
url = ( f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/" f"fundamental_iframe.php?t={ticker}&type={metric_type}&statement={statement}" - Network accessline 134
f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/" - Network accessline 169
def get_profit_margins(ticker: str, years_back: int = 15) -> list[dict]: url = ( f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/" - Network accessline 170
url = ( f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/" f"fundamental_metric.php?t={ticker}&chart=profit-margin&sub=&yb={years_back}" - Network accessline 171
f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/" - Network accessline 193
def get_dividend_yield(ticker: str, years_back: int = 15) -> list[dict]: url = f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/dividend_yield.php?t={ticker}&yb={years_back}" - Network accessline 194
url = f"https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/dividend_yield.php?t={ticker}&yb={years_back}" - Network accessline 225
Base URL prefix: `https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/` - Network accessline 242
url_slug: last segment of the page URL, e.g. 'sp500-pe-ratio-price-to-earnings-chart' """ url = f"https://www.macrotrends.net/assets/php/chart_iframe_comp.php?id={page_id}&url={url_slug}" - Network accessline 243
""" url = f"https://www.macrotrends.net/assets/php/chart_iframe_comp.php?id={page_id}&url={url_slug}" html = http_get(url) - Network accessline 244
url = f"https://www.macrotrends.net/assets/php/chart_iframe_comp.php?id={page_id}&url={url_slug}" - Network accessline 292
page_url = "https://www.macrotrends.net/2577/sp500-pe-ratio-price-to-earnings-chart" - Network accessline 324
Returns {'data': [[ts_ms, value], ...], 'metadata': {...}} """ url = f"https://www.macrotrends.net/economic-data/{page_id}/{freq}" - Network accessline 325
""" url = f"https://www.macrotrends.net/economic-data/{page_id}/{freq}" headers = { - Network accessline 326
url = f"https://www.macrotrends.net/economic-data/{page_id}/{freq}" - Network accessline 331
"Referer": referer_url, } with urllib.request.urlopen(urllib.request.Request(url, headers=headers), timeout=20) as r: - Network accessline 332
} with urllib.request.urlopen(urllib.request.Request(url, headers=headers), timeout=20) as r: raw = r.read() - Network accessline 333
with urllib.request.urlopen(urllib.request.Request(url, headers=headers), timeout=20) as r: - Network accessline 342
# Fed Funds Rate (daily, 25319 records) ffr = get_economic_data(2015, "https://www.macrotrends.net/2015/fed-funds-rate-historical-chart", freq='D') - Network accessline 343
ffr = get_economic_data(2015, "https://www.macrotrends.net/2015/fed-funds-rate-historical-chart", freq='D') - Network accessline 355
# 10-Year Treasury yield (daily, 16074 records) t10 = get_economic_data(2016, "https://www.macrotrends.net/2016/10-year-treasury-bond-rate-yield-chart", freq='D') - Network accessline 356
t10 = get_economic_data(2016, "https://www.macrotrends.net/2016/10-year-treasury-bond-rate-yield-chart", freq='D') - Network accessline 359
# Gold prices (monthly, 1336 records, 1915-present) — template=5 gold = get_economic_data(1333, "https://www.macrotrends.net/1333/historical-gold-prices-100-year-chart", freq='M') - Network accessline 360
gold = get_economic_data(1333, "https://www.macrotrends.net/1333/historical-gold-prices-100-year-chart", freq='M') - Network accessline 363
# US Unemployment Rate (monthly, 938 records) unemp = get_economic_data(1316, "https://www.macrotrends.net/1316/us-national-unemployment-rate", freq='M') - Network accessline 364
unemp = get_economic_data(1316, "https://www.macrotrends.net/1316/us-national-unemployment-rate", freq='M') - Network accessline 367
# Debt-to-GDP ratio (monthly, 712 records) debt_gdp = get_economic_data(1381, "https://www.macrotrends.net/1381/debt-to-gdp-ratio-historical-chart", freq='M') - Network accessline 368
debt_gdp = get_economic_data(1381, "https://www.macrotrends.net/1381/debt-to-gdp-ratio-historical-chart", freq='M') - Network accessline 442
# Works for dataDaily, chartData, or originalData: html = http_get("https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/stock_price_history.php?t=AAPL&yb=15") - Network accessline 443
html = http_get("https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/stock_price_history.php?t=AAPL&yb=15") - Network accessline 446
html2 = http_get("https://www.macrotrends.net/assets/php/chart_iframe_comp.php?id=2577&url=sp500-pe-ratio-price-to-earnings-chart") - Network accessline 457
STOCK_BASE = "https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/" - Network accessline 482
# From numeric ID + URL slug (read from page source or page URL) f"https://www.macrotrends.net/assets/php/chart_iframe_comp.php?id={id}&url={slug}" - Network accessline 483
f"https://www.macrotrends.net/assets/php/chart_iframe_comp.php?id={id}&url={slug}" - Network accessline 485
# Economic indicator JSON API (requires Referer header) f"https://www.macrotrends.net/economic-data/{page_id}/{freq}" - Network accessline 486
f"https://www.macrotrends.net/economic-data/{page_id}/{freq}" - Network accessline 537
**No public API for ticker lookup:** To find the company slug for a URL, check the search endpoint: `https://www.macrotrends.net/production/stocks/desktop/PRODUCTION/ticker_search_list.php?v=YYYYMMDD` — but the stock price iframe only needs
agent-workspace/domain-skills/manus/tasks.md
- Network accessline 7
- App home / new-task composer: `https://manus.im/app` - Network accessline 8
- Running or completed task: `https://manus.im/app/<taskId>` — `<taskId>` is a 22-char base62-ish opaque id (character set includes letters, digits, and `-`/`_`). The same id is the session id on the API side. - Network accessline 9
- Public share page: `https://manus.im/share/<taskId>` — only reachable after a `ShareSession` call (clicking *Share*). - Network accessline 16
[Credential-related source omitted] - Access to secretsline 16
[Credential-related source omitted] - Network accessline 34
status = js(r""" (async()=>{ const r = await fetch('https://api.manus.im/session.v1.SessionService/GetSession', { - Network accessline 35
(async()=>{ const r = await fetch('https://api.manus.im/session.v1.SessionService/GetSession', { method: 'POST', - Network accessline 36
const r = await fetch('https://api.manus.im/session.v1.SessionService/GetSession', { - Network accessline 53
browser-harness <<'PY' new_tab("https://manus.im/app") - Network accessline 54
new_tab("https://manus.im/app") - Network accessline 141
click(rect['x'], rect['y']) wait(0.5) # The share URL is https://manus.im/share/<same-taskId-as-/app/> - Network accessline 142
wait(0.5) # The share URL is https://manus.im/share/<same-taskId-as-/app/> print(page_info()['url'].replace('/app/', '/share/')) - Network accessline 143
# The share URL is https://manus.im/share/<same-taskId-as-/app/> - Network accessline 150
- Clicking **Share** in the top bar opens a floating popover (`div[role="dialog"]` inside a `[data-floating-ui-portal]`). It auto-runs `session.v1.SessionService/ShareSession` on first open and sets the task to **Public access** (the checkm - Network accessline 151
- Clicking **Share** a second time **toggles the popover closed** — don't double-click thinking it's a no-op. - **"Copy link" writes via `document.execCommand('copy')`, not `navigator.clipboard.writeText`.** If you need to capture the URL, - Network accessline 152
- **"Copy link" writes via `document.execCommand('copy')`, not `navigator.clipboard.writeText`.** If you need to capture the URL, hook both or just compute it: it's `https://manus.im/share/<taskId>` where the id comes straight from the URL - Network accessline 163
- **"Task completed" is the only DOM marker for terminal state.** Failed / cancelled tasks may surface different text — if you hit one, extend this skill. - **Cloud PC / Computer Use tasks** (when the monitor icon in the composer is toggled - Network accessline 165
- **Auth wall.** If `https://manus.im/app` redirects to `/login` or a Google OAuth page, stop and ask the user to sign in. Never type credentials from a screenshot.
agent-workspace/domain-skills/medium/article-hydration.md
- Network accessline 13
- Canonical: `https://medium.com/@<author>/<slug>-<id>` - Network accessline 14
- Publication: `https://<pub>.medium.com/<slug>-<id>` or `https://medium.com/<pub>/<slug>-<id>` - Network accessline 36
browser-harness <<'PY' new_tab("https://medium.com/@user/slug-abc123") - Network accessline 37
new_tab("https://medium.com/@user/slug-abc123")
agent-workspace/domain-skills/medium/scraping.md
- Network accessline 3
`https://medium.com` — blogging platform. Three access paths tested and validated: the undocumented `?format=json` endpoint (fastest for article + publication data), the undocumented GraphQL API (best for targeted metric lookups), and RSS f - Network accessline 34
""" sep = '&' if '?' in url else '?' req = urllib.request.Request( - Network accessline 35
sep = '&' if '?' in url else '?' req = urllib.request.Request( url + sep + 'format=json', - Network accessline 36
req = urllib.request.Request( - Network accessline 42
} ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 43
) with urllib.request.urlopen(req, timeout=20) as r: raw = r.read() - Network accessline 44
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 60
data = medium_json("https://medium.com/@karpathy/software-2-0-a64152b37c35") - Network accessline 68
creator_id = val['creatorId'] # "ac9d9a35533e" slug = val['uniqueSlug'] # "software-2-0-a64152b37c35" url = val['canonicalUrl'] # "https://medium.com/@ka - Network accessline 69
slug = val['uniqueSlug'] # "software-2-0-a64152b37c35" url = val['canonicalUrl'] # "https://medium.com/@karpathy/..." first_pub = val['firstPublishedAt'] # uni - Network accessline 70
url = val['canonicalUrl'] # "https://medium.com/@karpathy/..." - Network accessline 132
`POST https://medium.com/_/graphql` with a JSON body. No auth, no CSRF token required. - Network accessline 138
def gql(query): body = json.dumps({"query": query}).encode() req = urllib.request.Request( - Network accessline 139
body = json.dumps({"query": query}).encode() req = urllib.request.Request( "https://medium.com/_/graphql", - Network accessline 140
req = urllib.request.Request( - Network accessline 141
"https://medium.com/_/graphql", - Network accessline 149
method="POST", ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 150
) with urllib.request.urlopen(req, timeout=20) as r: raw = r.read() - Network accessline 151
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 279
# User feed (up to 10 latest posts) rss = http_get("https://medium.com/feed/@karpathy") - Network accessline 280
rss = http_get("https://medium.com/feed/@karpathy") - Network accessline 284
# posts[0]['creator'] -> "Andrej Karpathy" # posts[0]['tags'] -> ['programming', 'software-development', 'artificial-intelligence', 'future', 'machine-learning'] # posts[0]['link'] -> "https://karpathy.medium.com/software-2-0-a6415 - Network accessline 285
# posts[0]['tags'] -> ['programming', 'software-development', 'artificial-intelligence', 'future', 'machine-learning'] # posts[0]['link'] -> "https://karpathy.medium.com/software-2-0-a64152b37c35?source=rss-..." # posts[0]['body_htm - Network accessline 286
# posts[0]['link'] -> "https://karpathy.medium.com/software-2-0-a64152b37c35?source=rss-..." - Network accessline 289
# Publication feed (up to 10 latest posts) rss_pub = http_get("https://medium.com/feed/towards-data-science") - Network accessline 290
rss_pub = http_get("https://medium.com/feed/towards-data-science") - Network accessline 306
data = medium_json("https://medium.com/@karpathy?limit=10") - Network accessline 328
# Append as query params to the same profile URL to get next page next_url = ( f"https://medium.com/@{user['username']}" - Network accessline 329
next_url = ( f"https://medium.com/@{user['username']}" f"?limit={next_params['limit']}&to={next_params['to']}" - Network accessline 330
f"https://medium.com/@{user['username']}" - Network accessline 345
data = medium_json("https://medium.com/towards-data-science") - Network accessline 376
url = "https://medium.com/@karpathy/software-2-0-a64152b37c35" - Network accessline 390
- **`?format=json` works; profile stream API does not** — `https://medium.com/_/api/users/{id}/profile/stream` returns HTTP 403 for unauthenticated requests. Use `?format=json` on the profile URL instead.
agent-workspace/domain-skills/mercari/scraping.md
- Network accessline 11
- **Item pages are server-rendered.** `/us/item/<id>/` embeds an Apollo cache in `__NEXT_DATA__.props.pageProps.serverState`: `ItemDetail:<id>` (price, condition, status, ...) and `PublicUser:<seller id>` (username, rating, sales). Block 2 - Network accessline 12
- **Prices are cents** in both sources (`15000` = $150.00), and so are the URL price filters (`minPrice=10000`). - **Never follow tile links.** Result tiles link to `/us/item/<id>/?ref=search_results`, and the seller link carries `?tracking - Network accessline 13
- **Never follow tile links.** Result tiles link to `/us/item/<id>/?ref=search_results`, and the seller link carries `?tracking_ref_id=`; robots.txt disallows both. Both blocks build `https://www.mercari.com/us/item/<id>/` instead. - Network accessline 23
BASE = "https://www.mercari.com" - Possible obfuscationline 88
data = json.loads(base64.b64decode(b["body"]) if b.get("base64Encoded") else b["body"]) - Network accessline 166
'nintendo switch oled' batch 2: offset 47, 100 rows, 99 new, count=8889 199 rows of 8889 status: truncated_max_batches {"id": "m34776430562", "title": "Nintendo Switch OLED Console - White - As is. For Parts or Repair", "price": 150.0, "ori - Network accessline 167
199 rows of 8889 status: truncated_max_batches {"id": "m34776430562", "title": "Nintendo Switch OLED Console - White - As is. For Parts or Repair", "price": 150.0, "original_price": 170.0, "condition": "Poor", "status": "on_sale", "brand": - Network accessline 168
{"id": "m34776430562", "title": "Nintendo Switch OLED Console - White - As is. For Parts or Repair", "price": 150.0, "original_price": 170.0, "condition": "Poor", "status": "on_sale", "brand": "Nintendo", "category": "Consoles", "seller_id" - Network accessline 169
{"id": "m18850154865", "title": "Nintendo Switch OLED Modded – 1TB Storage + Accessories", "price": 480.0, "original_price": null, "condition": "Good", "status": "on_sale", "brand": "Nintendo", "category": "Consoles", "seller_id": 506215568 - Network accessline 187
BASE = "https://www.mercari.com" - Network accessline 312
ids: ['m34776430562', 'm18850154865', 'm15731011026'] {"id": "m34776430562", "title": "Nintendo Switch OLED Console - White - As is. For Parts or Repair", "price": 150.0, "original_price": 170.0, "condition": "Poor", "status": "on_sale", "b - Network accessline 313
{"id": "m34776430562", "title": "Nintendo Switch OLED Console - White - As is. For Parts or Repair", "price": 150.0, "original_price": 170.0, "condition": "Poor", "status": "on_sale", "brand": "Nintendo", "category": "Consoles", "buyer_ship - Network accessline 314
{"id": "m18850154865", "title": "Nintendo Switch OLED Modded – 1TB Storage + Accessories", "price": 480.0, "original_price": null, "condition": "Good", "status": "on_sale", "brand": "Nintendo", "category": "Consoles", "buyer_shipping": 0.0, - Network accessline 315
{"id": "m15731011026", "title": "Nintendo Switch OLED Model with Splatoon 2 Game", "price": 185.25, "original_price": 195.0, "condition": "Good", "status": "trading", "brand": "Nintendo", "category": "Consoles", "buyer_shipping": 0.0, "ship - Network accessline 347
| `category` | `categoryTitle` | leaf category, e.g. `Consoles` | | `seller_id` | `seller.id` | numeric; the search row has no seller name or rating, use block 2 for those | | `url` | built from `id` | `https://www.mercari.com/us/item/<id>/ - Network accessline 348
| `seller_id` | `seller.id` | numeric; the search row has no seller name or rating, use block 2 for those | | `url` | built from `id` | `https://www.mercari.com/us/item/<id>/`, no `?ref=` | | (batch) `count` | `count` | approximate total | - Network accessline 349
| `url` | built from `id` | `https://www.mercari.com/us/item/<id>/`, no `?ref=` | - Network accessline 364
| `seller.sales`, `seller.listed` | `.numSales`, `.numSellItems` | | | `seller.id_verified`, `seller.pro_seller` | `.kycVerificationStatus == "verified"`, `.isProSeller` | | | `seller.url` | built from username | `https://www.mercari.com/u/ - Network accessline 366
| `seller.url` | built from username | `https://www.mercari.com/u/<username>/` (no robots rule; not loaded here). The page's own seller link adds a disallowed `?tracking_ref_id=` |
agent-workspace/domain-skills/mermaid/render.md
- Network accessline 12
https://mermaid.live/edit#pako:<data> - Network accessline 25
raw = json.dumps(state).encode("utf-8") data = base64.urlsafe_b64encode(zlib.compress(raw, 9)).decode("ascii").rstrip("=") return "https://mermaid.live/edit#pako:" + data - Network accessline 27
return "https://mermaid.live/edit#pako:" + data
agent-workspace/domain-skills/metacritic/scraping.md
- Access to secretsline 14
[Credential-related source omitted] - Network accessline 16
def get_game_scores(slug): """slug = URL slug e.g. 'elden-ring', 'the-last-of-us'""" base = f"https://backend.metacritic.com" - Network accessline 17
"""slug = URL slug e.g. 'elden-ring', 'the-last-of-us'""" base = f"https://backend.metacritic.com" product = json.loads(http_get( - Network accessline 18
base = f"https://backend.metacritic.com" - Access to secretsline 21
[Credential-related source omitted] - Access to secretsline 25
[Credential-related source omitted] - Network accessline 60
url = "https://www.metacritic.com/game/elden-ring/" # or /movie/ or /tv/ - Network accessline 93
[Credential-related source omitted] - Access to secretsline 93
[Credential-related source omitted] - Network accessline 94
BASE = "https://backend.metacritic.com" - Access to secretsline 98
[Credential-related source omitted] - Access to secretsline 99
[Credential-related source omitted] - Access to secretsline 107
[Credential-related source omitted] - Access to secretsline 108
[Credential-related source omitted] - Access to secretsline 116
[Credential-related source omitted] - Access to secretsline 117
[Credential-related source omitted] - Access to secretsline 141
[Credential-related source omitted] - Network accessline 143
def _fetch(url): h = {"User-Agent": "Mozilla/5.0", "Accept-Encoding": "gzip"} with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=15) as r: - Network accessline 144
h = {"User-Agent": "Mozilla/5.0", "Accept-Encoding": "gzip"} with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=15) as r: data = r.read() - Network accessline 145
with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=15) as r: - Network accessline 150
def batch_game_scores(slugs, workers=5): """Fetch critic+user scores for multiple game slugs in parallel.""" BASE = "https://backend.metacritic.com" - Network accessline 151
[Credential-related source omitted] - Network accessline 152
BASE = "https://backend.metacritic.com" - Access to secretsline 153
[Credential-related source omitted] - Access to secretsline 182
[Credential-related source omitted] - Network accessline 191
type_param = f"&mcoTypeId={type_map[media_type]}" if media_type else "&mcoTypeId=1%2C2%2C3%2C13" url = ( f"https://backend.metacritic.com/finder/metacritic/search/{q}/web" - Network accessline 192
url = ( f"https://backend.metacritic.com/finder/metacritic/search/{q}/web" f"?offset=0&limit={limit}&sortBy=META_SCORE&sortDirection=DESC" - Network accessline 193
f"https://backend.metacritic.com/finder/metacritic/search/{q}/web" - Access to secretsline 196
[Credential-related source omitted] - Access to secretsline 223
[Credential-related source omitted] - Network accessline 232
[Credential-related source omitted] - Network accessline 233
[Credential-related source omitted] - Network accessline 234
[Credential-related source omitted] - Access to secretsline 234
[Credential-related source omitted] - Access to secretsline 268
[Credential-related source omitted] - Network accessline 270
def game_platforms(slug): url = ( f"https://backend.metacritic.com/games/metacritic/{slug}/web" - Network accessline 271
[Credential-related source omitted] - Network accessline 272
f"https://backend.metacritic.com/games/metacritic/{slug}/web" - Access to secretsline 273
[Credential-related source omitted] - Access to secretsline 302
[Credential-related source omitted] - Network accessline 305
"""sort: 'date' | 'score' | 'publication'""" url = ( f"https://backend.metacritic.com/reviews/metacritic/critic/{media}/{slug}/web" - Network accessline 306
url = ( f"https://backend.metacritic.com/reviews/metacritic/critic/{media}/{slug}/web" f"?offset={offset}&limit={limit}&sort={sort}" - Network accessline 307
f"https://backend.metacritic.com/reviews/metacritic/critic/{media}/{slug}/web" - Access to secretsline 309
[Credential-related source omitted] - Access to secretsline 336
[Credential-related source omitted] - Network accessline 339
"""order_by: 'score' | 'date' | 'helpfulness'""" url = ( f"https://backend.metacritic.com/reviews/metacritic/user/{media}/{slug}/web" - Network accessline 340
url = ( f"https://backend.metacritic.com/reviews/metacritic/user/{media}/{slug}/web" f"?offset={offset}&limit={limit}&orderBy={order_by}&orderType={order_type}" - Network accessline 341
f"https://backend.metacritic.com/reviews/metacritic/user/{media}/{slug}/web" - Access to secretsline 343
[Credential-related source omitted] - Network accessline 369
url = "https://www.metacritic.com/game/the-last-of-us/" - Network accessline 437
slug_from_url("https://www.metacritic.com/game/the-last-of-us/") # "the-last-of-us"
agent-workspace/domain-skills/microsoft-365/domain-setup.md
agent-workspace/domain-skills/musicbrainz/scraping.md
- Network accessline 3
`https://musicbrainz.org` — open music encyclopedia with a fully free JSON API. - Network accessline 21
data = json.loads(http_get("https://musicbrainz.org/ws/2/artist/?query=queen&fmt=json&limit=5", headers=UA)) - Network accessline 57
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/artist/?query=queen&fmt=json&limit=5", - Network accessline 58
"https://musicbrainz.org/ws/2/artist/?query=queen&fmt=json&limit=5", - Network accessline 76
# inc= parameters stack with + between them resp = json.loads(http_get( "https://musicbrainz.org/ws/2/artist/0383dadf-2a4e-4d10-a46a-e9e041da8eb3" - Network accessline 77
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/artist/0383dadf-2a4e-4d10-a46a-e9e041da8eb3" "?inc=releases+tags+ratings+release-groups&fmt=json", - Network accessline 78
"https://musicbrainz.org/ws/2/artist/0383dadf-2a4e-4d10-a46a-e9e041da8eb3" - Network accessline 109
# Browse API: uses 'artist' param (not 'query') — response key is 'release-count' not 'count' resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release/" - Network accessline 110
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release/" "?artist=0383dadf-2a4e-4d10-a46a-e9e041da8eb3&fmt=json&limit=25&offset=0", - Network accessline 111
"https://musicbrainz.org/ws/2/release/" - Network accessline 128
# Search by title resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release/?query=dark+side+of+the+moon&fmt=json&limit=5", - Network accessline 129
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release/?query=dark+side+of+the+moon&fmt=json&limit=5", headers=UA - Network accessline 130
"https://musicbrainz.org/ws/2/release/?query=dark+side+of+the+moon&fmt=json&limit=5", - Network accessline 135
# Full release with track list, artists, and labels release = json.loads(http_get( "https://musicbrainz.org/ws/2/release/b84ee12a-09ef-421b-82de-0441a926375b" - Network accessline 136
release = json.loads(http_get( "https://musicbrainz.org/ws/2/release/b84ee12a-09ef-421b-82de-0441a926375b" "?inc=artists+recordings+labels+release-groups&fmt=json", - Network accessline 137
"https://musicbrainz.org/ws/2/release/b84ee12a-09ef-421b-82de-0441a926375b" - Network accessline 176
# Use Lucene field syntax to filter by artist resp = json.loads(http_get( "https://musicbrainz.org/ws/2/recording/" - Network accessline 177
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/recording/" "?query=bohemian+rhapsody+AND+artist:queen&fmt=json&limit=5", - Network accessline 178
"https://musicbrainz.org/ws/2/recording/" - Network accessline 195
# Use release-group endpoint to avoid getting every regional edition resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release-group/" - Network accessline 196
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release-group/" "?query=release-group:\"A+Night+at+the+Opera\"+AND+artist:queen&fmt=json&limit=5", - Network accessline 197
"https://musicbrainz.org/ws/2/release-group/" - Network accessline 206
# Browse release-groups for an artist resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release-group/" - Network accessline 207
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release-group/" "?artist=0383dadf-2a4e-4d10-a46a-e9e041da8eb3&fmt=json&limit=25", - Network accessline 208
"https://musicbrainz.org/ws/2/release-group/" - Network accessline 220
# Label search resp = json.loads(http_get( "https://musicbrainz.org/ws/2/label/?query=EMI&fmt=json&limit=3", - Network accessline 221
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/label/?query=EMI&fmt=json&limit=3", headers=UA - Network accessline 222
"https://musicbrainz.org/ws/2/label/?query=EMI&fmt=json&limit=3", - Network accessline 229
# Work (song composition — author-level, not performance-level) resp = json.loads(http_get( "https://musicbrainz.org/ws/2/work/?query=bohemian+rhapsody&fmt=json&limit=3", - Network accessline 230
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/work/?query=bohemian+rhapsody&fmt=json&limit=3", headers=UA - Network accessline 231
"https://musicbrainz.org/ws/2/work/?query=bohemian+rhapsody&fmt=json&limit=3", - Network accessline 249
try: resp = json.loads(http_get( f"https://coverartarchive.org/release/{release_mbid}", - Network accessline 250
resp = json.loads(http_get( f"https://coverartarchive.org/release/{release_mbid}", headers=UA - Network accessline 251
f"https://coverartarchive.org/release/{release_mbid}", - Network accessline 270
url = get_cover_art("b84ee12a-09ef-421b-82de-0441a926375b") # http://coverartarchive.org/release/b84ee12a.../1611507818-500.jpg - Network accessline 271
# http://coverartarchive.org/release/b84ee12a.../1611507818-500.jpg - Network accessline 273
# Full images response structure resp = json.loads(http_get( "https://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b", - Network accessline 274
resp = json.loads(http_get( "https://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b", headers=UA - Network accessline 275
"https://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b", - Network accessline 291
# Field search: artist:, type:, country:, tag:, release:, date: resp = json.loads(http_get( "https://musicbrainz.org/ws/2/artist/" - Network accessline 292
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/artist/" "?query=artist:queen+AND+type:group+AND+country:GB&fmt=json&limit=5", - Network accessline 293
"https://musicbrainz.org/ws/2/artist/" - Network accessline 299
# Phrase search with quotes resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release/" - Network accessline 300
resp = json.loads(http_get( "https://musicbrainz.org/ws/2/release/" '?query=release:"A+Night+at+the+Opera"+AND+artist:queen&fmt=json&limit=5', - Network accessline 301
"https://musicbrainz.org/ws/2/release/" - Network accessline 320
def fetch_artist(mbid): resp = json.loads(http_get( f"https://musicbrainz.org/ws/2/artist/{mbid}?inc=tags&fmt=json", - Network accessline 321
resp = json.loads(http_get( f"https://musicbrainz.org/ws/2/artist/{mbid}?inc=tags&fmt=json", headers=UA - Network accessline 322
f"https://musicbrainz.org/ws/2/artist/{mbid}?inc=tags&fmt=json", - Network accessline 353
while total is None or offset < total: resp = json.loads(http_get( f"https://musicbrainz.org/ws/2/release/" - Network accessline 354
resp = json.loads(http_get( f"https://musicbrainz.org/ws/2/release/" f"?artist={artist_mbid}&fmt=json&limit={page_size}&offset={offset}", - Network accessline 355
f"https://musicbrainz.org/ws/2/release/" - Network accessline 433
| Resource | URL | |---|---| | Artist search | `https://musicbrainz.org/ws/2/artist/?query={q}&fmt=json&limit=5` | - Network accessline 434
|---|---| | Artist search | `https://musicbrainz.org/ws/2/artist/?query={q}&fmt=json&limit=5` | | Artist by MBID | `https://musicbrainz.org/ws/2/artist/{mbid}?inc=tags+ratings&fmt=json` | - Network accessline 435
| Artist search | `https://musicbrainz.org/ws/2/artist/?query={q}&fmt=json&limit=5` | - Network accessline 436
| Artist by MBID | `https://musicbrainz.org/ws/2/artist/{mbid}?inc=tags+ratings&fmt=json` | - Network accessline 437
| Browse releases by artist | `https://musicbrainz.org/ws/2/release/?artist={mbid}&fmt=json&limit=25&offset=0` | - Network accessline 438
| Release search | `https://musicbrainz.org/ws/2/release/?query={q}&fmt=json&limit=5` | - Network accessline 439
| Release by MBID | `https://musicbrainz.org/ws/2/release/{mbid}?inc=artists+recordings+labels&fmt=json` | - Network accessline 440
| Release-group browse | `https://musicbrainz.org/ws/2/release-group/?artist={mbid}&fmt=json&limit=25` | - Network accessline 441
| Recording search | `https://musicbrainz.org/ws/2/recording/?query={q}&fmt=json&limit=5` | - Network accessline 442
| Label search | `https://musicbrainz.org/ws/2/label/?query={q}&fmt=json&limit=5` | - Network accessline 443
| Work search | `https://musicbrainz.org/ws/2/work/?query={q}&fmt=json&limit=5` | - Network accessline 444
| Cover art | `https://coverartarchive.org/release/{release-mbid}` | - Network accessline 446
MusicBrainz entity browser URL (human-readable): `https://musicbrainz.org/artist/{mbid}` (replace `artist` with `release`, `recording`, etc.)
agent-workspace/domain-skills/namecheap/advanced-dns.md
- Network accessline 5
- Domain DNS: `https://ap.www.namecheap.com/domains/domaincontrolpanel/<domain>/advancedns`.
agent-workspace/domain-skills/nasa/scraping.md
- Network accessline 3
`https://api.nasa.gov` — open NASA data APIs. **Never use the browser.** All endpoints return JSON via `http_get`. DEMO_KEY works for low-volume use; register for a free personal key at https://api.nasa.gov/ to raise limits. - Network accessline 13
[Credential-related source omitted] - Network accessline 14
[Credential-related source omitted] - Access to secretsline 14
[Credential-related source omitted] - Network accessline 43
[Credential-related source omitted] - Access to secretsline 43
[Credential-related source omitted] - Network accessline 49
print(apod.get('copyright')) # None if public domain # Confirmed output (2026-04-18): # url: https://apod.nasa.gov/apod/image/2604/PanstarrsPlanetsPerrotLab1024.jpg - Network accessline 50
# Confirmed output (2026-04-18): # url: https://apod.nasa.gov/apod/image/2604/PanstarrsPlanetsPerrotLab1024.jpg # hdurl: https://apod.nasa.gov/apod/image/2604/PanstarrsPlanetsPerrot.jpg - Network accessline 51
# url: https://apod.nasa.gov/apod/image/2604/PanstarrsPlanetsPerrotLab1024.jpg - Network accessline 52
# hdurl: https://apod.nasa.gov/apod/image/2604/PanstarrsPlanetsPerrot.jpg - Network accessline 62
apods = json.loads(http_get( "https://api.nasa.gov/planetary/apod" - Network accessline 63
"https://api.nasa.gov/planetary/apod" - Access to secretsline 64
[Credential-related source omitted] - Network accessline 87
[Credential-related source omitted] - Network accessline 88
[Credential-related source omitted] - Access to secretsline 88
[Credential-related source omitted] - Network accessline 101
data = json.loads(http_get( "https://api.nasa.gov/neo/rest/v1/feed" - Network accessline 102
"https://api.nasa.gov/neo/rest/v1/feed" - Access to secretsline 103
[Credential-related source omitted] - Network accessline 135
[Credential-related source omitted] - Network accessline 136
[Credential-related source omitted] - Network accessline 137
[Credential-related source omitted] - Access to secretsline 137
[Credential-related source omitted] - Network accessline 150
# sol = Martian solar day since landing data = json.loads(http_get( "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos" - Network accessline 151
[Credential-related source omitted] - Network accessline 152
"https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos" - Access to secretsline 153
[Credential-related source omitted] - Network accessline 166
# Filter by camera data = json.loads(http_get( "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos" - Network accessline 167
[Credential-related source omitted] - Network accessline 168
"https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos" - Access to secretsline 169
[Credential-related source omitted] - Network accessline 177
data = json.loads(http_get( "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/latest_photos" - Network accessline 178
"https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/latest_photos" - Access to secretsline 179
[Credential-related source omitted] - Access to secretsline 188
[Credential-related source omitted] - Network accessline 194
# Latest available images (natural color) images = json.loads(http_get("https://epic.gsfc.nasa.gov/api/natural")) - Network accessline 195
images = json.loads(http_get("https://epic.gsfc.nasa.gov/api/natural")) - Network accessline 205
date_str = img['date'].split(' ')[0] # '2026-04-16' year, month, day = date_str.split('-') png_url = f"https://epic.gsfc.nasa.gov/archive/natural/{year}/{month}/{day}/png/{img['image']}.png" - Network accessline 206
year, month, day = date_str.split('-') png_url = f"https://epic.gsfc.nasa.gov/archive/natural/{year}/{month}/{day}/png/{img['image']}.png" jpg_thumb = f"https://epic.gsfc.nasa.gov/archive/natural/{year}/{month}/{day}/thumbs/{img['image']}.j - Network accessline 207
png_url = f"https://epic.gsfc.nasa.gov/archive/natural/{year}/{month}/{day}/png/{img['image']}.png" - Network accessline 208
jpg_thumb = f"https://epic.gsfc.nasa.gov/archive/natural/{year}/{month}/{day}/thumbs/{img['image']}.jpg" - Network accessline 210
# Confirmed: https://epic.gsfc.nasa.gov/archive/natural/2026/04/16/png/epic_1b_20260416162050.png - Network accessline 214
# Images for a specific date images = json.loads(http_get("https://epic.gsfc.nasa.gov/api/natural/date/2024-01-15")) - Network accessline 215
images = json.loads(http_get("https://epic.gsfc.nasa.gov/api/natural/date/2024-01-15")) - Network accessline 218
# Enhanced (color-corrected) images — same API, different path enhanced = json.loads(http_get("https://epic.gsfc.nasa.gov/api/enhanced/date/2024-01-15")) - Network accessline 219
enhanced = json.loads(http_get("https://epic.gsfc.nasa.gov/api/enhanced/date/2024-01-15")) - Network accessline 222
date_str = img['date'].split(' ')[0] year, month, day = date_str.split('-') url = f"https://epic.gsfc.nasa.gov/archive/enhanced/{year}/{month}/{day}/png/{img['image']}.png" - Network accessline 223
year, month, day = date_str.split('-') url = f"https://epic.gsfc.nasa.gov/archive/enhanced/{year}/{month}/{day}/png/{img['image']}.png" # e.g. .../archive/enhanced/2024/01/15/png/epic_RGB_20240115005515.png - Network accessline 224
url = f"https://epic.gsfc.nasa.gov/archive/enhanced/{year}/{month}/{day}/png/{img['image']}.png" - Network accessline 227
# All available dates all_dates = json.loads(http_get("https://epic.gsfc.nasa.gov/api/natural/all")) - Network accessline 228
all_dates = json.loads(http_get("https://epic.gsfc.nasa.gov/api/natural/all")) - Network accessline 242
# Short-period planets with known radii planets = json.loads(http_get( "https://exoplanetarchive.ipac.caltech.edu/TAP/sync" - Network accessline 243
planets = json.loads(http_get( "https://exoplanetarchive.ipac.caltech.edu/TAP/sync" "?query=select+pl_name,hostname,pl_orbper+from+ps+where+pl_orbper+%3C+10" - Network accessline 244
"https://exoplanetarchive.ipac.caltech.edu/TAP/sync" - Network accessline 254
# Use 'pscomppars' for one row per planet (composite best-estimate params) planets = json.loads(http_get( "https://exoplanetarchive.ipac.caltech.edu/TAP/sync" - Network accessline 255
planets = json.loads(http_get( "https://exoplanetarchive.ipac.caltech.edu/TAP/sync" "?query=select+pl_name,hostname,disc_year,discoverymethod,pl_orbper,pl_rade,pl_masse,pl_eqt,sy_dist" - Network accessline 256
"https://exoplanetarchive.ipac.caltech.edu/TAP/sync" - Network accessline 282
[Credential-related source omitted] - Network accessline 283
[Credential-related source omitted] - Network accessline 284
[Credential-related source omitted] - Access to secretsline 284
[Credential-related source omitted] - Network accessline 286
[Credential-related source omitted] - Network accessline 287
[Credential-related source omitted] - Network accessline 288
[Credential-related source omitted] - Access to secretsline 288
[Credential-related source omitted] - Network accessline 289
[Credential-related source omitted] - Access to secretsline 289
[Credential-related source omitted] - Network accessline 290
[Credential-related source omitted] - Access to secretsline 290
[Credential-related source omitted] - Access to secretsline 291
[Credential-related source omitted] - Network accessline 292
[Credential-related source omitted] - Access to secretsline 292
[Credential-related source omitted] - Network accessline 296
| Endpoint | URL | |---|---| | Latest natural images | `https://epic.gsfc.nasa.gov/api/natural` | - Network accessline 297
|---|---| | Latest natural images | `https://epic.gsfc.nasa.gov/api/natural` | | Natural by date | `https://epic.gsfc.nasa.gov/api/natural/date/YYYY-MM-DD` | - Network accessline 298
| Latest natural images | `https://epic.gsfc.nasa.gov/api/natural` | - Network accessline 299
| Natural by date | `https://epic.gsfc.nasa.gov/api/natural/date/YYYY-MM-DD` | - Network accessline 300
| Enhanced latest | `https://epic.gsfc.nasa.gov/api/enhanced` | - Network accessline 301
| Enhanced by date | `https://epic.gsfc.nasa.gov/api/enhanced/date/YYYY-MM-DD` | - Network accessline 302
| All available dates | `https://epic.gsfc.nasa.gov/api/natural/all` | - Network accessline 303
| PNG image | `https://epic.gsfc.nasa.gov/archive/natural/YYYY/MM/DD/png/{image}.png` | - Network accessline 304
| Thumbnail (JPEG) | `https://epic.gsfc.nasa.gov/archive/natural/YYYY/MM/DD/thumbs/{image}.jpg` | - Network accessline 305
| Enhanced PNG | `https://epic.gsfc.nasa.gov/archive/enhanced/YYYY/MM/DD/png/{image}.png` | - Network accessline 310
https://exoplanetarchive.ipac.caltech.edu/TAP/sync?query=<ADQL>&format=json&maxrec=<N> - Network accessline 315
- **DEMO_KEY limit is effectively 10/hour per IP, not 30** — The `X-Ratelimit-Limit` header shows `10` in practice. When the daily budget (~50 req) is exhausted, the `retry-after` header is set to ~80,000 seconds (about 22 hours). Register
agent-workspace/domain-skills/news-aggregation/multi-source.md
- Network accessline 11
| Source | Feed URL | Format | Items | Fetch time | |--------|----------|--------|-------|------------| | TechCrunch | `https://techcrunch.com/feed/` | RSS 2.0 | 20 | ~0.08s | - Network accessline 12
|--------|----------|--------|-------|------------| | TechCrunch | `https://techcrunch.com/feed/` | RSS 2.0 | 20 | ~0.08s | | Ars Technica | `https://feeds.arstechnica.com/arstechnica/index` | RSS 2.0 | 20 | ~0.10s | - Network accessline 13
| TechCrunch | `https://techcrunch.com/feed/` | RSS 2.0 | 20 | ~0.08s | - Network accessline 14
| Ars Technica | `https://feeds.arstechnica.com/arstechnica/index` | RSS 2.0 | 20 | ~0.10s | - Network accessline 15
| BBC News | `http://feeds.bbci.co.uk/news/rss.xml` | RSS 2.0 | 37 | ~0.23s | - Network accessline 16
| The Guardian (World) | `https://www.theguardian.com/world/rss` | RSS 2.0 | 45 | ~0.11s | - Network accessline 17
| The Guardian (Tech) | `https://www.theguardian.com/technology/rss` | RSS 2.0 | 32 | ~0.25s | - Network accessline 18
| Wired | `https://www.wired.com/feed/rss` | RSS 2.0 | 50 | ~0.10s | - Network accessline 19
| NPR Top Stories | `https://feeds.npr.org/1001/rss.xml` | RSS 2.0 | 10 | ~0.14s | - Network accessline 20
| Hacker News | `https://news.ycombinator.com/rss` | RSS 2.0 | 30 | ~0.16s | - Network accessline 21
| CNN Top Stories | `http://rss.cnn.com/rss/cnn_topstories.rss` | RSS 2.0 | 69 | ~0.25s | - Network accessline 22
| NYT Homepage | `https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml` | RSS 2.0 | 23 | ~0.12s | - Network accessline 23
| The Verge | `https://www.theverge.com/rss/index.xml` | **Atom** | 10 | ~0.15s | - Network accessline 33
RSS_FEEDS = [ ("TechCrunch", "https://techcrunch.com/feed/"), - Network accessline 34
("TechCrunch", "https://techcrunch.com/feed/"), - Network accessline 35
("Ars Technica", "https://feeds.arstechnica.com/arstechnica/index"), - Network accessline 36
("BBC News", "http://feeds.bbci.co.uk/news/rss.xml"), - Network accessline 37
("Guardian World", "https://www.theguardian.com/world/rss"), - Network accessline 38
("Wired", "https://www.wired.com/feed/rss"), - Network accessline 39
("NPR", "https://feeds.npr.org/1001/rss.xml"), - Network accessline 40
("Wired", "https://www.wired.com/feed/rss"), - Network accessline 67
NS = {'atom': 'http://www.w3.org/2005/Atom'} - Network accessline 69
xml_data = http_get("https://www.theverge.com/rss/index.xml") - Network accessline 79
Do NOT use `root.findall('.//{http://www.w3.org/2005/Atom}entry')` with a bare namespace — the explicit `NS` dict approach above is cleaner. Do NOT call `.text` on a `find()` result without checking for `None` first (the naive RSS path hit - Network accessline 96
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"} html = http_get("https://www.nytimes.com", headers=headers) # 1.1MB, works - Network accessline 97
html = http_get("https://www.nytimes.com", headers=headers) # 1.1MB, works - Network accessline 98
html = http_get("https://news.ycombinator.com") # 34KB, works without UA - Network accessline 103
import re html = http_get("https://news.ycombinator.com") - Network accessline 104
html = http_get("https://news.ycombinator.com") - Network accessline 116
goto_url("https://www.bbc.com/news") - Network accessline 149
goto_url("https://techcrunch.com") - Network accessline 172
goto_url("https://www.reuters.com") - Network accessline 191
YES → http_get + XML parse (fastest, ~0.1s per feed) - RSS 2.0: root.findall('.//item') - Atom: root.findall('.//atom:entry', {'atom': 'http://www.w3.org/2005/Atom'}) - Network accessline 192
- RSS 2.0: root.findall('.//item') - Atom: root.findall('.//atom:entry', {'atom': 'http://www.w3.org/2005/Atom'}) NO → Does http_get return valid HTML (not 403/401/JS shell)? - Network accessline 193
- Atom: root.findall('.//atom:entry', {'atom': 'http://www.w3.org/2005/Atom'})
agent-workspace/domain-skills/open-library/scraping.md
- Network accessline 3
`https://openlibrary.org` — Internet Archive's free book catalog. All endpoints are public JSON APIs — no auth, no browser, no scraping required. - Network accessline 13
# Search by title results = json.loads(http_get("https://openlibrary.org/search.json?q=dune&limit=5")) - Network accessline 14
results = json.loads(http_get("https://openlibrary.org/search.json?q=dune&limit=5")) - Network accessline 32
# Free-text search r = json.loads(http_get("https://openlibrary.org/search.json?q=dune+frank+herbert&limit=5")) - Network accessline 33
r = json.loads(http_get("https://openlibrary.org/search.json?q=dune+frank+herbert&limit=5")) - Network accessline 35
# Author search r = json.loads(http_get( "https://openlibrary.org/search.json?author=tolkien&limit=5" - Network accessline 36
r = json.loads(http_get( "https://openlibrary.org/search.json?author=tolkien&limit=5" "&fields=title,author_name,first_publish_year,isbn" - Network accessline 37
"https://openlibrary.org/search.json?author=tolkien&limit=5" - Network accessline 42
# Title + author combined r = json.loads(http_get( "https://openlibrary.org/search.json?title=dune&author=frank+herbert&limit=3" - Network accessline 43
r = json.loads(http_get( "https://openlibrary.org/search.json?title=dune&author=frank+herbert&limit=3" "&fields=title,author_name,edition_count,first_publish_year" - Network accessline 44
"https://openlibrary.org/search.json?title=dune&author=frank+herbert&limit=3" - Network accessline 52
# ISBN lookup (returns 0–2 results for the same work) r = json.loads(http_get("https://openlibrary.org/search.json?isbn=9780743273565")) - Network accessline 53
r = json.loads(http_get("https://openlibrary.org/search.json?isbn=9780743273565")) - Network accessline 121
def lookup_isbn(isbn): url = f"https://openlibrary.org/search.json?isbn={isbn}&fields=title,author_name,first_publish_year,key" - Network accessline 122
url = f"https://openlibrary.org/search.json?isbn={isbn}&fields=title,author_name,first_publish_year,key" - Network accessline 148
work_id = 'OL893415W' # from search doc['key'] = '/works/OL893415W' work = json.loads(http_get(f"https://openlibrary.org/works/{work_id}.json")) - Network accessline 149
work = json.loads(http_get(f"https://openlibrary.org/works/{work_id}.json")) - Network accessline 177
editions_resp = json.loads(http_get( f"https://openlibrary.org/works/{work_id}/editions.json?limit=10&offset=0" - Network accessline 178
f"https://openlibrary.org/works/{work_id}/editions.json?limit=10&offset=0" - Network accessline 211
edition_id = 'OL7353617M' # from editions list e['key'] or cover_edition_key in search edition = json.loads(http_get(f"https://openlibrary.org/books/{edition_id}.json")) - Network accessline 212
edition = json.loads(http_get(f"https://openlibrary.org/books/{edition_id}.json")) - Network accessline 232
# jscmd=data: cleaned up dict with cover URLs pre-built r = json.loads(http_get( "https://openlibrary.org/api/books" - Network accessline 233
r = json.loads(http_get( "https://openlibrary.org/api/books" "?bibkeys=ISBN:9780743273565,ISBN:9780451524935" - Network accessline 234
"https://openlibrary.org/api/books" - Network accessline 244
# book['publishers'] == [{'name': 'Independently Published'}] # book['number_of_pages'] == 208 # book['url'] == 'http://openlibrary.org/books/OL46773254M/The_Great_Gatsby' - Network accessline 245
# book['number_of_pages'] == 208 # book['url'] == 'http://openlibrary.org/books/OL46773254M/The_Great_Gatsby' # book['key'] == '/books/OL46773254M' - Network accessline 246
# book['url'] == 'http://openlibrary.org/books/OL46773254M/The_Great_Gatsby' - Network accessline 253
# jscmd=details: raw edition JSON + extra fields r2 = json.loads(http_get( "https://openlibrary.org/api/books" - Network accessline 254
r2 = json.loads(http_get( "https://openlibrary.org/api/books" "?bibkeys=ISBN:9780743273565&format=json&jscmd=details" - Network accessline 255
"https://openlibrary.org/api/books" - Network accessline 258
item = r2['ISBN:9780743273565'] # item['bib_key'] == 'ISBN:9780743273565' # item['info_url'] == 'http://openlibrary.org/books/OL...' - Network accessline 259
# item['bib_key'] == 'ISBN:9780743273565' # item['info_url'] == 'http://openlibrary.org/books/OL...' # item['preview'] == 'noview' | 'restricted' | 'full' - Network accessline 260
# item['info_url'] == 'http://openlibrary.org/books/OL...' - Network accessline 261
# item['preview'] == 'noview' | 'restricted' | 'full' # item['preview_url'] == URL to read on OL or IA # item['thumbnail_url']== 'https://covers.openlibrary.org/b/id/14314120-S.jpg' - Network accessline 262
# item['preview_url'] == URL to read on OL or IA # item['thumbnail_url']== 'https://covers.openlibrary.org/b/id/14314120-S.jpg' # item['details'] → raw edition JSON (same as /books/OL...M.json) - Network accessline 263
# item['thumbnail_url']== 'https://covers.openlibrary.org/b/id/14314120-S.jpg' - Network accessline 277
# Lookup by known author key author = json.loads(http_get("https://openlibrary.org/authors/OL26320A.json")) - Network accessline 278
author = json.loads(http_get("https://openlibrary.org/authors/OL26320A.json")) - Network accessline 294
# Author works (paginated) works = json.loads(http_get("https://openlibrary.org/authors/OL26320A/works.json?limit=5")) - Network accessline 295
works = json.loads(http_get("https://openlibrary.org/authors/OL26320A/works.json?limit=5")) - Network accessline 304
r = json.loads(http_get("https://openlibrary.org/search/authors.json?q=tolkien")) - Network accessline 328
# Book covers — three key types: https://covers.openlibrary.org/b/id/{cover_id}-{size}.jpg # by cover ID (most reliable) - Network accessline 329
https://covers.openlibrary.org/b/id/{cover_id}-{size}.jpg # by cover ID (most reliable) - Network accessline 330
https://covers.openlibrary.org/b/isbn/{isbn}-{size}.jpg # by ISBN - Network accessline 331
https://covers.openlibrary.org/b/olid/{edition_id}-{size}.jpg # by edition OLID (unreliable — see gotchas) - Network accessline 333
# Author photos: https://covers.openlibrary.org/a/id/{photo_id}-{size}.jpg - Network accessline 334
https://covers.openlibrary.org/a/id/{photo_id}-{size}.jpg - Network accessline 342
def get_cover_bytes(cover_id: int, size: str = 'M') -> bytes | None: """Fetch cover image bytes. Returns None if no cover (43-byte GIF placeholder).""" url = f"https://covers.openlibrary.org/b/id/{cover_id}-{size}.jpg" - Network accessline 343
"""Fetch cover image bytes. Returns None if no cover (43-byte GIF placeholder).""" url = f"https://covers.openlibrary.org/b/id/{cover_id}-{size}.jpg" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 344
url = f"https://covers.openlibrary.org/b/id/{cover_id}-{size}.jpg" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=15) as resp: - Network accessline 345
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 346
with urllib.request.urlopen(req, timeout=15) as resp: - Network accessline 350
# Or just get the URL for embedding: def cover_url(cover_id: int, size: str = 'M') -> str: return f"https://covers.openlibrary.org/b/id/{cover_id}-{size}.jpg" - Network accessline 352
return f"https://covers.openlibrary.org/b/id/{cover_id}-{size}.jpg" - Network accessline 355
from helpers import http_get import json work = json.loads(http_get("https://openlibrary.org/works/OL893415W.json")) - Network accessline 356
import json work = json.loads(http_get("https://openlibrary.org/works/OL893415W.json")) if work.get('covers'): - Network accessline 357
work = json.loads(http_get("https://openlibrary.org/works/OL893415W.json")) - Network accessline 365
# Medium-size cover by ISBN: url = f"https://covers.openlibrary.org/b/isbn/{isbn}-M.jpg" - Network accessline 366
url = f"https://covers.openlibrary.org/b/isbn/{isbn}-M.jpg" - Network accessline 367
# Redirects to Internet Archive CDN, content-type: image/jpeg # Use ?default=false to get 404 instead of 1×1 GIF placeholder for missing covers url_safe = f"https://covers.openlibrary.org/b/isbn/{isbn}-M.jpg?default=false" - Network accessline 369
url_safe = f"https://covers.openlibrary.org/b/isbn/{isbn}-M.jpg?default=false" - Network accessline 380
# Subject slugs: lowercase, underscores for spaces r = json.loads(http_get("https://openlibrary.org/subjects/science_fiction.json?limit=5")) - Network accessline 381
r = json.loads(http_get("https://openlibrary.org/subjects/science_fiction.json?limit=5")) - Network accessline 398
# Pagination: &offset=N # Place subject: r2 = json.loads(http_get("https://openlibrary.org/subjects/place:london.json?limit=5")) - Network accessline 399
# Place subject: r2 = json.loads(http_get("https://openlibrary.org/subjects/place:london.json?limit=5")) # r2['subject_type'] == 'place', r2['work_count'] == 23927 - Network accessline 400
r2 = json.loads(http_get("https://openlibrary.org/subjects/place:london.json?limit=5")) - Network accessline 403
# Person subject: # https://openlibrary.org/subjects/person:napoleon.json?limit=5 - Network accessline 404
# https://openlibrary.org/subjects/person:napoleon.json?limit=5 - Network accessline 406
# https://openlibrary.org/subjects/time:middle_ages.json?limit=5 - Network accessline 408
# Combine with ebooks=true to filter to only freely readable books: r3 = json.loads(http_get("https://openlibrary.org/subjects/science_fiction.json?limit=5&ebooks=true")) - Network accessline 409
r3 = json.loads(http_get("https://openlibrary.org/subjects/science_fiction.json?limit=5&ebooks=true")) - Network accessline 421
for period in ['daily', 'weekly', 'monthly']: r = json.loads(http_get(f"https://openlibrary.org/trending/{period}.json?limit=10")) - Network accessline 422
r = json.loads(http_get(f"https://openlibrary.org/trending/{period}.json?limit=10")) - Network accessline 464
resp = json.loads(http_get("https://openlibrary.org/works/OL893415W/editions.json?limit=50")) - Network accessline 465
while 'next' in resp.get('links', {}): resp = json.loads(http_get("https://openlibrary.org" + resp['links']['next'])) # process resp['entries'] - Network accessline 466
resp = json.loads(http_get("https://openlibrary.org" + resp['links']['next']))
agent-workspace/domain-skills/openalex/scraping.md
- Network accessline 3
`https://api.openalex.org` — open academic knowledge graph covering 260M+ works, 90M+ authors, 110K+ institutions. **Never use the browser for OpenAlex.** The entire API is JSON over HTTPS, completely free, no API key required. Add `mailto= - Network accessline 13
data = json.loads(http_get( "https://api.openalex.org/works?search=transformer+attention&per-page=5&mailto=you@example.com" - Network accessline 14
"https://api.openalex.org/works?search=transformer+attention&per-page=5&mailto=you@example.com" - Network accessline 30
data = json.loads(http_get( "https://api.openalex.org/works" - Network accessline 31
"https://api.openalex.org/works" - Network accessline 47
# Confirmed output (2026-04-18): # W3151130473 2021 1887 CrossViT: Cross-Attention Multi-Scale Vision Transformer for I # doi: https://doi.org/10.1109/iccv48922.2021.00041 - Network accessline 48
# W3151130473 2021 1887 CrossViT: Cross-Attention Multi-Scale Vision Transformer for I # doi: https://doi.org/10.1109/iccv48922.2021.00041 # open access: False | pdf: None - Network accessline 49
# doi: https://doi.org/10.1109/iccv48922.2021.00041 - Network accessline 60
# By OpenAlex ID (bare or full URL form both work) w = json.loads(http_get("https://api.openalex.org/works/W2626778328?mailto=you@example.com")) - Network accessline 61
w = json.loads(http_get("https://api.openalex.org/works/W2626778328?mailto=you@example.com")) - Network accessline 65
# By DOI (pass the full DOI URL as the entity ID) w = json.loads(http_get( "https://api.openalex.org/works/https://doi.org/10.1038/nature14539?mailto=you@example.com" - Network accessline 66
w = json.loads(http_get( "https://api.openalex.org/works/https://doi.org/10.1038/nature14539?mailto=you@example.com" )) - Network accessline 67
"https://api.openalex.org/works/https://doi.org/10.1038/nature14539?mailto=you@example.com" - Network accessline 81
w = json.loads(http_get( "https://api.openalex.org/works/W2626778328" - Network accessline 82
"https://api.openalex.org/works/W2626778328" - Network accessline 100
# Search by name data = json.loads(http_get( "https://api.openalex.org/authors?search=geoffrey+hinton&per-page=3&mailto=you@example.com" - Network accessline 101
data = json.loads(http_get( "https://api.openalex.org/authors?search=geoffrey+hinton&per-page=3&mailto=you@example.com" )) - Network accessline 102
"https://api.openalex.org/authors?search=geoffrey+hinton&per-page=3&mailto=you@example.com" - Network accessline 114
# Fetch by bare ID a = json.loads(http_get("https://api.openalex.org/authors/A5108093963?mailto=you@example.com")) - Network accessline 115
a = json.loads(http_get("https://api.openalex.org/authors/A5108093963?mailto=you@example.com")) - Network accessline 119
# Get all works by this author (sorted by citations) works_data = json.loads(http_get( "https://api.openalex.org/works" - Network accessline 120
works_data = json.loads(http_get( "https://api.openalex.org/works" "?filter=author.id:A5108093963" - Network accessline 121
"https://api.openalex.org/works" - Network accessline 141
data = json.loads(http_get( "https://api.openalex.org/institutions?search=MIT&per-page=3&mailto=you@example.com" - Network accessline 142
"https://api.openalex.org/institutions?search=MIT&per-page=3&mailto=you@example.com" - Network accessline 149
# Works from an institution works = json.loads(http_get( "https://api.openalex.org/works" - Network accessline 150
works = json.loads(http_get( "https://api.openalex.org/works" "?filter=institutions.id:I63966007" - Network accessline 151
"https://api.openalex.org/works" - Network accessline 169
# Concepts endpoint (Wikidata-linked) data = json.loads(http_get( "https://api.openalex.org/concepts?search=machine+learning&per-page=5&mailto=you@example.com" - Network accessline 170
data = json.loads(http_get( "https://api.openalex.org/concepts?search=machine+learning&per-page=5&mailto=you@example.com" )) - Network accessline 171
"https://api.openalex.org/concepts?search=machine+learning&per-page=5&mailto=you@example.com" - Network accessline 178
# Topics endpoint (newer: domain > field > subfield > topic) data2 = json.loads(http_get( "https://api.openalex.org/topics?search=machine+learning&per-page=3&mailto=you@example.com" - Network accessline 179
data2 = json.loads(http_get( "https://api.openalex.org/topics?search=machine+learning&per-page=3&mailto=you@example.com" )) - Network accessline 180
"https://api.openalex.org/topics?search=machine+learning&per-page=3&mailto=you@example.com" - Network accessline 197
data = json.loads(http_get( "https://api.openalex.org/sources?search=nature&per-page=3&mailto=you@example.com" - Network accessline 198
"https://api.openalex.org/sources?search=nature&per-page=3&mailto=you@example.com" - Network accessline 205
# Works in a source works = json.loads(http_get( "https://api.openalex.org/works?filter=primary_location.source.id:S137773608" - Network accessline 206
works = json.loads(http_get( "https://api.openalex.org/works?filter=primary_location.source.id:S137773608" "&per-page=3&sort=cited_by_count:desc" - Network accessline 207
"https://api.openalex.org/works?filter=primary_location.source.id:S137773608" - Network accessline 221
data = json.loads(http_get( "https://api.openalex.org/funders?search=national+science+foundation&per-page=3&mailto=you@example.com" - Network accessline 222
"https://api.openalex.org/funders?search=national+science+foundation&per-page=3&mailto=you@example.com" - Network accessline 238
# Papers that CITE this paper (forward citations) citing = json.loads(http_get( f"https://api.openalex.org/works?filter=cites:{paper_id}" - Network accessline 239
citing = json.loads(http_get( f"https://api.openalex.org/works?filter=cites:{paper_id}" "&per-page=5&sort=cited_by_count:desc" - Network accessline 240
f"https://api.openalex.org/works?filter=cites:{paper_id}" - Network accessline 250
# Papers THIS paper cites (backward — list of IDs in the work object) paper = json.loads(http_get( f"https://api.openalex.org/works/{paper_id}?select=referenced_works&mailto=you@example.com" - Network accessline 251
paper = json.loads(http_get( f"https://api.openalex.org/works/{paper_id}?select=referenced_works&mailto=you@example.com" )) - Network accessline 252
f"https://api.openalex.org/works/{paper_id}?select=referenced_works&mailto=you@example.com" - Network accessline 274
encoded_cursor = urllib.parse.quote(cursor, safe="") url = ( f"https://api.openalex.org/works" - Network accessline 275
url = ( f"https://api.openalex.org/works" f"?filter={query_filter}" - Network accessline 276
f"https://api.openalex.org/works" - Network accessline 305
# Publication counts by year for machine learning papers data = json.loads(http_get( "https://api.openalex.org/works" - Network accessline 306
data = json.loads(http_get( "https://api.openalex.org/works" "?filter=concepts.id:C119857082" # C119857082 = Machine learning concept - Network accessline 307
"https://api.openalex.org/works" - Network accessline 374
| `language` | `language:en` | ISO 639-1 language code | | `cites` | `cites:W2626778328` | Works citing this paper | | `doi` | `doi:10.1038/nature14539` | By DOI (no `https://doi.org/` prefix) | - Network accessline 376
| `doi` | `doi:10.1038/nature14539` | By DOI (no `https://doi.org/` prefix) | - Network accessline 383
https://api.openalex.org/{entity_type} - Network accessline 417
Full entity URLs: `https://openalex.org/{ID}` (canonical form returned in `id` field). - Network accessline 444
- **OpenAlex IDs in the `id` field are full URLs, not bare IDs.** The field returns `https://openalex.org/W2626778328`. Always `.split("/")[-1]` to get the bare `W2626778328` form needed for `filter=cites:`, `filter=author.id:`, etc. - Network accessline 446
- **DOI lookup uses the full DOI URL as the path parameter.** Correct: `GET /works/https://doi.org/10.1038/nature14539`. Incorrect: `GET /works/10.1038/nature14539` (returns 404).
agent-workspace/domain-skills/openstreetmap/scraping.md
- Network accessline 21
q = urllib.parse.quote(query) raw = http_get( f"https://nominatim.openstreetmap.org/search?q={q}&format=json&limit={limit}&addressdetails=1", - Network accessline 22
raw = http_get( f"https://nominatim.openstreetmap.org/search?q={q}&format=json&limit={limit}&addressdetails=1", headers=UA - Network accessline 23
f"https://nominatim.openstreetmap.org/search?q={q}&format=json&limit={limit}&addressdetails=1", - Network accessline 56
raw = http_get( "https://nominatim.openstreetmap.org/search?q=Eiffel+Tower&format=json&limit=3&addressdetails=1", - Network accessline 57
"https://nominatim.openstreetmap.org/search?q=Eiffel+Tower&format=json&limit=3&addressdetails=1", - Network accessline 74
raw = http_get( "https://nominatim.openstreetmap.org/reverse?lat=48.8584&lon=2.2945&format=json", - Network accessline 75
"https://nominatim.openstreetmap.org/reverse?lat=48.8584&lon=2.2945&format=json", - Network accessline 95
raw = http_get( "https://nominatim.openstreetmap.org/search?city=Paris&country=France&format=json&limit=1", - Network accessline 96
"https://nominatim.openstreetmap.org/search?city=Paris&country=France&format=json&limit=1", - Network accessline 114
# Prefix: N=node, W=way, R=relation raw = http_get( "https://nominatim.openstreetmap.org/lookup?osm_ids=W5013364&format=json", - Network accessline 115
raw = http_get( "https://nominatim.openstreetmap.org/lookup?osm_ids=W5013364&format=json", headers=UA - Network accessline 116
"https://nominatim.openstreetmap.org/lookup?osm_ids=W5013364&format=json", - Network accessline 154
**Endpoint**: `https://overpass-api.de/api/interpreter` - Network accessline 156
- `https://overpass.openstreetmap.fr/api/interpreter` — requires non-Mozilla User-Agent - Network accessline 166
UA = {"User-Agent": "browser-harness/1.0"} OVERPASS = "https://overpass.openstreetmap.fr/api/interpreter" - Network accessline 167
OVERPASS = "https://overpass.openstreetmap.fr/api/interpreter" - Network accessline 205
OVERPASS = "https://overpass.openstreetmap.fr/api/interpreter" - Network accessline 208
"""POST to Overpass — no URL length limits, preferred for multi-statement QL.""" data = urllib.parse.urlencode({"data": query}).encode() req = urllib.request.Request( - Network accessline 209
data = urllib.parse.urlencode({"data": query}).encode() req = urllib.request.Request( OVERPASS, data=data, method="POST", - Network accessline 210
req = urllib.request.Request( - Network accessline 216
} ) with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 217
) with urllib.request.urlopen(req, timeout=30) as r: body = r.read() - Network accessline 218
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 248
"phone": "+33 1 45 51 56 74", "opening_hours": "Mo-Sa 08:00-23:00; Su 09:00-19:00", # optional "website": "https://...", # optional - Network accessline 249
"opening_hours": "Mo-Sa 08:00-23:00; Su 09:00-19:00", # optional "website": "https://...", # optional "wheelchair": "yes" # optional - Network accessline 250
"website": "https://...", # optional - Network accessline 307
https://{a,b,c}.tile.openstreetmap.org/{z}/{x}/{y}.png - Network accessline 312
- Returns 256×256 PNG tiles - Policy: max 2 req/s per IP, non-commercial use, must display OSM attribution - Tile coordinate calculator: `https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames` - Network accessline 313
- Policy: max 2 req/s per IP, non-commercial use, must display OSM attribution - Tile coordinate calculator: `https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames` - Bulk tile downloading is prohibited — use Overpass or data extracts in - Network accessline 314
- Tile coordinate calculator: `https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames` - Network accessline 327
x, y = lat_lon_to_tile(48.8582, 2.2945, 14) url = f"https://a.tile.openstreetmap.org/14/{x}/{y}.png" - Network accessline 328
url = f"https://a.tile.openstreetmap.org/14/{x}/{y}.png" - Network accessline 329
# url == 'https://a.tile.openstreetmap.org/14/8281/5646.png' - Network accessline 345
raw = http_get("https://overpass-api.de/api/status", headers={"User-Agent": "browser-harness/1.0"}) - Network accessline 357
def overpass_get_with_retry(query: str, max_retries: int = 3) -> dict: for attempt in range(max_retries): url = f"https://overpass.openstreetmap.fr/api/interpreter?data={urllib.parse.quote(query)}" - Network accessline 358
for attempt in range(max_retries): url = f"https://overpass.openstreetmap.fr/api/interpreter?data={urllib.parse.quote(query)}" raw = http_get(url, headers={"User-Agent": "browser-harness/1.0"}) - Network accessline 359
url = f"https://overpass.openstreetmap.fr/api/interpreter?data={urllib.parse.quote(query)}" - Network accessline 379
UA = {"User-Agent": "browser-harness/1.0"} NOMINATIM = "https://nominatim.openstreetmap.org" - Network accessline 380
NOMINATIM = "https://nominatim.openstreetmap.org" - Network accessline 381
OVERPASS = "https://overpass.openstreetmap.fr/api/interpreter" - Network accessline 403
"""POST variant — avoids URL length limits for complex queries.""" data = urllib.parse.urlencode({"data": query}).encode() req = urllib.request.Request( - Network accessline 404
data = urllib.parse.urlencode({"data": query}).encode() req = urllib.request.Request( OVERPASS, data=data, method="POST", - Network accessline 405
req = urllib.request.Request( - Network accessline 409
"Accept-Encoding": "gzip"} ) with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 410
) with urllib.request.urlopen(req, timeout=30) as r: body = r.read() - Network accessline 411
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 490
**Overpass `http_get` POST workaround**: `http_get` only supports GET. For POST requests (needed to avoid URL length limits for complex multi-statement QL), use `urllib.request.Request` directly as shown in the `overpass_post()` example abo
agent-workspace/domain-skills/outlook/webmail-compose.md
- Network accessline 5
- Mail: `https://outlook.office.com/mail/`.
agent-workspace/domain-skills/package-registries/npm-pypi.md
- Network accessline 3
`https://registry.npmjs.org` · `https://api.npmjs.org` · `https://pypi.org` · `https://pypistats.org` - Network accessline 32
import json data = json.loads(http_get("https://registry.npmjs.org/react")) - Network accessline 33
data = json.loads(http_get("https://registry.npmjs.org/react")) - Network accessline 50
print(v['license']) # 'MIT' print(list(v.get('dependencies', {}).keys())) # [] (react 19 has no runtime deps) print(v.get('homepage')) # 'https://react.dev/' - Network accessline 51
print(list(v.get('dependencies', {}).keys())) # [] (react 19 has no runtime deps) print(v.get('homepage')) # 'https://react.dev/' print(len(data['versions'])) # 2785 — all published versions - Network accessline 52
print(v.get('homepage')) # 'https://react.dev/' - Network accessline 59
import json # Fetch a specific version v = json.loads(http_get("https://registry.npmjs.org/react/19.2.5")) - Network accessline 60
# Fetch a specific version v = json.loads(http_get("https://registry.npmjs.org/react/19.2.5")) print(v['name'], v['version'], v['description']) - Network accessline 61
v = json.loads(http_get("https://registry.npmjs.org/react/19.2.5")) - Network accessline 64
# Fetch latest directly (no need to resolve dist-tags first) v = json.loads(http_get("https://registry.npmjs.org/react/latest")) - Network accessline 65
v = json.loads(http_get("https://registry.npmjs.org/react/latest")) - Network accessline 74
req = urllib.request.Request( - Network accessline 75
"https://registry.npmjs.org/react", - Network accessline 79
} ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 80
) with urllib.request.urlopen(req, timeout=20) as r: raw = r.read() - Network accessline 81
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 97
import json data = json.loads(http_get("https://registry.npmjs.org/@playwright/test")) - Network accessline 98
data = json.loads(http_get("https://registry.npmjs.org/@playwright/test")) - Network accessline 106
# Direct path (preferred) url = f"https://registry.npmjs.org/{pkg}" # '@playwright/test' - Network accessline 107
url = f"https://registry.npmjs.org/{pkg}" # '@playwright/test' - Network accessline 109
url = f"https://registry.npmjs.org/{pkg.replace('/', '%2F')}" - Network accessline 124
stats = json.loads(http_get("https://api.npmjs.org/downloads/point/last-week/react")) - Network accessline 142
bulk = json.loads(http_get( "https://api.npmjs.org/downloads/point/last-week/" - Network accessline 143
"https://api.npmjs.org/downloads/point/last-week/" - Network accessline 166
resp = json.loads(http_get( "https://api.npmjs.org/downloads/range/2025-01-01:2025-01-07/react" - Network accessline 167
"https://api.npmjs.org/downloads/range/2025-01-01:2025-01-07/react" - Network accessline 183
# Fields: text, size (max ~250), from (offset), quality, popularity, maintenance weights data = json.loads(http_get( "https://registry.npmjs.org/-/v1/search?text=browser+automation&size=5" - Network accessline 184
data = json.loads(http_get( "https://registry.npmjs.org/-/v1/search?text=browser+automation&size=5" )) - Network accessline 185
"https://registry.npmjs.org/-/v1/search?text=browser+automation&size=5" - Network accessline 216
try: data = json.loads(http_get("https://registry.npmjs.org/nonexistent-pkg-xyz")) except urllib.error.HTTPError as e: - Network accessline 217
data = json.loads(http_get("https://registry.npmjs.org/nonexistent-pkg-xyz")) except urllib.error.HTTPError as e: # 404 for missing packages - Network accessline 233
# Latest version metadata data = json.loads(http_get("https://pypi.org/pypi/requests/json")) - Network accessline 234
data = json.loads(http_get("https://pypi.org/pypi/requests/json")) - Network accessline 245
print(info['home_page']) # None (may be empty — check project_urls) print(info['project_urls']) # {'Documentation': 'https://requests.readthedocs.io', - Network accessline 246
print(info['project_urls']) # {'Documentation': 'https://requests.readthedocs.io', # 'Source': 'https://github.com/psf/requests'} - Network accessline 247
# {'Documentation': 'https://requests.readthedocs.io', - Network accessline 248
# 'Source': 'https://github.com/psf/requests'} - Network accessline 274
# Fetch a pinned version (not just latest) data = json.loads(http_get("https://pypi.org/pypi/requests/2.32.3/json")) - Network accessline 275
data = json.loads(http_get("https://pypi.org/pypi/requests/2.32.3/json")) - Network accessline 285
data = json.loads(http_get("https://pypi.org/pypi/requests/json")) - Network accessline 315
# Recent (last day/week/month) — fastest, single call stats = json.loads(http_get("https://pypistats.org/api/packages/requests/recent")) - Network accessline 316
stats = json.loads(http_get("https://pypistats.org/api/packages/requests/recent")) - Network accessline 322
# Historical daily totals (overall, going back ~6 months) overall = json.loads(http_get("https://pypistats.org/api/packages/requests/overall")) - Network accessline 323
overall = json.loads(http_get("https://pypistats.org/api/packages/requests/overall")) - Network accessline 331
# Without mirrors (pip installs only, more accurate for real usage): clean = json.loads(http_get( "https://pypistats.org/api/packages/requests/overall?mirrors=false" - Network accessline 332
clean = json.loads(http_get( "https://pypistats.org/api/packages/requests/overall?mirrors=false" )) - Network accessline 333
"https://pypistats.org/api/packages/requests/overall?mirrors=false" - Network accessline 336
# By Python major version by_python = json.loads(http_get( "https://pypistats.org/api/packages/requests/python_major" - Network accessline 337
by_python = json.loads(http_get( "https://pypistats.org/api/packages/requests/python_major" )) - Network accessline 338
"https://pypistats.org/api/packages/requests/python_major" - Network accessline 342
# By OS by_sys = json.loads(http_get( "https://pypistats.org/api/packages/requests/system" - Network accessline 343
by_sys = json.loads(http_get( "https://pypistats.org/api/packages/requests/system" )) - Network accessline 344
"https://pypistats.org/api/packages/requests/system" - Network accessline 348
# By Python minor version by_minor = json.loads(http_get( "https://pypistats.org/api/packages/requests/python_minor" - Network accessline 349
by_minor = json.loads(http_get( "https://pypistats.org/api/packages/requests/python_minor" )) - Network accessline 350
"https://pypistats.org/api/packages/requests/python_minor" - Network accessline 362
def get_pypi_info(pkg): d = json.loads(http_get(f"https://pypi.org/pypi/{pkg}/json")) - Network accessline 363
d = json.loads(http_get(f"https://pypi.org/pypi/{pkg}/json")) - Network accessline 388
try: data = json.loads(http_get("https://pypi.org/pypi/nonexistent-xyz-abc/json")) except urllib.error.HTTPError as e: - Network accessline 389
data = json.loads(http_get("https://pypi.org/pypi/nonexistent-xyz-abc/json")) except urllib.error.HTTPError as e: print(e.code) # 404 - Network accessline 405
def npm_info(pkg): # Use single-version endpoint (1-2KB) not full registry doc (MB) v = json.loads(http_get(f"https://registry.npmjs.org/{pkg}/latest")) - Network accessline 406
# Use single-version endpoint (1-2KB) not full registry doc (MB) v = json.loads(http_get(f"https://registry.npmjs.org/{pkg}/latest")) s = json.loads(http_get(f"https://api.npmjs.org/downloads/point/last-month/{pkg}")) - Network accessline 407
v = json.loads(http_get(f"https://registry.npmjs.org/{pkg}/latest")) - Network accessline 408
s = json.loads(http_get(f"https://api.npmjs.org/downloads/point/last-month/{pkg}")) - Network accessline 424
pkgs = ['react', 'vue', 'angular', 'svelte'] bulk = json.loads(http_get( f"https://api.npmjs.org/downloads/point/last-week/{','.join(pkgs)}" - Network accessline 425
bulk = json.loads(http_get( f"https://api.npmjs.org/downloads/point/last-week/{','.join(pkgs)}" )) - Network accessline 426
f"https://api.npmjs.org/downloads/point/last-week/{','.join(pkgs)}" - Network accessline 464
- **PyPI XML-RPC API is dead** — `https://pypi.org/pypi` (XML-RPC) returns a fault for most methods including `package_releases`. Use JSON API only.
agent-workspace/domain-skills/partsouq/vin-lookup.md
- Network accessline 8
https://partsouq.com/en/search/all?q=<17-char VIN>
agent-workspace/domain-skills/perplexity/computer.md
- Network accessline 3
"Perplexity Computer" is Perplexity's long-running agent product that lives under `https://www.perplexity.ai/computer/*`. It runs multi-step research/build tasks in a cloud sandbox and produces a plan (Todo), tool invocations, and file arti - Network accessline 9
- Dashboard / task list: `https://www.perplexity.ai/computer/tasks` - Network accessline 10
- Task detail (run page): `https://www.perplexity.ai/computer/tasks/<slug>-<id>` - Network accessline 16
# Python: urlparse(href).path.rstrip('/').rsplit('/', 1)[-1][-22:] ``` - Connectors: `https://www.perplexity.ai/computer/connectors` - Network accessline 17
``` - Connectors: `https://www.perplexity.ai/computer/connectors` - Custom skills: `https://www.perplexity.ai/computer/skills` - Network accessline 18
- Connectors: `https://www.perplexity.ai/computer/connectors` - Network accessline 19
- Custom skills: `https://www.perplexity.ai/computer/skills` - Network accessline 20
- Public share: the same task URL with `?view=thread` appended (e.g. `https://www.perplexity.ai/computer/tasks/<slug>-<id>?view=thread`). There is **no separate `/share/<id>` path** — the access level is toggled server-side and the `view=th - Network accessline 44
browser-harness <<'PY' new_tab("https://www.perplexity.ai/computer/tasks") - Network accessline 45
new_tab("https://www.perplexity.ai/computer/tasks") - Network accessline 64
browser-harness <<'PY' new_tab("https://www.perplexity.ai/computer/tasks") - Network accessline 65
new_tab("https://www.perplexity.ai/computer/tasks") - Network accessline 115
| Tool label | the only `<button>` direct child of the wrapper | Text = human-readable action, e.g. `"Writing to chart.py"`, `"Generating the comparison chart"`, `"Researching: <query>"`. | | Timestamp + duration | sibling text node with `A - Network accessline 116
| Timestamp + duration | sibling text node with `Apr 17, 4:00 AM · 9s` format | Durations stop updating when the tool completes. | | Inline image artifact | `<img src="https://pplx-res.cloudinary.com/...">` or `<img src="https://d2z0o16i8xm - Network accessline 117
| Inline image artifact | `<img src="https://pplx-res.cloudinary.com/...">` or `<img src="https://d2z0o16i8xm8ak.cloudfront.net/...">` | Cloudinary is the persistent URL; CloudFront URLs are presigned (expire) — if you want to archive, down - Network accessline 119
| Citation favicons | `<img src="https://www.google.com/s2/favicons?domain=...">` | Google's favicon proxy; the hostnames next to them are the actual citation sources. |
agent-workspace/domain-skills/polymarket/scraping.md
- Network accessline 9
- Event page: `https://polymarket.com/event/<slug>` — a group of related markets (e.g. "Iran x Israel/US conflict ends by…" holds one market per proposed end-date). - Network accessline 10
- Single market (rare nowadays; most UI routes are events): `https://polymarket.com/market/<slug>`. - Network accessline 15
Base: `https://gamma-api.polymarket.com`. No auth, no key, no rate limit observed under normal use. All data structured JSON. **Use `http_get` from `helpers.py`.** - Network accessline 23
ev = json.loads(http_get( "https://gamma-api.polymarket.com/events?slug=iran-x-israelus-conflict-ends-by" - Network accessline 24
"https://gamma-api.polymarket.com/events?slug=iran-x-israelus-conflict-ends-by" - Network accessline 63
Endpoint: `https://gamma-api.polymarket.com/comments` (NOT `comments-api.polymarket.com` — that hostname no longer resolves as of Apr 2026). - Network accessline 71
ev = json.loads(http_get("https://gamma-api.polymarket.com/events?slug=iran-x-israelus-conflict-ends-by"))[0] - Network accessline 73
raw = http_get( f"https://gamma-api.polymarket.com/comments" - Network accessline 74
f"https://gamma-api.polymarket.com/comments" - Network accessline 104
Real-time order book lives on `https://clob.polymarket.com`. Needed when `bestBid`/`bestAsk` on Gamma are stale (rare) or for trade history. Market-data endpoints don't need auth; order placement does. - Network accessline 107
# Mid-price from live order book ob = json.loads(http_get(f"https://clob.polymarket.com/book?token_id={clob_token_id}")) - Network accessline 108
ob = json.loads(http_get(f"https://clob.polymarket.com/book?token_id={clob_token_id}")) - Network accessline 132
browser-harness <<'PY' new_tab("https://polymarket.com/event/iran-x-israelus-conflict-ends-by") - Network accessline 133
new_tab("https://polymarket.com/event/iran-x-israelus-conflict-ends-by")
agent-workspace/domain-skills/poshmark/scraping.md
- Network accessline 23
UA = "poshmark-listing-export/1.0 (python-urllib; personal research script)" BASE = "https://poshmark.com" - Network accessline 24
BASE = "https://poshmark.com" - Network accessline 52
def fetch(url, budget_s=120): - Network accessline 58
remaining = deadline - time.monotonic() try: req = urllib.request.Request(url, headers={ - Network accessline 59
try: req = urllib.request.Request(url, headers={ "User-Agent": UA, "Accept-Encoding": "gzip", "Accept-Language": "en-US,en;q=0.9"}) - Network accessline 60
req = urllib.request.Request(url, headers={ - Network accessline 61
"User-Agent": UA, "Accept-Encoding": "gzip", "Accept-Language": "en-US,en;q=0.9"}) with urllib.request.urlopen(req, timeout=max(0.1, min(30, remaining))) as r: body = read_body(r, deadline) - Network accessline 62
with urllib.request.urlopen(req, timeout=max(0.1, min(30, remaining))) as r: - Network accessline 138
for page in range(1, max_pages + 1): url = browse_url(path, filters, page) final, html = fetch(url) - Network accessline 139
url = browse_url(path, filters, page) final, html = fetch(url) if not same_url(final, url): - Network accessline 140
final, html = fetch(url) - Network accessline 183
page 3: 48 rows, 48 new, total=5000, next=True 144 listings, status: truncated_max_pages {"id": "6add680c8925d3da8fdfd464", "title": "Levis | 712 Slim Fit 28 Distress Jeans", "brand": "Levi's", "size": "US 28", "price": 30.0, "original_pric - Network accessline 184
144 listings, status: truncated_max_pages {"id": "6add680c8925d3da8fdfd464", "title": "Levis | 712 Slim Fit 28 Distress Jeans", "brand": "Levi's", "size": "US 28", "price": 30.0, "original_price": 67.0, "currency": "USD", "department": "Wom - Network accessline 185
{"id": "6add680c8925d3da8fdfd464", "title": "Levis | 712 Slim Fit 28 Distress Jeans", "brand": "Levi's", "size": "US 28", "price": 30.0, "original_price": 67.0, "currency": "USD", "department": "Women", "category": "Denim", "status": "avail - Network accessline 187
page 1: 0 rows, 0 new, total=0, next=False 0 listings for an unknown brand, status: complete refused: server sent us elsewhere: asked https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc, got https://poshmark.com/br - Network accessline 188
0 listings for an unknown brand, status: complete refused: server sent us elsewhere: asked https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc, got https://poshmark.com/brand/lululemon_athletica-Women-Pants_&_Jumps - Network accessline 189
refused: server sent us elsewhere: asked https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc, got https://poshmark.com/brand/lululemon_athletica-Women-Pants_&_Jumpsuits?sort_by=added_desc; call scrape() again with - Network accessline 198
{"id": "6add6586cbbea541a1f1443a", "title": "Lululemon License to Train High-Rise Pant Army Green Casual Women’s Active Small", "brand": "lululemon athletica", "size": "US S", "price": 85.0, "original_price": 128.0, "currency": "USD", "depa - Network accessline 203
The hydrated page keeps `window.__INITIAL_STATE__`, so the browser path reads the same JSON instead of scraping tiles. `open_page` only accepts `https://poshmark.com/brand/<slug>` and `/category/<slug>` URLs, waits until the tab is on exact - Network accessline 245
u = urllib.parse.urlparse(url) if u.scheme != "https" or u.netloc != "poshmark.com" or not ALLOWED_PATH.fullmatch(urllib.parse.unquote(u.path)): raise ValueError(f"refusing {url}: only https://poshmark.com/brand/<slug> and /cate - Network accessline 246
if u.scheme != "https" or u.netloc != "poshmark.com" or not ALLOWED_PATH.fullmatch(urllib.parse.unquote(u.path)): raise ValueError(f"refusing {url}: only https://poshmark.com/brand/<slug> and /category/<slug> pages are allowed") - Network accessline 247
raise ValueError(f"refusing {url}: only https://poshmark.com/brand/<slug> and /category/<slug> pages are allowed") - Network accessline 267
MAX_PAGES, SITE_CAP_TOTAL = 3, 5000 base = "https://poshmark.com/category/Men-Shoes?" + urllib.parse.urlencode( - Network accessline 268
base = "https://poshmark.com/category/Men-Shoes?" + urllib.parse.urlencode( - Network accessline 290
time.sleep(2) try: # this slug 301s to a different canonical path, so open_page() refuses it and names the target open_page("https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc") - Network accessline 291
try: # this slug 301s to a different canonical path, so open_page() refuses it and names the target open_page("https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc") except RuntimeError as e: - Network accessline 292
open_page("https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc") - Network accessline 296
try: # robots.txt disallows /search: refused before the tab navigates open_page("https://poshmark.com/search?query=nike") - Network accessline 297
open_page("https://poshmark.com/search?query=nike") - Network accessline 315
"price": 89, "original_price": null, "url": "https://poshmark.com/listing/6add6e68441b19999eb53d55" - Network accessline 316
"original_price": null, "url": "https://poshmark.com/listing/6add6e68441b19999eb53d55" }, - Network accessline 317
"url": "https://poshmark.com/listing/6add6e68441b19999eb53d55" - Network accessline 319
... ] refused: redirected: asked https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc, got https://poshmark.com/brand/lululemon_athletica-Women-Pants_&_Jumpsuits?sort_by=added_desc; open that URL instead if it is th - Network accessline 320
] refused: redirected: asked https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc, got https://poshmark.com/brand/lululemon_athletica-Women-Pants_&_Jumpsuits?sort_by=added_desc; open that URL instead if it is the pa - Network accessline 321
refused: redirected: asked https://poshmark.com/brand/Lululemon_Athletica-Women-Pants?sort_by=added_desc, got https://poshmark.com/brand/lululemon_athletica-Women-Pants_&_Jumpsuits?sort_by=added_desc; open that URL instead if it is the page - Network accessline 322
refused: refusing https://poshmark.com/search?query=nike: only https://poshmark.com/brand/<slug> and /category/<slug> pages are allowed - Network accessline 354
| `category` | `category` | e.g. `"Denim"`, `"Pants"` | | `status` | `inventory.status` | `"available"` | | `url` | built from `id`: `https://poshmark.com/listing/<id>` | 301s to the canonical `/listing/<Title-Slug>-<id>`. The slug is left - Network accessline 355
| `status` | `inventory.status` | `"available"` | | `url` | built from `id`: `https://poshmark.com/listing/<id>` | 301s to the canonical `/listing/<Title-Slug>-<id>`. The slug is left out because it repeats the seller-written title with spa - Network accessline 356
| `url` | built from `id`: `https://poshmark.com/listing/<id>` | 301s to the canonical `/listing/<Title-Slug>-<id>`. The slug is left out because it repeats the seller-written title with spaces turned into `-` and punctuation dropped, so `r
agent-workspace/domain-skills/producthunt/scraping.md
- Network accessline 3
Field-tested against https://www.producthunt.com on 2026-04-18. - Network accessline 26
# goto_url() may fail on Product Hunt — use new_tab() reliably tid = new_tab("https://www.producthunt.com") - Network accessline 27
tid = new_tab("https://www.producthunt.com") - Network accessline 28
wait(4) # React SPA needs time; wait_for_load() alone is insufficient page = page_info() # Verify: url should be 'https://www.producthunt.com/' - Network accessline 30
# Verify: url should be 'https://www.producthunt.com/' - Network accessline 90
URL: https://www.producthunt.com/leaderboard/daily/YYYY/M/D - Network accessline 91
Example: https://www.producthunt.com/leaderboard/daily/2026/4/18 - Network accessline 110
URL: https://www.producthunt.com/leaderboard/weekly/YYYY/WW - Network accessline 111
Example: https://www.producthunt.com/leaderboard/weekly/2026/16 - Network accessline 123
URL: https://www.producthunt.com/leaderboard/monthly/YYYY/M - Network accessline 124
Example: https://www.producthunt.com/leaderboard/monthly/2026/4 - Network accessline 131
URL: `https://www.producthunt.com/topics/developer-tools` - Network accessline 136
# Navigate to topic new_tab("https://www.producthunt.com/topics/developer-tools") - Network accessline 137
new_tab("https://www.producthunt.com/topics/developer-tools") - Network accessline 166
URL: `https://www.producthunt.com/categories/ai-agents` - Network accessline 178
URL: `https://www.producthunt.com/products/claude-opus-4-7` - Network accessline 204
URL: `https://www.producthunt.com/search?q=AI+agent` - Network accessline 209
new_tab("https://www.producthunt.com/search?q=AI+agent") - Network accessline 228
**Note:** Search result elements are `<button>` elements (not `<a>` links), so there is no `href` in the DOM. Product URL must be constructed: `https://www.producthunt.com/products/<slug>` where slug must be derived by other means. The elem - Network accessline 275
# 1. Open Product Hunt in a new tab new_tab("https://www.producthunt.com/leaderboard/daily/2026/4/18") - Network accessline 276
new_tab("https://www.producthunt.com/leaderboard/daily/2026/4/18")
agent-workspace/domain-skills/pubmed/scraping.md
- Network accessline 3
`https://pubmed.ncbi.nlm.nih.gov` — 37 M+ biomedical citations. **Never use the browser for PubMed.** All data is reachable via `http_get` using the NCBI E-utilities REST API. No API key required; a free key raises the rate limit from 3 to - Network accessline 13
# Step 1: search → get PMIDs search = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" - Network accessline 14
search = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" "?db=pubmed&term=deep+learning+radiology&retmax=10&retmode=json" - Network accessline 15
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" - Network accessline 21
# Step 2: fetch lightweight metadata for all PMIDs in one call summary = json.loads(http_get( f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi" - Network accessline 22
summary = json.loads(http_get( f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi" f"?db=pubmed&id={','.join(pmids)}&retmode=json" - Network accessline 23
f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi" - Network accessline 50
data = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" - Network accessline 51
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" - Network accessline 97
data = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi" - Network accessline 98
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi" - Network accessline 137
raw = http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi" - Network accessline 138
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi" - Network accessline 233
# Step 1: ESearch with usehistory=y — NCBI holds result set on server search = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" - Network accessline 234
search = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" "?db=pubmed&term=CRISPR+gene+editing&retmax=0&retmode=json&usehistory=y" - Network accessline 235
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" - Network accessline 247
for start in range(0, min(total, 1000), batch_size): # cap at 1000 for demo raw = http_get( f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi" - Network accessline 248
raw = http_get( f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi" f"?db=pubmed&query_key={query_key}&WebEnv={webenv}" - Network accessline 249
f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi" - Network accessline 265
data = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/einfo.fcgi?retmode=json" - Network accessline 266
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/einfo.fcgi?retmode=json" - Network accessline 281
data = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/einfo.fcgi?db=pubmed&retmode=json" - Network accessline 282
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/einfo.fcgi?db=pubmed&retmode=json" - Network accessline 304
# linkname=pubmed_pmc — may also hit the server outage; check error field data = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi" - Network accessline 305
data = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi" "?dbfrom=pubmed&id=38325330&linkname=pubmed_pmc&retmode=json" - Network accessline 306
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi" - Network accessline 329
**Practical alternative**: If ELink is down, extract DOI from EFetch/ESummary and use `https://doi.org/{doi}` directly for the full-text link. - Network accessline 336
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi # search → PMIDs - Network accessline 337
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi # PMIDs → JSON summary - Network accessline 338
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi # PMIDs → full XML - Network accessline 339
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi # cross-db links - Network accessline 340
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/einfo.fcgi # DB metadata - Network accessline 371
pmid = "41999029" pubmed_url = f"https://pubmed.ncbi.nlm.nih.gov/{pmid}/" - Network accessline 372
pubmed_url = f"https://pubmed.ncbi.nlm.nih.gov/{pmid}/" - Network accessline 373
doi = "10.12659/MSM.951157" doi_url = f"https://doi.org/{doi}" # resolves to publisher page pmc_id = "PMC9876543" # from ESummary articleids - Network accessline 374
doi_url = f"https://doi.org/{doi}" # resolves to publisher page - Network accessline 376
pmc_url = f"https://www.ncbi.nlm.nih.gov/pmc/articles/{pmc_id}/" - Network accessline 405
[Credential-related source omitted] - Access to secretsline 405
[Credential-related source omitted] - Network accessline 411
search = json.loads(http_get( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" - Network accessline 412
"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"
agent-workspace/domain-skills/qbo/report-export.md
- Network accessline 11
3. Set the required report expansion state. 4. Click QBO report toolbar `Export` -> `Export to PDF`. 5. Wait for the generated `blob:https://qbo.intuit.com/<uuid>` PDF target. - Network accessline 12
4. Click QBO report toolbar `Export` -> `Export to PDF`. 5. Wait for the generated `blob:https://qbo.intuit.com/<uuid>` PDF target. 6. Fetch that blob from the QBO page origin and write the bytes locally. - Network accessline 13
5. Wait for the generated `blob:https://qbo.intuit.com/<uuid>` PDF target. 6. Fetch that blob from the QBO page origin and write the bytes locally. 7. Validate with `pdftotext` when report content matters. - Network accessline 29
BU_NAME=qbo BU_CDP_URL=http://127.0.0.1:9223 browser-harness <<'PY' - Network accessline 36
- Custom reports list route: `https://qbo.intuit.com/app/customreports`. - Network accessline 69
- QBO `Export` -> `Export to PDF` produces the clean report PDF. - This path may not fire a normal Chromium `Browser.downloadProgress` event, so `Browser.setDownloadBehavior` alone is not enough. - QBO opens an in-page PDF modal using Chrom - Network accessline 70
- This path may not fire a normal Chromium `Browser.downloadProgress` event, so `Browser.setDownloadBehavior` alone is not enough. - QBO opens an in-page PDF modal using Chromium's built-in PDF viewer. The actual report PDF appears as a chi - Network accessline 71
- QBO opens an in-page PDF modal using Chromium's built-in PDF viewer. The actual report PDF appears as a child `blob:https://qbo.intuit.com/<uuid>` target. - Network accessline 82
t["url"] for t in cdp("Target.getTargets")["targetInfos"] if t.get("url", "").startswith("blob:https://qbo.intuit.com/") - Network accessline 83
for t in cdp("Target.getTargets")["targetInfos"] if t.get("url", "").startswith("blob:https://qbo.intuit.com/") ] - Network accessline 84
if t.get("url", "").startswith("blob:https://qbo.intuit.com/") - Network accessline 99
wait(2) # let the PDF viewer finish loading the blob meta = js(f""" return fetch({json.dumps(blob)}).then(async r => {{ - Network accessline 100
meta = js(f""" return fetch({json.dumps(blob)}).then(async r => {{ const b = await r.blob(); - Network accessline 101
return fetch({json.dumps(blob)}).then(async r => {{ - Possible obfuscationline 129
pdf = base64.b64decode("".join(parts))
agent-workspace/domain-skills/quora/scraping.md
- Network accessline 3
`https://www.quora.com` — Q&A platform. One reliable access path: `http_get` with a Chrome UA against question, answer, topic, and profile pages. Quora SSR-renders all public data into `window.ansFrontendGlobals.data.inlineQueryResults` via - Network accessline 42
Requires Chrome/Firefox UA — bare Mozilla/5.0 returns 403. """ req = urllib.request.Request(url, headers={ - Network accessline 43
""" req = urllib.request.Request(url, headers={ "User-Agent": CHROME_UA, - Network accessline 44
req = urllib.request.Request(url, headers={ - Network accessline 48
"Accept-Language": "en-US,en;q=0.9", }) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 49
}) with urllib.request.urlopen(req, timeout=20) as r: data = r.read() - Network accessline 50
with urllib.request.urlopen(req, timeout=20) as r: - Access to secretsline 96
[Credential-related source omitted] - Network accessline 176
result = quora_question("https://www.quora.com/What-is-the-meaning-of-life") - Network accessline 226
""" Fetch a single answer by its permalink. URL format: https://www.quora.com/{question-slug}/answer/{author-profile-slug} - Network accessline 227
Fetch a single answer by its permalink. URL format: https://www.quora.com/{question-slug}/answer/{author-profile-slug} Returns answer dict with: aid, num_upvotes, num_views, text, author info. - Network accessline 228
URL format: https://www.quora.com/{question-slug}/answer/{author-profile-slug} - Network accessline 251
# Example: # quora_answer("https://www.quora.com/What-is-the-meaning-of-life/answer/Pararth-Shah") - Network accessline 252
# quora_answer("https://www.quora.com/What-is-the-meaning-of-life/answer/Pararth-Shah") - Network accessline 262
""" Fetch topic metadata from a Quora topic page. URL format: https://www.quora.com/topic/{topic-slug} - Network accessline 263
Fetch topic metadata from a Quora topic page. URL format: https://www.quora.com/topic/{topic-slug} Returns: tid, name, num_followers, url, is_following, has_leaderboard. - Network accessline 264
URL format: https://www.quora.com/topic/{topic-slug} - Network accessline 289
# Example: # quora_topic("https://www.quora.com/topic/Python-programming-language") - Network accessline 290
# quora_topic("https://www.quora.com/topic/Python-programming-language") - Network accessline 299
def quora_profile(profile_url): """ Fetch user profile data from https://www.quora.com/profile/{username} - Network accessline 300
""" Fetch user profile data from https://www.quora.com/profile/{username} Returns: uid, name, credential, follower_count, following_count, profile_image_url. - Network accessline 301
Fetch user profile data from https://www.quora.com/profile/{username} - Network accessline 330
# Example: # quora_profile("https://www.quora.com/profile/Pararth-Shah") - Network accessline 331
# quora_profile("https://www.quora.com/profile/Pararth-Shah") - Network accessline 356
- **Search pages do not yield result data** — `https://www.quora.com/search?q=...` returns 3 payloads with viewer/network info only — no search results in the SSR payload. Search results are loaded client-side and are not accessible via htt - Network accessline 362
- **`permaUrl` may be an absolute URL for Spaces answers** — Most answers have `permaUrl: "/Question-slug/answer/Author-Name"` (relative). Answers posted in a Quora Space have a full absolute URL like `"https://spacename.quora.com/Question-
agent-workspace/domain-skills/rawg/scraping.md
- Network accessline 3
Field-tested against rawg.io on 2026-04-18. `https://rawg.io` — world's largest video game database with 500K+ games. - Network accessline 4
`https://rawg.io` — world's largest video game database with 500K+ games. - Network accessline 10
`https://api.rawg.io/api/` requires a valid API key on every request. - Network accessline 21
Free API keys are available at `https://rawg.io/apidocs` after signing up at `https://rawg.io/signup` (no credit card, ~1 minute). Free tier: **20,000 requests/month**. - Network accessline 22
`https://rawg.io/signup` (no credit card, ~1 minute). Free tier: **20,000 requests/month**. - Access to secretsline 23
[Credential-related source omitted] - Network accessline 44
Returns game dict or None. """ resp = http_get(f"https://rawg.io/games/{slug}") - Network accessline 45
""" resp = http_get(f"https://rawg.io/games/{slug}") idx = resp.find('window.CLIENT_PARAMS = {') - Network accessline 46
resp = http_get(f"https://rawg.io/games/{slug}") - Network accessline 85
# game['updated'] -> '2026-04-17T23:18:04' # game['playtime'] -> 43 (average hours) # game['website'] -> 'https://thewitcher.com/en/witcher3' - Network accessline 86
# game['playtime'] -> 43 (average hours) # game['website'] -> 'https://thewitcher.com/en/witcher3' # game['background_image'] -> 'https://media.rawg.io/media/games/618/618c2031a07bbff6b4f611f10b6bcdbc.jpg' - Network accessline 87
# game['website'] -> 'https://thewitcher.com/en/witcher3' - Network accessline 88
# game['background_image'] -> 'https://media.rawg.io/media/games/618/618c2031a07bbff6b4f611f10b6bcdbc.jpg' - Network accessline 145
def top_games(): """Returns list of 40 game dicts from rawg.io/games listing page.""" resp = http_get("https://rawg.io/games") - Network accessline 146
"""Returns list of 40 game dicts from rawg.io/games listing page.""" resp = http_get("https://rawg.io/games") idx = resp.find('window.CLIENT_PARAMS = {') - Network accessline 147
resp = http_get("https://rawg.io/games") - Network accessline 194
[Credential-related source omitted] - Access to secretsline 194
[Credential-related source omitted] - Network accessline 198
1. Sign up at `https://rawg.io/signup` - Network accessline 199
2. Visit `https://rawg.io/apidocs` — click "Get API key" - Access to secretsline 201
[Credential-related source omitted] - Access to secretsline 209
[Credential-related source omitted] - Network accessline 211
# Search results = json.loads(http_get( f"https://api.rawg.io/api/games?search=witcher&page_size=5&key={KEY}" - Network accessline 212
results = json.loads(http_get( f"https://api.rawg.io/api/games?search=witcher&page_size=5&key={KEY}" )) - Network accessline 213
f"https://api.rawg.io/api/games?search=witcher&page_size=5&key={KEY}" - Network accessline 219
# Top-rated top = json.loads(http_get( f"https://api.rawg.io/api/games?ordering=-metacritic&page_size=10&key={KEY}" - Network accessline 220
top = json.loads(http_get( f"https://api.rawg.io/api/games?ordering=-metacritic&page_size=10&key={KEY}" )) - Network accessline 221
f"https://api.rawg.io/api/games?ordering=-metacritic&page_size=10&key={KEY}" - Network accessline 224
# By date range recent = json.loads(http_get( f"https://api.rawg.io/api/games?dates=2024-01-01,2024-12-31&ordering=-added&page_size=20&key={KEY}" - Network accessline 225
recent = json.loads(http_get( f"https://api.rawg.io/api/games?dates=2024-01-01,2024-12-31&ordering=-added&page_size=20&key={KEY}" )) - Network accessline 226
f"https://api.rawg.io/api/games?dates=2024-01-01,2024-12-31&ordering=-added&page_size=20&key={KEY}" - Network accessline 229
# By platform (PC=4, PS4=18, Xbox One=1, Switch=7) pc_games = json.loads(http_get( f"https://api.rawg.io/api/games?platforms=4&ordering=-rating&page_size=10&key={KEY}" - Network accessline 230
pc_games = json.loads(http_get( f"https://api.rawg.io/api/games?platforms=4&ordering=-rating&page_size=10&key={KEY}" )) - Network accessline 231
f"https://api.rawg.io/api/games?platforms=4&ordering=-rating&page_size=10&key={KEY}" - Network accessline 238
# By ID (faster if you have it) game = json.loads(http_get(f"https://api.rawg.io/api/games/3328?key={KEY}")) - Network accessline 239
game = json.loads(http_get(f"https://api.rawg.io/api/games/3328?key={KEY}")) - Network accessline 242
# By slug game = json.loads(http_get( f"https://api.rawg.io/api/games/the-witcher-3-wild-hunt?key={KEY}" - Network accessline 243
game = json.loads(http_get( f"https://api.rawg.io/api/games/the-witcher-3-wild-hunt?key={KEY}" )) - Network accessline 244
f"https://api.rawg.io/api/games/the-witcher-3-wild-hunt?key={KEY}" - Network accessline 270
# All platforms platforms = json.loads(http_get(f"https://api.rawg.io/api/platforms?key={KEY}")) - Network accessline 271
platforms = json.loads(http_get(f"https://api.rawg.io/api/platforms?key={KEY}")) - Network accessline 274
# Parent platforms only parents = json.loads(http_get(f"https://api.rawg.io/api/platforms/lists/parents?key={KEY}")) - Network accessline 275
parents = json.loads(http_get(f"https://api.rawg.io/api/platforms/lists/parents?key={KEY}")) - Network accessline 277
# Genres genres = json.loads(http_get(f"https://api.rawg.io/api/genres?key={KEY}")) - Network accessline 278
genres = json.loads(http_get(f"https://api.rawg.io/api/genres?key={KEY}"))
agent-workspace/domain-skills/realtor-com/scraping.md
- Network accessline 10
- **Search pages** (`/realestateandhomes-search/<City_ST or ZIP>[/pg-N]`) are a React Router app. All 42 results per page, plus the total count, sit in `window.__reactRouterDataRouter.state.loaderData.srp.search.value`. That object has pric - Network accessline 11
- **Listing pages** (`/realestateandhomes-detail/<slug>`) are a Next.js app. `__NEXT_DATA__` -> `props.pageProps.initialReduxState.propertyDetails` holds the full key facts (year built, HOA, price/sqft, days on MLS, lot, garage, stories, de - Network accessline 12
- From an open realtor.com tab, a same-origin `fetch()` of a listing URL returned 200 with `__NEXT_DATA__` in the HTML. That gives listing facts in batches without navigating the tab. - Network accessline 52
is_foreclosure: !!f.is_foreclosure, is_new_listing: !!f.is_new_listing, list_date: p.list_date, lat: p.lat, lng: p.lng, broker: p.brokerageName, url: p.ldpSlug ? 'https://www.realtor.com/realestateandhomes-detail/' + p.ldpSl - Network accessline 53
list_date: p.list_date, lat: p.lat, lng: p.lng, broker: p.brokerageName, url: p.ldpSlug ? 'https://www.realtor.com/realestateandhomes-detail/' + p.ldpSlug : null }; - Network accessline 54
url: p.ldpSlug ? 'https://www.realtor.com/realestateandhomes-detail/' + p.ldpSlug : null - Network accessline 60
def search_url(location, page=1): base = "https://www.realtor.com/realestateandhomes-search/" + urllib.parse.quote(location, safe="") - Network accessline 61
base = "https://www.realtor.com/realestateandhomes-search/" + urllib.parse.quote(location, safe="") - Network accessline 135
STOPPED AT MAX_PAGES=3: 126 of 7008 collected; raise MAX_PAGES for the rest 126 listings of 7008 (partial) 1704 Shelbourne Dr 78752 400000 3 2 1556 House for sale https://www.realtor.com/realestateandhomes-detail/1704-Shelbourne-Dr_Austin_T - Network accessline 136
126 listings of 7008 (partial) 1704 Shelbourne Dr 78752 400000 3 2 1556 House for sale https://www.realtor.com/realestateandhomes-detail/1704-Shelbourne-Dr_Austin_TX_78752_M81029-30727 6700 Tulloch Way 78754 439999 4 3.5 3840 Pending https: - Network accessline 137
1704 Shelbourne Dr 78752 400000 3 2 1556 House for sale https://www.realtor.com/realestateandhomes-detail/1704-Shelbourne-Dr_Austin_TX_78752_M81029-30727 - Network accessline 138
6700 Tulloch Way 78754 439999 4 3.5 3840 Pending https://www.realtor.com/realestateandhomes-detail/6700-Tulloch-Way_Austin_TX_78754_M83959-32351 - Network accessline 139
6305 Leatherwood Cv 78759 720000 4 2.5 2164 House for sale https://www.realtor.com/realestateandhomes-detail/6305-Leatherwood-Cv_Austin_TX_78759_M76134-13530 - Network accessline 147
This needs a www.realtor.com tab (block 1 leaves one open), because `fetch()` must be same-origin. It reads the saved `realtor_listings.json`, fetches each listing's HTML from inside the page and parses `__NEXT_DATA__`. - Network accessline 165
const ctl = new AbortController(); const timer = setTimeout(() => ctl.abort(), 30000); fetch(url, {credentials: 'same-origin', signal: ctl.signal}).then(async res => { - Network accessline 166
const timer = setTimeout(() => ctl.abort(), 30000); fetch(url, {credentials: 'same-origin', signal: ctl.signal}).then(async res => { const html = await res.text(); - Network accessline 167
fetch(url, {credentials: 'same-origin', signal: ctl.signal}).then(async res => { - Network accessline 265
if not on_realtor(): try: goto_url("https://www.realtor.com/") - Network accessline 266
try: goto_url("https://www.realtor.com/") except TimeoutError: - Network accessline 267
goto_url("https://www.realtor.com/") - Network accessline 273
time.sleep(1) else: raise RuntimeError("need a www.realtor.com tab for same-origin fetch()") - Network accessline 275
raise RuntimeError("need a www.realtor.com tab for same-origin fetch()") - Network accessline 319
{'url': 'https://www.realtor.com/realestateandhomes-detail/6700-Tulloch-Way_Austin_TX_78754_M83959-32351', 'property_id': '8395932351', 'listing_id': '3001457163', 'status': 'for_sale', 'flags': ['is_pending'], 'list_price': 439999, 'price_ - Network accessline 431
{'name': '1704 Shelbourne Dr, Austin, TX 78752', 'price': 400000, 'availability': 'https://schema.org/InStock', 'beds': 3, 'baths': 2, 'sqft': 1556, 'year_built': 1969, 'type': 'SingleFamilyResidence', 'date_posted': '2026-02-21T14:21:38Z', - Network accessline 454
| `lat`, `lng` | `lat`, `lng` | | | `broker` | `brokerageName` | brokerage business name | | `url` | `ldpSlug` | `https://www.realtor.com/realestateandhomes-detail/<ldpSlug>`; null when there is no slug | - Network accessline 456
| `url` | `ldpSlug` | `https://www.realtor.com/realestateandhomes-detail/<ldpSlug>`; null when there is no slug | - Network accessline 490
- **`__NEXT_DATA__` on search pages is a stub** (`{"props":{"pageProps":{"geo":{"area_type":"city"}}}}`). Search moved to React Router. Listing pages still use Next.js. - **Two apps, two globals.** `window.__reactRouterDataRouter` exists on - Network accessline 491
- **Two apps, two globals.** `window.__reactRouterDataRouter` exists on search pages only. On listing pages, use `#__NEXT_DATA__` or JSON-LD. - **`js()` gives up after about 5 s.** In browser-harness, a slow `Runtime.evaluate` raises `Runti - Network accessline 492
- **`js()` gives up after about 5 s.** In browser-harness, a slow `Runtime.evaluate` raises `RuntimeError("Runtime.evaluate timed out ...")`, and a slow `goto_url()` can raise `TimeoutError` (the daemon's IPC wait is 5 s). The blocks catch - Network accessline 508
- Pages past the end (`/78704/pg-11` when `total=398`) return 0 rows rather than an error. Block 1 stops at the first short page, so it never requests them. - An unknown location (`Nowhereville_ZZ`): the page loads with the title "For Sale - Network accessline 510
- An unknown listing slug: `fetch()` returned 200 after a redirect to `/realestateandhomes-search/Austin_TX`, with no `propertyDetails`. Block 2 treats that as a failed listing and does not retry it.
agent-workspace/domain-skills/reddit/scraping.md
- Network accessline 9
- Full post: `https://www.reddit.com/r/<sub>/comments/<id>/<slug>/` - Network accessline 10
- Share short-link: `https://www.reddit.com/r/<sub>/s/<hash>` — redirects to the full URL once the page loads. `new_tab(short_url)` + `wait_for_load()` is enough; by the time you read `location.href` it will be the canonical one. - Network accessline 11
- Old Reddit: append `/.json` to any post URL for anonymous JSON: `https://www.reddit.com/r/<sub>/comments/<id>/.json`. - Network accessline 12
- Old UI (simpler DOM, no web components): `https://old.reddit.com/r/<sub>/comments/<id>/` — useful fallback when `shreddit-*` selectors change. - Network accessline 20
url = "https://www.reddit.com/r/cursor/comments/1l0u9y7/claude_code_prompt_to_autogenerate_full_cursor/.json" - Network accessline 38
browser-harness <<'PY' new_tab("https://www.reddit.com/r/vibecoding/comments/1kwuqpz/") - Network accessline 39
new_tab("https://www.reddit.com/r/vibecoding/comments/1kwuqpz/")
agent-workspace/domain-skills/redfin/scraping.md
- Network accessline 26
PAUSE = 3.0 # seconds between page loads MAX_SHORT = 0.01 # raise if more than this share of the header count is missing (a live count drifts a little) BASE = "https://www.redfin.com" - Network accessline 28
BASE = "https://www.redfin.com" - Network accessline 234
"price_per_sqft": 683, "hoa_month": null, "days_on_market": 1, "status": "Active", "neighborhood": "SOUTH PARK SEC 2", "lat": 30.232246, "lon": -97.7638868, "url": "https://www.redfin.com/TX/Austin/503-S-Park-Dr-78704/home/31703545", "s - Network accessline 235
"neighborhood": "SOUTH PARK SEC 2", "lat": 30.232246, "lon": -97.7638868, "url": "https://www.redfin.com/TX/Austin/503-S-Park-Dr-78704/home/31703545", "source": "embedded"}, {"property_id": 31205095, "address": "1818 Margaret St", "price - Network accessline 236
"url": "https://www.redfin.com/TX/Austin/503-S-Park-Dr-78704/home/31703545", "source": "embedded"}, - Network accessline 265
Reads the first URL saved by block 1; pass any `https://www.redfin.com/.../home/<id>` URL to `listing_details()` instead. Everything comes from the one listing page: its JSON-LD plus the detail data embedded in its HTML. - Network accessline 406
{ "url": "https://www.redfin.com/TX/Austin/503-S-Park-Dr-78704/home/31703545", - Network accessline 407
"url": "https://www.redfin.com/TX/Austin/503-S-Park-Dr-78704/home/31703545", - Network accessline 412
"lat": 30.232246, "lon": -97.7638868, "amenities": ["Heating & cooling: Has A/C"], "photos": "22 urls, first: https://ssl.cdn-redfin.com/photo/92/bigphoto/245/3820245_0.jpg", - Network accessline 413
"amenities": ["Heating & cooling: Has A/C"], "photos": "22 urls, first: https://ssl.cdn-redfin.com/photo/92/bigphoto/245/3820245_0.jpg", "property_id": 31703545, "listing_id": 224677425, "mls_id": "3820245", - Network accessline 414
"photos": "22 urls, first: https://ssl.cdn-redfin.com/photo/92/bigphoto/245/3820245_0.jpg", - Network accessline 446
| neighborhood | `location.value` | embedded only | `"SOUTH PARK SEC 2"` | | lat / lon | `latLong.value.latitude/longitude` | JSON-LD `geo` | `30.232246`, `-97.7638868` | | url | `"https://www.redfin.com" + url` | card link | `.../home/3170 - Network accessline 447
| lat / lon | `latLong.value.latitude/longitude` | JSON-LD `geo` | `30.232246`, `-97.7638868` | | url | `"https://www.redfin.com" + url` | card link | `.../home/31703545` | | source | `"embedded"` | `"card"` | | - Network accessline 448
| url | `"https://www.redfin.com" + url` | card link | `.../home/31703545` | - Network accessline 488
- Plain HTTP is blocked: `curl https://www.redfin.com/robots.txt` was redirected to `ratelimited.redfin.com` with status 429, so even robots.txt was read in the browser.
agent-workspace/domain-skills/rest-countries/scraping.md
- Network accessline 3
`https://restcountries.com` — open JSON API for country data. **Never use the browser.** All data is reachable via `http_get`. No auth required, no API key. - Network accessline 13
data = http_get("https://restcountries.com/v3.1/all?fields=name,cca2,capital,population,area,region") - Network accessline 40
# Single code — returns a list (one element) data = http_get("https://restcountries.com/v3.1/alpha/DE") - Network accessline 41
data = http_get("https://restcountries.com/v3.1/alpha/DE") - Network accessline 44
# But: /alpha/CODE?fields=... returns a plain dict, not a list — watch for this data2 = http_get("https://restcountries.com/v3.1/alpha/DE?fields=name,cca2,currencies,languages,flags") - Network accessline 45
data2 = http_get("https://restcountries.com/v3.1/alpha/DE?fields=name,cca2,currencies,languages,flags") - Network accessline 52
languages = country2["languages"] # {"deu": "German"} lang_names = list(languages.values()) # ["German"] flag_png = country2["flags"]["png"] # " - Network accessline 53
lang_names = list(languages.values()) # ["German"] flag_png = country2["flags"]["png"] # "https://flagcdn.com/w320/de.png" flag_svg = country2["flags"]["svg"] - Network accessline 54
flag_png = country2["flags"]["png"] # "https://flagcdn.com/w320/de.png" - Network accessline 55
flag_svg = country2["flags"]["svg"] # "https://flagcdn.com/de.svg" - Network accessline 70
codes = ["US", "GB", "FR", "DE", "JP", "CN", "IN", "BR", "AU", "CA"] data = http_get(f"https://restcountries.com/v3.1/alpha?codes={','.join(codes)}&fields=name,cca2,population") - Network accessline 71
data = http_get(f"https://restcountries.com/v3.1/alpha?codes={','.join(codes)}&fields=name,cca2,population") - Network accessline 85
# Partial match (default) — may return multiple results data = http_get("https://restcountries.com/v3.1/name/united") - Network accessline 86
data = http_get("https://restcountries.com/v3.1/name/united") - Network accessline 90
# Exact match — use fullText=true with the full common or official name data2 = http_get("https://restcountries.com/v3.1/name/united%20kingdom?fullText=true") - Network accessline 91
data2 = http_get("https://restcountries.com/v3.1/name/united%20kingdom?fullText=true") - Network accessline 103
data = http_get("https://restcountries.com/v3.1/region/europe?fields=name,cca2,population") - Network accessline 122
data = http_get("https://restcountries.com/v3.1/subregion/Western%20Europe?fields=name,cca2") - Network accessline 134
data = http_get("https://restcountries.com/v3.1/lang/arabic") - Network accessline 149
data = http_get("https://restcountries.com/v3.1/currency/EUR") - Network accessline 164
data = http_get("https://restcountries.com/v3.1/capital/berlin?fields=name,cca2,capital") - Network accessline 177
data = http_get("https://restcountries.com/v3.1/alpha/US")
agent-workspace/domain-skills/rightmove/scraping.md
- Network accessline 9
- Search result pages (`/property-for-sale/find.html`, `/property-to-rent/find.html`) are Next.js pages. Every listing on the page is in `<script id="__NEXT_DATA__">` at `props.pageProps.searchResults.properties`. A plain HTTP GET gets it, - Network accessline 10
- A free-text place ("Bristol", "Camden Town", "BS8") must first be turned into a `locationIdentifier` like `REGION^219` or `OUTCODE^295` with the public typeahead endpoint `https://los.rightmove.co.uk/typeahead`. - Network accessline 11
- 24 organic listings per page plus 1 "featured" slot (25 objects). Paginate with `index=0, 24, 48 ...`. Hard cap: 42 pages / `index=984` (about 1,000 listings) even when `resultCount` is higher. The code below reports when it hits that cap - Network accessline 12
- Property pages (`/properties/<id>`) embed `window.__PAGE_MODEL`, a flattened JSON graph. Decode it to get key features, full description, tenure, council tax band, nearest stations and (for rentals) deposit / furnishing / available date. - Network accessline 13
- Plain-HTTP requests (typeahead and search pages only) send a truthful client User-Agent naming this skill. An HTTP 403/429 whose body says the service is "for the use of Rightmove Group Limited only" is an access block: `fetch()` stops an - Network accessline 26
HEADERS = { "User-Agent": "browser-harness-rightmove-skill/1.0 (+https://github.com/browser-use/browser-harness)", # truthful client UA - Network accessline 27
"User-Agent": "browser-harness-rightmove-skill/1.0 (+https://github.com/browser-use/browser-harness)", # truthful client UA - Network accessline 58
def fetch(url, accept="text/html", tries=4): - Network accessline 64
wait = None try: req = urllib.request.Request(url, headers={**HEADERS, "Accept": accept}) - Network accessline 65
try: req = urllib.request.Request(url, headers={**HEADERS, "Accept": accept}) with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 66
req = urllib.request.Request(url, headers={**HEADERS, "Accept": accept}) - Network accessline 67
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 89
def find_location(query): """Free text -> list of (locationIdentifier, displayName), best first. Punctuation breaks the endpoint (HTTP 400).""" url = "https://los.rightmove.co.uk/typeahead?" + urllib.parse.urlencode({"query": _norm( - Network accessline 90
"""Free text -> list of (locationIdentifier, displayName), best first. Punctuation breaks the endpoint (HTTP 400).""" url = "https://los.rightmove.co.uk/typeahead?" + urllib.parse.urlencode({"query": _norm(query), "limit": 10, "exclude" - Network accessline 91
url = "https://los.rightmove.co.uk/typeahead?" + urllib.parse.urlencode({"query": _norm(query), "limit": 10, "exclude": "STREET"}) - Network accessline 92
status, _, text = fetch(url, accept="application/json") # without this Accept you get XML - Network accessline 109
path = CHANNEL_PATHS[channel] params = {"locationIdentifier": location_id, "index": index, **filters} url = f"https://www.rightmove.co.uk/{path}/find.html?" + urllib.parse.urlencode(params) # ^ -> %5E - Network accessline 110
params = {"locationIdentifier": location_id, "index": index, **filters} url = f"https://www.rightmove.co.uk/{path}/find.html?" + urllib.parse.urlencode(params) # ^ -> %5E status, final_url, html = fetch(url) - Network accessline 111
url = f"https://www.rightmove.co.uk/{path}/find.html?" + urllib.parse.urlencode(params) # ^ -> %5E - Network accessline 112
status, final_url, html = fetch(url) - Network accessline 151
"first_visible": p.get("firstVisibleDate"), "featured": p.get("featuredProperty"), "url": f"https://www.rightmove.co.uk/properties/{pid}" if pid is not None else None, - Network accessline 152
"featured": p.get("featuredProperty"), "url": f"https://www.rightmove.co.uk/properties/{pid}" if pid is not None else None, } - Network accessline 153
"url": f"https://www.rightmove.co.uk/properties/{pid}" if pid is not None else None, - Network accessline 206
Bristol REGION^219 results: 1994 pages: 2 stopped: max_pages rows: 50 {'id': 94594029, 'address': 'Bowden Place, Downend', 'price': 285000, 'price_text': '£285,000', 'frequency': 'not specified', 'beds': 2, 'baths': 1, 'type': 'End of Terra - Network accessline 207
{'id': 94594029, 'address': 'Bowden Place, Downend', 'price': 285000, 'price_text': '£285,000', 'frequency': 'not specified', 'beds': 2, 'baths': 1, 'type': 'End of Terrace', 'agent': 'Ocean, Downend', 'added_or_reduced': 'Added yesterday', - Network accessline 296
def get_property(property_id, first=False): """Decoded property page, or None if the listing is gone (404/410).""" url = f"https://www.rightmove.co.uk/properties/{property_id}" - Network accessline 297
"""Decoded property page, or None if the listing is gone (404/410).""" url = f"https://www.rightmove.co.uk/properties/{property_id}" if not open_and_confirm(url, property_check(property_id), first=first): - Network accessline 298
url = f"https://www.rightmove.co.uk/properties/{property_id}" - Network accessline 324
def first_ids(path, location_id, n=2, first=False): url = f"https://www.rightmove.co.uk/{path}/find.html?" + urllib.parse.urlencode({"locationIdentifier": location_id, "index": 0}) - Network accessline 325
url = f"https://www.rightmove.co.uk/{path}/find.html?" + urllib.parse.urlencode({"locationIdentifier": location_id, "index": 0}) - Network accessline 433
base = "https://www.rightmove.co.uk/property-to-rent/find.html?" - Network accessline 463
pid = rows[0][0] time.sleep(1.5) if not open_and_confirm(f"https://www.rightmove.co.uk/properties/{pid}", property_check(pid)): - Network accessline 464
time.sleep(1.5) if not open_and_confirm(f"https://www.rightmove.co.uk/properties/{pid}", property_check(pid)): raise RuntimeError(f"property {pid} answered 404/410") - Network accessline 465
if not open_and_confirm(f"https://www.rightmove.co.uk/properties/{pid}", property_check(pid)): - Network accessline 500
| `first_visible` | `firstVisibleDate` | `"2026-05-15T15:36:54Z"` | | `featured` | `featuredProperty` | `true` on the 1 paid slot per page | | `url` | built from `id` | `https://www.rightmove.co.uk/properties/88550319` | - Network accessline 502
| `url` | built from `id` | `https://www.rightmove.co.uk/properties/88550319` | - Network accessline 537
- **Access block.** Plain-HTTP requests to property pages returned HTTP 429 with a body saying the API "is for the use of Rightmove Group Limited only". That is an access block, not a rate limit: example 1's `fetch()` raises on a 403/429 wi - Network accessline 538
- **Retry-After.** Example 1's `fetch()` honours `Retry-After` (seconds or HTTP-date) up to 120 s and raises if the server asks for longer. It never sleeps after the last attempt. - Network accessline 541
- **Typeahead returns XML unless you send `Accept: application/json`.** - **Ambiguous places.** `Clifton` returns Clifton in Bristol, Nottingham, York and more; `Camden Town` returns the London region first, then the station and Camden Town - Network accessline 542
- **Ambiguous places.** `Clifton` returns Clifton in Bristol, Nottingham, York and more; `Camden Town` returns the London region first, then the station and Camden Town in Gosport. `pick_location()` takes the top-ranked match whose name sta - Network accessline 543
- **Pagination cap.** `pagination.total` never exceeded 42 pages. Page 42 (`index=984`) has no `pagination.next` even when `resultCount` is 3,748, which is why `scrape()` compares `resultCount` with 1,008 to tell the cap from a real last pa - Network accessline 556
- `https://www.rightmove.co.uk/typeAhead/uknostreet/...` (older lookup path) returned the "We couldn't find the place you were looking for" HTML.
agent-workspace/domain-skills/rotten-tomatoes/scraping.md
- Network accessline 25
BASE = "https://www.rottentomatoes.com" # No User-Agent override: urllib sends its own truthful "Python-urllib/3.x", which got HTTP 200 on every URL below. - Network accessline 46
for i in range(tries): try: with urllib.request.urlopen(urllib.request.Request(url, headers=HDRS), timeout=timeout) as r: - Network accessline 47
try: with urllib.request.urlopen(urllib.request.Request(url, headers=HDRS), timeout=timeout) as r: data = r.read() - Network accessline 48
with urllib.request.urlopen(urllib.request.Request(url, headers=HDRS), timeout=timeout) as r: - Network accessline 260
60 titles, 60 unique urls, complete list: False stopped at max_pages=2; the list has more pages {"ems_id": "5b44daa8-5b70-3a2b-b009-0052edcfc114", "title": "Tenzing", "url": "https://www.rottentomatoes.com/m/tenzing", "type": "Movie", "toma - Network accessline 261
stopped at max_pages=2; the list has more pages {"ems_id": "5b44daa8-5b70-3a2b-b009-0052edcfc114", "title": "Tenzing", "url": "https://www.rottentomatoes.com/m/tenzing", "type": "Movie", "tomatometer": 98, "certified_fresh": true, "popcornm - Network accessline 262
{"ems_id": "5b44daa8-5b70-3a2b-b009-0052edcfc114", "title": "Tenzing", "url": "https://www.rottentomatoes.com/m/tenzing", "type": "Movie", "tomatometer": 98, "certified_fresh": true, "popcornmeter": 91, "release_text": "Streaming Oct 16, 20 - Network accessline 265
... enriched 5 of 5 | failed: [] {"url": "https://www.rottentomatoes.com/m/oppenheimer_2023", "type": "Movie", "title": "Oppenheimer", "tomatometer": 93, "tomatometer_reviews": 510, "tomatometer_avg": "8.60", "certified_fresh": true, "top_c - Network accessline 266
enriched 5 of 5 | failed: [] {"url": "https://www.rottentomatoes.com/m/oppenheimer_2023", "type": "Movie", "title": "Oppenheimer", "tomatometer": 93, "tomatometer_reviews": 510, "tomatometer_avg": "8.60", "certified_fresh": true, "top_criti - Network accessline 267
{"url": "https://www.rottentomatoes.com/m/oppenheimer_2023", "type": "Movie", "title": "Oppenheimer", "tomatometer": 93, "tomatometer_reviews": 510, "tomatometer_avg": "8.60", "certified_fresh": true, "top_critics_score": 95, "top_critics_r - Network accessline 268
{"url": "https://www.rottentomatoes.com/tv/the_bear", "type": "TVSeries", "title": "The Bear", "tomatometer": 93, "tomatometer_reviews": 469, "tomatometer_avg": "8.30", "certified_fresh": false, "top_critics_score": 93, "top_critics_reviews - Network accessline 269
{"url": "https://www.rottentomatoes.com/tv/the_bear/s05", "type": "TVSeason", "title": "Season 5 – The Bear", "tomatometer": 96, "tomatometer_reviews": 83, "tomatometer_avg": "8.10", "certified_fresh": true, "top_critics_score": 97, "top_cr - Network accessline 354
# Title page: read the embedded JSON from the DOM open_page("https://www.rottentomatoes.com/m/oppenheimer_2023", "#media-scorecard-json", first=True) - Network accessline 355
open_page("https://www.rottentomatoes.com/m/oppenheimer_2023", "#media-scorecard-json", first=True) - Network accessline 390
open_page("https://www.rottentomatoes.com/browse/movies_in_theaters/sort:popular", TILE) - Network accessline 426
{"url": "https://www.rottentomatoes.com/m/oppenheimer_2023", "title": "Oppenheimer (2023)", "tomatometer": "93", "reviews": 510, "popcornmeter": "91", "audience": "10,000+ Verified Ratings", "rating": "R", "genres": ["Biography", "History", - Network accessline 430
after Load more: 88 tiles stopped at MAX_CLICKS=2; list not exhausted rows: 88 | url now: https://www.rottentomatoes.com/browse/movies_in_theaters/sort:popular?page=3 - Network accessline 431
stopped at MAX_CLICKS=2; list not exhausted rows: 88 | url now: https://www.rottentomatoes.com/browse/movies_in_theaters/sort:popular?page=3 {'title': 'You Can See Everything', 'url': 'https://www.rottentomatoes.com/m/you_can_see_everything - Network accessline 432
rows: 88 | url now: https://www.rottentomatoes.com/browse/movies_in_theaters/sort:popular?page=3 - Network accessline 433
{'title': 'You Can See Everything', 'url': 'https://www.rottentomatoes.com/m/you_can_see_everything', 'tomatometer': '98%', 'popcornmeter': '97%', 'date': 'Opened Oct 16, 2026'} - Network accessline 440
| Key | Source | Example / note | |---|---|---| | url | final URL after redirects | `"https://www.rottentomatoes.com/m/oppenheimer_2023"` | - Network accessline 441
|---|---|---| | url | final URL after redirects | `"https://www.rottentomatoes.com/m/oppenheimer_2023"` | | type | JSON-LD `@type` | `"Movie"`, `"TVSeries"`, `"TVSeason"` | - Network accessline 442
| url | final URL after redirects | `"https://www.rottentomatoes.com/m/oppenheimer_2023"` | - Network accessline 483
- **Confirm the page before reading it.** Right after `goto_url` from the title page to a browse page, `location.href` was already the new URL but `readyState` was `loading`, then `interactive`; `wait_for_load()` alone only checks `readySta - Network accessline 484
- **Browser call timeouts.** A slow `cdp` round trip raises a `TimeoutError` subclass, but `js` re-raises a timed-out `Runtime.evaluate` as `RuntimeError("Runtime.evaluate timed out; ...")`, so `except TimeoutError` alone misses it. `is_har - Network accessline 485
- **Region redirects.** Bare `https://rottentomatoes.com/` redirects to `https://www.rottentomatoes.com/`. Title, browse and `/cnapi/` URLs returned HTTP 200 with no redirect from both vantage points used, but both were in the US (the site'
agent-workspace/domain-skills/sec-edgar/scraping.md
- Network accessline 3
`https://www.sec.gov` / `https://data.sec.gov` / `https://efts.sec.gov` — all public data, no auth required. Every workflow here is pure `http_get` — no browser needed. - Network accessline 20
import json UA = {"User-Agent": "browser-harness research@example.com"} tickers = json.loads(http_get("https://www.sec.gov/files/company_tickers.json", headers=UA)) - Network accessline 21
UA = {"User-Agent": "browser-harness research@example.com"} tickers = json.loads(http_get("https://www.sec.gov/files/company_tickers.json", headers=UA)) # 10,391 public companies, ~50KB, always fresh - Network accessline 22
tickers = json.loads(http_get("https://www.sec.gov/files/company_tickers.json", headers=UA)) - Network accessline 39
import json UA = {"User-Agent": "browser-harness research@example.com"} tickers = json.loads(http_get("https://www.sec.gov/files/company_tickers.json", headers=UA)) - Network accessline 41
tickers = json.loads(http_get("https://www.sec.gov/files/company_tickers.json", headers=UA)) - Network accessline 56
UA = {"User-Agent": "browser-harness research@example.com"} cik = "0000320193" # Apple - always zero-pad to 10 digits data = json.loads(http_get(f"https://data.sec.gov/submissions/CIK{cik}.json", headers=UA)) - Network accessline 58
data = json.loads(http_get(f"https://data.sec.gov/submissions/CIK{cik}.json", headers=UA)) - Network accessline 93
accn_nodash = accn.replace("-", "") url = f"https://www.sec.gov/Archives/edgar/data/{cik}/{accn_nodash}/{doc}" - Network accessline 94
url = f"https://www.sec.gov/Archives/edgar/data/{cik}/{accn_nodash}/{doc}" - Network accessline 95
# https://www.sec.gov/Archives/edgar/data/320193/000032019325000079/aapl-20250927.htm - Network accessline 108
# companyconcept: one metric, all reported values (quarterly + annual) data = json.loads(http_get( f"https://data.sec.gov/api/xbrl/companyconcept/CIK{cik_padded}/us-gaap/Assets.json", - Network accessline 109
data = json.loads(http_get( f"https://data.sec.gov/api/xbrl/companyconcept/CIK{cik_padded}/us-gaap/Assets.json", headers=UA - Network accessline 110
f"https://data.sec.gov/api/xbrl/companyconcept/CIK{cik_padded}/us-gaap/Assets.json", - Network accessline 144
# companyfacts: all reported XBRL concepts in one ~5MB call data = json.loads(http_get( "https://data.sec.gov/api/xbrl/companyfacts/CIK0000320193.json", - Network accessline 145
data = json.loads(http_get( "https://data.sec.gov/api/xbrl/companyfacts/CIK0000320193.json", headers=UA - Network accessline 146
"https://data.sec.gov/api/xbrl/companyfacts/CIK0000320193.json", - Network accessline 201
# Top companies by annual revenue (2024) data = json.loads(http_get( "https://data.sec.gov/api/xbrl/frames/us-gaap/RevenueFromContractWithCustomerExcludingAssessedTax/USD/CY2024.json", - Network accessline 202
data = json.loads(http_get( "https://data.sec.gov/api/xbrl/frames/us-gaap/RevenueFromContractWithCustomerExcludingAssessedTax/USD/CY2024.json", headers=UA - Network accessline 203
"https://data.sec.gov/api/xbrl/frames/us-gaap/RevenueFromContractWithCustomerExcludingAssessedTax/USD/CY2024.json", - Network accessline 216
# Total assets snapshot end of 2024 (balance sheet = instantaneous) data2 = json.loads(http_get( "https://data.sec.gov/api/xbrl/frames/us-gaap/Assets/USD/CY2024Q4I.json", - Network accessline 217
data2 = json.loads(http_get( "https://data.sec.gov/api/xbrl/frames/us-gaap/Assets/USD/CY2024Q4I.json", headers=UA - Network accessline 218
"https://data.sec.gov/api/xbrl/frames/us-gaap/Assets/USD/CY2024Q4I.json", - Network accessline 232
# startdt, enddt, size (max 100), from (offset for pagination) url = ( "https://efts.sec.gov/LATEST/search-index" - Network accessline 233
url = ( "https://efts.sec.gov/LATEST/search-index" "?q=%22climate+risk%22" - Network accessline 234
"https://efts.sec.gov/LATEST/search-index" - Network accessline 275
# Best method: company_tickers.json (fastest, all tickers) tickers = json.loads(http_get("https://www.sec.gov/files/company_tickers.json", headers=UA)) - Network accessline 276
tickers = json.loads(http_get("https://www.sec.gov/files/company_tickers.json", headers=UA)) - Network accessline 280
# Alternative: full-text search aggregations (finds CIK from company name) data = json.loads(http_get( "https://efts.sec.gov/LATEST/search-index?q=%22microsoft+corporation%22&forms=10-K", - Network accessline 281
data = json.loads(http_get( "https://efts.sec.gov/LATEST/search-index?q=%22microsoft+corporation%22&forms=10-K", headers=UA - Network accessline 282
"https://efts.sec.gov/LATEST/search-index?q=%22microsoft+corporation%22&forms=10-K", - Network accessline 301
def get_company_meta(ticker_cik): ticker, cik = ticker_cik subs = json.loads(http_get(f"https://data.sec.gov/submissions/CIK{cik}.json", headers=UA)) - Network accessline 302
ticker, cik = ticker_cik subs = json.loads(http_get(f"https://data.sec.gov/submissions/CIK{cik}.json", headers=UA)) return {"ticker": ticker, "name": subs['name'], "sic": subs['sic']} - Network accessline 303
subs = json.loads(http_get(f"https://data.sec.gov/submissions/CIK{cik}.json", headers=UA))
agent-workspace/domain-skills/sephora/scraping.md
- Network accessline 22
LIST_URL = "https://www.sephora.com/shop/face-serum" # a /shop/<category> or /brand/<brand> page - Network accessline 26
if not re.fullmatch(r"https://www\.sephora\.com/(shop|brand)/[a-z0-9-]+", LIST_URL): - Network accessline 27
raise SystemExit("LIST_URL must be https://www.sephora.com/shop/<slug> or /brand/<slug>, no query string") - Network accessline 63
"variation_type": p.get("variationType"), # "Size", "Color", ... "sponsored": bool(p.get("sponsored")), "url": "https://www.sephora.com" + p["targetUrl"] if p.get("targetUrl") else None, - Network accessline 64
"sponsored": bool(p.get("sponsored")), "url": "https://www.sephora.com" + p["targetUrl"] if p.get("targetUrl") else None, } - Network accessline 65
"url": "https://www.sephora.com" + p["targetUrl"] if p.get("targetUrl") else None, - Network accessline 70
opened_tab = None # set only if this block opened the tab; it never closes a tab it did not open href = js("location.href") or "" if not href.startswith("https://www.sephora.com/"): - Network accessline 71
href = js("location.href") or "" if not href.startswith("https://www.sephora.com/"): opened_tab = new_tab("https://www.sephora.com/") - Network accessline 72
if not href.startswith("https://www.sephora.com/"): - Network accessline 73
opened_tab = new_tab("https://www.sephora.com/") - Network accessline 140
"variation_type": "Size", "sponsored": false, "url": "https://www.sephora.com/product/vinoperfect-brightening-dark-spot-serum-vitamin-c-alternative-P94421?skuId=2744423" - Network accessline 141
"sponsored": false, "url": "https://www.sephora.com/product/vinoperfect-brightening-dark-spot-serum-vitamin-c-alternative-P94421?skuId=2744423" }, - Network accessline 142
"url": "https://www.sephora.com/product/vinoperfect-brightening-dark-spot-serum-vitamin-c-alternative-P94421?skuId=2744423" - Network accessline 149
The `status:` line says whether the walk is complete; with the default `MAX_PAGES = 3` it is `PARTIAL`, so never treat those rows as the whole category. With `MAX_PAGES = 20` the same category walked all 9 pages (`?currentPage=2` to `?curre - Network accessline 158
PRODUCT_URL = "https://www.sephora.com/product/studio-fix-powder-plus-foundation-24hr-oil-control-blur-matte-finish-12hr-buildable-coverage-P516457" - Network accessline 161
PRODUCT_URL = PRODUCT_URL.split("?")[0].split("#")[0] # ?skuId=... from listing URLs is optional m = re.fullmatch(r"https://www\.sephora\.com/product/[^/?#]*?(P\d+)", PRODUCT_URL) - Network accessline 162
m = re.fullmatch(r"https://www\.sephora\.com/product/[^/?#]*?(P\d+)", PRODUCT_URL) - Network accessline 163
if not m: raise SystemExit("PRODUCT_URL must look like https://www.sephora.com/product/<slug>-P<digits>") PRODUCT_ID = m.group(1) - Network accessline 164
raise SystemExit("PRODUCT_URL must look like https://www.sephora.com/product/<slug>-P<digits>") - Network accessline 171
opened_tab = None # set only if this block opened the tab; it never closes a tab it did not open href = js("location.href") or "" if not href.startswith("https://www.sephora.com/"): - Network accessline 172
href = js("location.href") or "" if not href.startswith("https://www.sephora.com/"): opened_tab = new_tab("https://www.sephora.com/") - Network accessline 173
if not href.startswith("https://www.sephora.com/"): - Network accessline 174
opened_tab = new_tab("https://www.sephora.com/") - Network accessline 233
"availability": (offers.get(s.get("skuId")) or {}).get("availability"), "image": (s.get("skuImages") or {}).get("imageUrl"), "url": "https://www.sephora.com" + s["targetUrl"] if s.get("targetUrl") else None, - Network accessline 234
"image": (s.get("skuImages") or {}).get("imageUrl"), "url": "https://www.sephora.com" + s["targetUrl"] if s.get("targetUrl") else None, }) - Network accessline 235
"url": "https://www.sephora.com" + s["targetUrl"] if s.get("targetUrl") else None, - Network accessline 279
"ingredients": "Synthetic Fluorphlogopite, Magnesium Potassium Fluorosilicate, Boron Nitride, ...", "how_to_use": "Suggested Usage: -Apply powder to prepped skin. ...", "url": "https://www.sephora.com/product/studio-fix-powder-plus-founda - Network accessline 280
"how_to_use": "Suggested Usage: -Apply powder to prepped skin. ...", "url": "https://www.sephora.com/product/studio-fix-powder-plus-foundation-24hr-oil-control-blur-matte-finish-12hr-buildable-coverage-P516457", "variant_count": 71, - Network accessline 281
"url": "https://www.sephora.com/product/studio-fix-powder-plus-foundation-24hr-oil-control-blur-matte-finish-12hr-buildable-coverage-P516457", - Network accessline 291
"few_left": false, "availability": "InStock", "image": "https://www.sephora.com/productimages/sku/s3018215-main-zoom.jpg", - Network accessline 292
"availability": "InStock", "image": "https://www.sephora.com/productimages/sku/s3018215-main-zoom.jpg", "url": "https://www.sephora.com/product/studio-fix-powder-plus-foundation-24hr-oil-control-blur-matte-finish-12hr-buildable-covera - Network accessline 293
"image": "https://www.sephora.com/productimages/sku/s3018215-main-zoom.jpg", - Network accessline 294
"url": "https://www.sephora.com/product/studio-fix-powder-plus-foundation-24hr-oil-control-blur-matte-finish-12hr-buildable-coverage-P516457?skuId=3018215" - Network accessline 320
| Sponsored | `sponsored` | boolean; `false` on all products seen (Face Serums pages 1 to 3, Foundation page 1, The Ordinary) | | URL | `targetUrl` | relative `/product/<slug>-P<id>?skuId=<sku>` | | Image | `heroImage` | `https://www.sephor - Network accessline 321
| URL | `targetUrl` | relative `/product/<slug>-P<id>?skuId=<sku>` | | Image | `heroImage` | `https://www.sephora.com/productimages/sku/s<sku>-main-zoom.jpg?imwidth=270...` | | Flags | `currentSku.isNew`, `isBestseller`, `isSephoraExclusive - Network accessline 322
| Image | `heroImage` | `https://www.sephora.com/productimages/sku/s<sku>-main-zoom.jpg?imwidth=270...` | - Network accessline 338
| Variants | `regularChildSkus[]` | 71 for P516457 (includes the default SKU); 1 for a single-size serum | | Variant fields | `skuId`, `variationValue`, `variationDesc`, `size`, `listPrice`, `isOutOfStock`, `isOnlyFewLeft`, `skuImages.image - Network accessline 340
| Variant offer | JSON-LD `ProductGroup.hasVariant[].offers` | `price` `"39.00"`, `priceCurrency` `"USD"`, `availability` `https://schema.org/InStock`; matched 71 of 71 SKUs by `sku` |
agent-workspace/domain-skills/shopify-admin/knowledge-base.md
- Network accessline 8
https://admin.shopify.com/store/<store-handle>/apps/shopify-knowledge-base/app
agent-workspace/domain-skills/shopify-storefronts/scraping.md
- Network accessline 12
- `/products/<handle>.js` adds fields the list endpoint lacks: prices in cents, `barcode`, `inventory_management`, `inventory_policy`, and on some stores `inventory_quantity`. - Headless Shopify stores (Hydrogen/Oxygen, Next.js) do not serv - Network accessline 14
- Browser fallback: open the storefront and call `fetch('/products.json?...')` from the page (same origin). On allbirds.com this returned the same 250/211/0 pages as plain HTTP. - Network accessline 37
STORE = "https://www.deathwishcoffee.com" # any Shopify storefront origin, no trailing slash - Network accessline 62
if attempt: time.sleep(delay) req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json", "Accept-Encoding": "gzip"}) - Network accessline 63
time.sleep(delay) req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json", "Accept-Encoding": "gzip"}) try: - Network accessline 64
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json", "Accept-Encoding": "gzip"}) - Network accessline 65
try: with urllib.request.urlopen(req, timeout=30) as r: data = r.read() - Network accessline 66
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 152
"available": true, "grams": 191, "image": "https://cdn.shopify.com/s/files/1/0271/7209/files/DeathWishCoffee_October26_Product_Silipint_SoloCup_Front_Web.jpg?v=1792676155", - Network accessline 153
"grams": 191, "image": "https://cdn.shopify.com/s/files/1/0271/7209/files/DeathWishCoffee_October26_Product_Silipint_SoloCup_Front_Web.jpg?v=1792676155", "all_images": [...], - Network accessline 154
"image": "https://cdn.shopify.com/s/files/1/0271/7209/files/DeathWishCoffee_October26_Product_Silipint_SoloCup_Front_Web.jpg?v=1792676155", - Network accessline 160
Same code against `https://www.allbirds.com` printed `page 1: 250`, `page 2: 211`, then `461 products, 5288 variants`. Each 250-product page took 0.2-1.5 s and was 0.6-4.5 MB. - Network accessline 169
STORE = "https://colourpop.com" - Network accessline 172
def get(url): req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json", "Accept-Encoding": "gzip"}) - Network accessline 173
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json", "Accept-Encoding": "gzip"}) - Network accessline 174
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 195
Colour Me Merry | ColourPop | Advent Calendar 2026 | from 99.0 to 99.0 42754994372690 Kit-ColourMeMerry 99.0 available qty 3750 deny barcode FG007713 images: ['https://cdn.shopify.com/s/files/1/1338/0845/files/Kit-ColourMeMerry-Hero.jpg?v - Network accessline 197
images: ['https://cdn.shopify.com/s/files/1/1338/0845/files/Kit-ColourMeMerry-Hero.jpg?v=1792618081', ...] - Network accessline 209
STORE = "https://kith.com" - Network accessline 213
def get(url, accept="application/xml"): req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": accept, "Accept-Encoding": "gzip"}) - Network accessline 214
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": accept, "Accept-Encoding": "gzip"}) - Network accessline 215
with urllib.request.urlopen(req, timeout=30) as r: - Network accessline 250
STORE = "https://www.allbirds.com" - Network accessline 254
(async (page) => { let r; try { r = await fetch('/products.json?limit=250&page=' + page, {headers: {Accept: 'application/json'}}); } - Network accessline 255
let r; try { r = await fetch('/products.json?limit=250&page=' + page, {headers: {Accept: 'application/json'}}); } catch (e) { return JSON.stringify({status: 0, rows: null}); } // network error - Network accessline 256
try { r = await fetch('/products.json?limit=250&page=' + page, {headers: {Accept: 'application/json'}}); } - Network accessline 315
STORE = "https://www.gymshark.com" - Network accessline 381
gymshark-fit-seamless-cropped-leggings-smokey-grey -> 5 variants gymshark-1-3-litre-water-bottle-black -> 1 variants {'title': 'eGift Card', 'brand': 'Gymshark | We Do Gym', 'group_id': '6453246788', 'variant_name': 'eGift Card', 'sku': 'GS - Network accessline 383
{'title': 'eGift Card', 'brand': 'Gymshark | We Do Gym', 'group_id': '6453246788', 'variant_name': 'eGift Card', 'sku': 'GSGFTCRD-10', 'size': '10.00', 'color': None, 'price': 10, 'currency': 'USD', 'availability': 'InStock', 'image': 'http - Network accessline 386
With `STORE = "https://www.fashionnova.com"` the same block printed `1 product sitemap(s), 37840 product URLs` and rows like `{'title': '00 Inferno Layered Mesh Jersey', 'brand': 'Fashion Nova', 'group_id': 'CLML508F', 'sku': 'CLML508F_Oliv - Network accessline 402
| `body_html` | `<p>Sun on your feet...` | description HTML | | `options` | `[{"name":"Size","position":1,"values":["5","6",...]}]` | single-variant products show `Title` / `Default Title` | | `images[]` | `{id, src, width, height, position - Network accessline 403
| `options` | `[{"name":"Size","position":1,"values":["5","6",...]}]` | single-variant products show `Title` / `Default Title` | | `images[]` | `{id, src, width, height, position, variant_ids}` | `src` is absolute `https://cdn.shopify.com/. - Network accessline 404
| `images[]` | `{id, src, width, height, position, variant_ids}` | `src` is absolute `https://cdn.shopify.com/...` | - Network accessline 435
- `/products.json` on headless stores: fashionnova.com 404 (Hydrogen/Oxygen), gymshark.com 403 from CloudFront. The in-browser `fetch('/products.json')` returned the same 404/403, so the browser is not a workaround there; use JSON-LD.
agent-workspace/domain-skills/slack/files.md
- Network accessline 22
so `files.list?user=<USERID>` can come back empty for the file you're after. Use `search.files?query=<filename>` to resolve real per-file IDs. - Raw bytes live at `https://files.slack.com/files-pri/<TEAMID>-<FILEID>/<name>` and need - Network accessline 23
`search.files?query=<filename>` to resolve real per-file IDs. - Raw bytes live at `https://files.slack.com/files-pri/<TEAMID>-<FILEID>/<name>` and need cookie auth. - Network accessline 24
- Raw bytes live at `https://files.slack.com/files-pri/<TEAMID>-<FILEID>/<name>` and need
agent-workspace/domain-skills/smartlead/mailbox-warmup.md
- Network accessline 5
- Application: `https://app.smartlead.ai/`.
agent-workspace/domain-skills/sofascore/scraping.md
agent-workspace/domain-skills/soundcloud/scraping.md
- Network accessline 10
`https://soundcloud.com/oembed?url=<resource_url>&format=json` - Network accessline 21
Works for: - https://soundcloud.com/{user}/{track-slug} - Network accessline 22
- https://soundcloud.com/{user}/{track-slug} - Network accessline 23
- https://soundcloud.com/{user}/sets/{playlist-slug} - Network accessline 24
- https://soundcloud.com/{user} - Network accessline 25
""" url = f"https://soundcloud.com/oembed?url={resource_url}&format=json" return json.loads(http_get(url)) - Network accessline 26
url = f"https://soundcloud.com/oembed?url={resource_url}&format=json" - Network accessline 29
# Track track = soundcloud_oembed("https://soundcloud.com/forss/flickermood") - Network accessline 30
track = soundcloud_oembed("https://soundcloud.com/forss/flickermood") - Network accessline 33
# "type": "rich", # "provider_name": "SoundCloud", # "provider_url": "https://soundcloud.com", - Network accessline 34
# "provider_name": "SoundCloud", # "provider_url": "https://soundcloud.com", # "height": 400, - Network accessline 35
# "provider_url": "https://soundcloud.com", - Network accessline 38
# "title": "Flickermood by Forss", # "description": "From the Soulhack album...", # "thumbnail_url": "https://i1.sndcdn.com/artworks-000067273316-smsiqx-t500x500.jpg", - Network accessline 39
# "description": "From the Soulhack album...", # "thumbnail_url": "https://i1.sndcdn.com/artworks-000067273316-smsiqx-t500x500.jpg", # "html": "<iframe width=\"100%\" height=\"400\" scrolling=\"no\" frameborder=\"no\" src=\"https://w. - Network accessline 40
# "thumbnail_url": "https://i1.sndcdn.com/artworks-000067273316-smsiqx-t500x500.jpg", - Network accessline 41
# "html": "<iframe width=\"100%\" height=\"400\" scrolling=\"no\" frameborder=\"no\" src=\"https://w.soundcloud.com/player/?visual=true&url=...\">", - Network accessline 42
# "author_name": "Forss", # "author_url": "https://soundcloud.com/forss" # } - Network accessline 43
# "author_url": "https://soundcloud.com/forss" - Network accessline 46
# Playlist/set pl = soundcloud_oembed("https://soundcloud.com/forss/sets/soulhack") - Network accessline 47
pl = soundcloud_oembed("https://soundcloud.com/forss/sets/soulhack") - Network accessline 50
# User profile user = soundcloud_oembed("https://soundcloud.com/forss") - Network accessline 51
user = soundcloud_oembed("https://soundcloud.com/forss") - Network accessline 93
# Track page — hydration key is 'sound' track = get_hydration_by_type("https://soundcloud.com/forss/flickermood", "sound") - Network accessline 94
track = get_hydration_by_type("https://soundcloud.com/forss/flickermood", "sound") - Network accessline 100
# track['genre'] = "Electronic" # track['created_at'] = "2007-09-22T14:45:46Z" # track['artwork_url'] = "https://i1.sndcdn.com/artworks-000067273316-smsiqx-large.jpg" - Network accessline 101
# track['created_at'] = "2007-09-22T14:45:46Z" # track['artwork_url'] = "https://i1.sndcdn.com/artworks-000067273316-smsiqx-large.jpg" # track['waveform_url'] = "https://wave.sndcdn.com/cWHNerOLlkUq_m.json" - Network accessline 102
# track['artwork_url'] = "https://i1.sndcdn.com/artworks-000067273316-smsiqx-large.jpg" - Network accessline 103
# track['waveform_url'] = "https://wave.sndcdn.com/cWHNerOLlkUq_m.json" - Network accessline 112
# User page — hydration key is 'user' user = get_hydration_by_type("https://soundcloud.com/forss", "user") - Network accessline 113
user = get_hydration_by_type("https://soundcloud.com/forss", "user") - Network accessline 126
# Playlist/set page — hydration key is 'playlist' playlist = get_hydration_by_type("https://soundcloud.com/forss/sets/soulhack", "playlist") - Network accessline 127
playlist = get_hydration_by_type("https://soundcloud.com/forss/sets/soulhack", "playlist") - Network accessline 158
def get_client_id(page_url="https://soundcloud.com"): - Network accessline 173
params['client_id'] = CLIENT_ID qs = "&".join(f"{k}={v}" for k, v in params.items()) return json.loads(http_get(f"https://api-v2.soundcloud.com/{path}?{qs}")) - Network accessline 175
return json.loads(http_get(f"https://api-v2.soundcloud.com/{path}?{qs}")) - Network accessline 181
# Resolve a permalink URL to get its resource with full metadata track = sc_api("resolve", url="https://soundcloud.com/forss/flickermood") - Network accessline 182
track = sc_api("resolve", url="https://soundcloud.com/forss/flickermood") - Network accessline 185
user = sc_api("resolve", url="https://soundcloud.com/forss") - Network accessline 265
# Waveform URL comes from track['waveform_url'] waveform_url = "https://wave.sndcdn.com/cWHNerOLlkUq_m.json" - Network accessline 266
waveform_url = "https://wave.sndcdn.com/cWHNerOLlkUq_m.json" - Network accessline 296
download_count int artwork_url str e.g. .../artworks-...-large.jpg (replace 'large' with 't500x500' for 500px) waveform_url str https://wave.sndcdn.com/....json - Network accessline 297
artwork_url str e.g. .../artworks-...-large.jpg (replace 'large' with 't500x500' for 500px) waveform_url str https://wave.sndcdn.com/....json permalink str Slug (e.g. "flickermood") - Network accessline 298
waveform_url str https://wave.sndcdn.com/....json
agent-workspace/domain-skills/spotify/scraping.md
- Network accessline 10
`https://open.spotify.com/oembed?url=<resource_url>` - Network accessline 22
resource_id: Spotify ID (22-char alphanumeric) """ resource_url = f"https://open.spotify.com/{resource_type}/{resource_id}" - Network accessline 23
""" resource_url = f"https://open.spotify.com/{resource_type}/{resource_id}" url = f"https://open.spotify.com/oembed?url={resource_url}" - Network accessline 24
resource_url = f"https://open.spotify.com/{resource_type}/{resource_id}" - Network accessline 25
url = f"https://open.spotify.com/oembed?url={resource_url}" - Network accessline 31
# { # "title": "Never Gonna Give You Up", # "thumbnail_url": "https://image-cdn-ak.spotifycdn.com/image/ab67616100005174...", - Network accessline 32
# "title": "Never Gonna Give You Up", # "thumbnail_url": "https://image-cdn-ak.spotifycdn.com/image/ab67616100005174...", # "thumbnail_width": 320, - Network accessline 33
# "thumbnail_url": "https://image-cdn-ak.spotifycdn.com/image/ab67616100005174...", - Network accessline 35
# "thumbnail_height": 320, # "type": "rich", # "html": "<iframe ...src=\"https://open.spotify.com/embed/track/4PTG3Z6...\"...>", - Network accessline 36
# "type": "rich", # "html": "<iframe ...src=\"https://open.spotify.com/embed/track/4PTG3Z6...\"...>", # "iframe_url": "https://open.spotify.com/embed/track/4PTG3Z6ehGkBFwjybzWkR8?utm_source=oembed", - Network accessline 37
# "html": "<iframe ...src=\"https://open.spotify.com/embed/track/4PTG3Z6...\"...>", - Network accessline 38
# "iframe_url": "https://open.spotify.com/embed/track/4PTG3Z6ehGkBFwjybzWkR8?utm_source=oembed", - Network accessline 41
# "version": "1.0", # "provider_name": "Spotify", # "provider_url": "https://spotify.com" - Network accessline 42
# "provider_name": "Spotify", # "provider_url": "https://spotify.com" # } - Network accessline 43
# "provider_url": "https://spotify.com" - Network accessline 72
def fetch_oembed(tid): url = f"https://open.spotify.com/oembed?url=https://open.spotify.com/track/{tid}" - Network accessline 73
url = f"https://open.spotify.com/oembed?url=https://open.spotify.com/track/{tid}" - Network accessline 96
def scrape_track(track_id): url = f"https://open.spotify.com/track/{track_id}" - Network accessline 97
url = f"https://open.spotify.com/track/{track_id}" - Network accessline 133
# "title": "Never Gonna Give You Up", # "artist": "Rick Astley", # "artist_urls": ["https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt"], - Network accessline 134
# "artist": "Rick Astley", # "artist_urls": ["https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt"], # "album_url": "https://open.spotify.com/album/6eUW0wxWtzkFdaEFsTJto6", - Network accessline 135
# "artist_urls": ["https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt"], - Network accessline 136
# "album_url": "https://open.spotify.com/album/6eUW0wxWtzkFdaEFsTJto6", - Network accessline 138
# "duration_s": 214, # "release_date": "1987-11-12", # "cover_art": "https://i.scdn.co/image/ab67616d0000b27315ebbedaacef61af244262a8", - Network accessline 139
# "release_date": "1987-11-12", # "cover_art": "https://i.scdn.co/image/ab67616d0000b27315ebbedaacef61af244262a8", # "audio_preview": "https://p.scdn.co/mp3-preview/b4c682084c3fd05538726d0a126b7e14b6e92c83", - Network accessline 140
# "cover_art": "https://i.scdn.co/image/ab67616d0000b27315ebbedaacef61af244262a8", - Network accessline 141
# "audio_preview": "https://p.scdn.co/mp3-preview/b4c682084c3fd05538726d0a126b7e14b6e92c83", - Network accessline 142
# "spotify_url": "https://open.spotify.com/track/4PTG3Z6ehGkBFwjybzWkR8", - Network accessline 150
def scrape_artist(artist_id): url = f"https://open.spotify.com/artist/{artist_id}" - Network accessline 151
url = f"https://open.spotify.com/artist/{artist_id}" - Network accessline 172
# "name": "Rick Astley", # "monthly_listeners": "Artist · 6.7M monthly listeners.", # "image": "https://i.scdn.co/image/ab6761610000e5ebe834a63a0cfa3c0f57a9a434", - Network accessline 173
# "monthly_listeners": "Artist · 6.7M monthly listeners.", # "image": "https://i.scdn.co/image/ab6761610000e5ebe834a63a0cfa3c0f57a9a434", # } - Network accessline 174
# "image": "https://i.scdn.co/image/ab6761610000e5ebe834a63a0cfa3c0f57a9a434", - Network accessline 182
`https://open.spotify.com/embed/{type}/{id}` returns a small Next.js SSR page. Its `__NEXT_DATA__` script tag contains a fully-parsed entity object. This is the only no-auth route that returns track listings for albums, playlists, and artis - Network accessline 191
Returns the entity dict from __NEXT_DATA__. """ url = f"https://open.spotify.com/embed/{resource_type}/{resource_id}" - Network accessline 192
""" url = f"https://open.spotify.com/embed/{resource_type}/{resource_id}" html = http_get(url) - Network accessline 193
url = f"https://open.spotify.com/embed/{resource_type}/{resource_id}" - Network accessline 209
# "isPlayable": True, # "isExplicit": False, # "audioPreview": {"url": "https://p.scdn.co/mp3-preview/b4c682..."}, - Network accessline 210
# "isExplicit": False, # "audioPreview": {"url": "https://p.scdn.co/mp3-preview/b4c682..."}, # "visualIdentity": { - Network accessline 211
# "audioPreview": {"url": "https://p.scdn.co/mp3-preview/b4c682..."}, - Network accessline 212
# "visualIdentity": { # "image": [ # {"url": "https://image-cdn-fa.spotifycdn.com/image/ab67616d00001e02...", "maxWidth": 300, "maxHeight": 300}, - Network accessline 213
# "image": [ # {"url": "https://image-cdn-fa.spotifycdn.com/image/ab67616d00001e02...", "maxWidth": 300, "maxHeight": 300}, # {"url": "https://image-cdn-fa.spotifycdn.com/image/ab67616d000048...", "maxWidth": 64, "maxHeight - Network accessline 214
# {"url": "https://image-cdn-fa.spotifycdn.com/image/ab67616d00001e02...", "maxWidth": 300, "maxHeight": 300}, - Network accessline 215
# {"url": "https://image-cdn-fa.spotifycdn.com/image/ab67616d000048...", "maxWidth": 64, "maxHeight": 64}, - Network accessline 216
# {"url": "https://image-cdn-fa.spotifycdn.com/image/ab67616d0000b27...", "maxWidth": 640, "maxHeight": 640}, - Network accessline 228
# "duration": 107426, # "isPlayable": True, # "audioPreview": {"url": "https://p.scdn.co/mp3-preview/d03c37..."}, - Network accessline 229
# "isPlayable": True, # "audioPreview": {"url": "https://p.scdn.co/mp3-preview/d03c37..."}, # "entityType": "track" - Network accessline 230
# "audioPreview": {"url": "https://p.scdn.co/mp3-preview/d03c37..."}, - Network accessline 251
def get_embed_token(resource_type="track", resource_id="4PTG3Z6ehGkBFwjybzWkR8"): """Extract the anonymous access token from an embed page.""" url = f"https://open.spotify.com/embed/{resource_type}/{resource_id}" - Network accessline 252
"""Extract the anonymous access token from an embed page.""" url = f"https://open.spotify.com/embed/{resource_type}/{resource_id}" html = http_get(url) - Network accessline 253
url = f"https://open.spotify.com/embed/{resource_type}/{resource_id}" - Access to secretsline 259
[Credential-related source omitted] - Access to secretsline 266
[Credential-related source omitted] - Network accessline 293
goto_url("https://open.spotify.com/search") - Network accessline 307
| Resource | URL pattern | ID format | |-----------|------------------------------------------------|-------------------| | Track | `https://open.spotify.com/track/{id}` | 22-char alp - Network accessline 308
|-----------|------------------------------------------------|-------------------| | Track | `https://open.spotify.com/track/{id}` | 22-char alphanum | | Album | `https://open.spotify.com/album/{id}` | 22-char alp - Network accessline 309
| Track | `https://open.spotify.com/track/{id}` | 22-char alphanum | - Network accessline 310
| Album | `https://open.spotify.com/album/{id}` | 22-char alphanum | - Network accessline 311
| Artist | `https://open.spotify.com/artist/{id}` | 22-char alphanum | - Network accessline 312
| Playlist | `https://open.spotify.com/playlist/{id}` | 22-char alphanum | - Network accessline 313
| oEmbed | `https://open.spotify.com/oembed?url={resource_url}` | any of above | - Network accessline 314
| Embed | `https://open.spotify.com/embed/{type}/{id}` | same ID | - Network accessline 332
- **Embed page for episodes**: The embed page SSR for episodes does not include `state.data.entity` in the expected structure — parse defensively. - **Anonymous token rate limiting**: The access token from embed pages is valid but severely - Network accessline 333
- **Anonymous token rate limiting**: The access token from embed pages is valid but severely rate-limited for `api.spotify.com/v1`. Observed `Retry-After: 79561` (~22 hours) after 2-3 rapid API calls. Use embed `__NEXT_DATA__` data instead - Network accessline 334
[Credential-related source omitted] - Access to secretsline 334
[Credential-related source omitted]
agent-workspace/domain-skills/stackoverflow/scraping.md
- Network accessline 3
`https://stackoverflow.com` — all public read-only data is available via the Stack Exchange API v2.3. No auth, no browser required for any read operation. API is fast, returns gzip-compressed JSON, and works transparently with `http_get`. - Network accessline 40
import json data = json.loads(http_get("https://api.stackexchange.com/2.3/info?site=stackoverflow")) - Network accessline 41
data = json.loads(http_get("https://api.stackexchange.com/2.3/info?site=stackoverflow")) - Network accessline 74
try: data = json.loads(http_get("https://api.stackexchange.com/2.3/questions?site=stackoverflow&pagesize=1")) - Network accessline 75
data = json.loads(http_get("https://api.stackexchange.com/2.3/questions?site=stackoverflow&pagesize=1")) - Network accessline 89
# WITHOUT filter=withbody — body field is ABSENT data = json.loads(http_get("https://api.stackexchange.com/2.3/questions?order=desc&sort=votes&tagged=python&site=stackoverflow&pagesize=1")) - Network accessline 90
data = json.loads(http_get("https://api.stackexchange.com/2.3/questions?order=desc&sort=votes&tagged=python&site=stackoverflow&pagesize=1")) - Network accessline 98
# WITH filter=withbody — body field is PRESENT data = json.loads(http_get("https://api.stackexchange.com/2.3/questions?order=desc&sort=votes&tagged=python&site=stackoverflow&pagesize=1&filter=withbody")) - Network accessline 99
data = json.loads(http_get("https://api.stackexchange.com/2.3/questions?order=desc&sort=votes&tagged=python&site=stackoverflow&pagesize=1&filter=withbody")) - Network accessline 101
print("Has body:", 'body' in q) # True print("Body preview:", q['body'][:60]) # '<p>What functionality does the <a href="https://do...' - Network accessline 103
# '<p>What functionality does the <a href="https://do...' - Network accessline 120
data = json.loads(http_get("https://api.stackexchange.com/2.3/questions/231767?site=stackoverflow&filter=withbody")) - Network accessline 152
import json, html data = json.loads(http_get( "https://api.stackexchange.com/2.3/questions" - Network accessline 153
data = json.loads(http_get( "https://api.stackexchange.com/2.3/questions" "?order=desc&sort=votes&tagged=python&site=stackoverflow&pagesize=5&filter=withbody" - Network accessline 154
"https://api.stackexchange.com/2.3/questions" - Network accessline 173
import json data = json.loads(http_get( "https://api.stackexchange.com/2.3/questions/231767/answers" - Network accessline 174
data = json.loads(http_get( "https://api.stackexchange.com/2.3/questions/231767/answers" "?order=desc&sort=votes&site=stackoverflow&filter=withbody&pagesize=3" - Network accessline 175
"https://api.stackexchange.com/2.3/questions/231767/answers" - Network accessline 194
import json data = json.loads(http_get( "https://api.stackexchange.com/2.3/questions/231767;419163;394809" - Network accessline 195
data = json.loads(http_get( "https://api.stackexchange.com/2.3/questions/231767;419163;394809" "?site=stackoverflow&filter=withbody" - Network accessline 196
"https://api.stackexchange.com/2.3/questions/231767;419163;394809" - Network accessline 214
# search/advanced: keyword in body OR title, filtered by tag, sorted by relevance data = json.loads(http_get( "https://api.stackexchange.com/2.3/search/advanced" - Network accessline 215
data = json.loads(http_get( "https://api.stackexchange.com/2.3/search/advanced" "?q=asyncio+event+loop&tagged=python&site=stackoverflow&pagesize=5&order=desc&sort=relevance" - Network accessline 216
"https://api.stackexchange.com/2.3/search/advanced" - Network accessline 224
# search: title-only keyword search via intitle= data = json.loads(http_get( "https://api.stackexchange.com/2.3/search" - Network accessline 225
data = json.loads(http_get( "https://api.stackexchange.com/2.3/search" "?intitle=asyncio+event+loop&site=stackoverflow&pagesize=5&order=desc&sort=relevance" - Network accessline 226
"https://api.stackexchange.com/2.3/search" - Network accessline 238
# Basic user info user = json.loads(http_get("https://api.stackexchange.com/2.3/users/1?site=stackoverflow")) - Network accessline 239
user = json.loads(http_get("https://api.stackexchange.com/2.3/users/1?site=stackoverflow")) - Network accessline 248
# Timeline (badge, question, answer events) data = json.loads(http_get("https://api.stackexchange.com/2.3/users/1/timeline?site=stackoverflow&pagesize=5")) - Network accessline 249
data = json.loads(http_get("https://api.stackexchange.com/2.3/users/1/timeline?site=stackoverflow&pagesize=5")) - Network accessline 253
# User's top answers answers = json.loads(http_get("https://api.stackexchange.com/2.3/users/1/answers?site=stackoverflow&pagesize=5&order=desc&sort=votes")) - Network accessline 254
answers = json.loads(http_get("https://api.stackexchange.com/2.3/users/1/answers?site=stackoverflow&pagesize=5&order=desc&sort=votes")) - Network accessline 258
# User's questions questions = json.loads(http_get("https://api.stackexchange.com/2.3/users/1/questions?site=stackoverflow&pagesize=3&order=desc&sort=votes")) - Network accessline 259
questions = json.loads(http_get("https://api.stackexchange.com/2.3/users/1/questions?site=stackoverflow&pagesize=3&order=desc&sort=votes")) - Network accessline 269
import json data = json.loads(http_get( "https://api.stackexchange.com/2.3/questions/231767/comments" - Network accessline 270
data = json.loads(http_get( "https://api.stackexchange.com/2.3/questions/231767/comments" "?site=stackoverflow&pagesize=5&order=desc&sort=creation&filter=withbody" - Network accessline 271
"https://api.stackexchange.com/2.3/questions/231767/comments" - Network accessline 284
import json related = json.loads(http_get( "https://api.stackexchange.com/2.3/questions/231767/related?site=stackoverflow&pagesize=5" - Network accessline 285
related = json.loads(http_get( "https://api.stackexchange.com/2.3/questions/231767/related?site=stackoverflow&pagesize=5" )) - Network accessline 286
"https://api.stackexchange.com/2.3/questions/231767/related?site=stackoverflow&pagesize=5" - Network accessline 297
import json tags = json.loads(http_get("https://api.stackexchange.com/2.3/tags?order=desc&sort=popular&site=stackoverflow&pagesize=5")) - Network accessline 298
tags = json.loads(http_get("https://api.stackexchange.com/2.3/tags?order=desc&sort=popular&site=stackoverflow&pagesize=5")) - Network accessline 328
questions = fetch_all_pages( "https://api.stackexchange.com/2.3/questions?order=desc&sort=votes" - Network accessline 329
"https://api.stackexchange.com/2.3/questions?order=desc&sort=votes" - Network accessline 346
def fetch_top_answer(qid): data = json.loads(http_get( f"https://api.stackexchange.com/2.3/questions/{qid}/answers" - Network accessline 347
data = json.loads(http_get( f"https://api.stackexchange.com/2.3/questions/{qid}/answers" "?order=desc&sort=votes&site=stackoverflow&filter=withbody&pagesize=1" - Network accessline 348
f"https://api.stackexchange.com/2.3/questions/{qid}/answers" - Network accessline 378
import re, html as htmllib headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"} page = http_get("https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python", headers=headers - Network accessline 379
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"} page = http_get("https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python", headers=headers) print("HTML length:", len - Network accessline 380
page = http_get("https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python", headers=headers)
agent-workspace/domain-skills/steam/scraping.md
- Network accessline 18
""" resp = http_get( f"https://store.steampowered.com/api/appdetails?appids={appid}&cc={cc}" - Network accessline 19
resp = http_get( f"https://store.steampowered.com/api/appdetails?appids={appid}&cc={cc}" ) - Network accessline 20
f"https://store.steampowered.com/api/appdetails?appids={appid}&cc={cc}" - Network accessline 35
# game["about_the_game"] -> HTML # game["detailed_description"]-> HTML # game["website"] -> "https://www.thewitcher.com/witcher3" - Network accessline 36
# game["detailed_description"]-> HTML # game["website"] -> "https://www.thewitcher.com/witcher3" # game["header_image"] -> URL to 460x215px header image - Network accessline 37
# game["website"] -> "https://www.thewitcher.com/witcher3" - Network accessline 43
# game["publishers"] -> ["CD PROJEKT RED"] # game["platforms"] -> {"windows": True, "mac": False, "linux": False} # game["metacritic"] -> {"score": 93, "url": "https://www.metacritic.com/..."} - Network accessline 44
# game["platforms"] -> {"windows": True, "mac": False, "linux": False} # game["metacritic"] -> {"score": 93, "url": "https://www.metacritic.com/..."} # game["genres"] -> [{"id": "3", "description": "RPG"}] - Network accessline 45
# game["metacritic"] -> {"score": 93, "url": "https://www.metacritic.com/..."} - Network accessline 125
def fetch_game(appid, cc="US"): resp = http_get( f"https://store.steampowered.com/api/appdetails?appids={appid}&cc={cc}" - Network accessline 126
resp = http_get( f"https://store.steampowered.com/api/appdetails?appids={appid}&cc={cc}" ) - Network accessline 127
f"https://store.steampowered.com/api/appdetails?appids={appid}&cc={cc}" - Network accessline 149
## Partial field fetch (filters=) - Network accessline 154
# Price only (tiny response) resp = http_get("https://store.steampowered.com/api/appdetails?appids=292030&filters=price_overview") - Network accessline 155
resp = http_get("https://store.steampowered.com/api/appdetails?appids=292030&filters=price_overview") - Network accessline 159
# Basic metadata (no price, no media) resp = http_get("https://store.steampowered.com/api/appdetails?appids=292030&filters=basic") - Network accessline 160
resp = http_get("https://store.steampowered.com/api/appdetails?appids=292030&filters=basic") - Network accessline 166
# Multiple filters comma-separated resp = http_get("https://store.steampowered.com/api/appdetails?appids=292030&filters=screenshots,price_overview") - Network accessline 167
resp = http_get("https://store.steampowered.com/api/appdetails?appids=292030&filters=screenshots,price_overview") - Network accessline 251
GET https://store.steampowered.com/app/292030/ - Network accessline 252
-> 302 -> https://store.steampowered.com/agecheck/app/292030/ - Network accessline 260
def get_store_page(appid): """Fetch game store HTML page, bypassing age gate.""" req = urllib.request.Request( - Network accessline 261
"""Fetch game store HTML page, bypassing age gate.""" req = urllib.request.Request( f"https://store.steampowered.com/app/{appid}/", - Network accessline 262
req = urllib.request.Request( - Network accessline 263
f"https://store.steampowered.com/app/{appid}/", - Network accessline 267
} ) with urllib.request.urlopen(req, timeout=15) as r: - Network accessline 268
) with urllib.request.urlopen(req, timeout=15) as r: html = r.read().decode("utf-8", errors="replace") - Network accessline 269
with urllib.request.urlopen(req, timeout=15) as r: - Network accessline 293
q = urllib.parse.quote(term) resp = http_get( f"https://store.steampowered.com/api/storesearch/?term={q}&l={lang}&cc={cc}" - Network accessline 294
resp = http_get( f"https://store.steampowered.com/api/storesearch/?term={q}&l={lang}&cc={cc}" ) - Network accessline 295
f"https://store.steampowered.com/api/storesearch/?term={q}&l={lang}&cc={cc}" - Network accessline 302
# {"type": "app", "name": "The Witcher 3: Wild Hunt", "id": 292030, # "price": {"currency": "USD", "initial": 3999, "final": 3999}, # "tiny_image": "https://...", "metascore": "93", - Network accessline 303
# "price": {"currency": "USD", "initial": 3999, "final": 3999}, # "tiny_image": "https://...", "metascore": "93", # "platforms": {"windows": True, "mac": False, "linux": False}, - Network accessline 304
# "tiny_image": "https://...", "metascore": "93", - Network accessline 341
encoded_cursor = urllib.parse.quote(cursor) resp = http_get( f"https://store.steampowered.com/appreviews/{appid}" - Network accessline 342
resp = http_get( f"https://store.steampowered.com/appreviews/{appid}" f"?json=1&num_per_page={num}&language={language}" - Network accessline 343
f"https://store.steampowered.com/appreviews/{appid}" - Network accessline 418
for _ in range(max_pages): resp = http_get( f"https://store.steampowered.com/appreviews/{appid}" - Network accessline 419
resp = http_get( f"https://store.steampowered.com/appreviews/{appid}" f"?json=1&num_per_page={num_per_page}&language={language}" - Network accessline 420
f"https://store.steampowered.com/appreviews/{appid}" f"?json=1&num_per_page={num_per_page}&language={language}" f"&filter=recent&cursor={urllib.parse.quote(cursor)}" - Network accessline 445
data = json.loads(http_get("https://store.steampowered.com/api/featured/")) - Network accessline 472
data = json.loads(http_get("https://store.steampowered.com/api/featuredcategories/")) - Network accessline 510
def get_all_store_appids(): data = json.loads(http_get("https://store.steampowered.com/api/featuredcategories/")) - Network accessline 511
data = json.loads(http_get("https://store.steampowered.com/api/featuredcategories/")) - Access to secretsline 557
[Credential-related source omitted]
agent-workspace/domain-skills/stripe/account-sandboxes.md
- Network accessline 5
- The account's classic Test mode keeps the main account ID. Its current-account routes use `https://dashboard.stripe.com/test/...`. Account-specific links can include `/{account_id}/test/...`. - Network accessline 12
1. Confirm the intended account in the account switcher and read its ID from account settings. 2. Open Test mode and its API keys page. Do not infer account identity from the URL alone. 3. Use the intended Test mode secret key for an authen - Network accessline 13
[Credential-related source omitted] - Network accessline 14
3. Use the intended Test mode secret key for an authenticated `GET https://api.stripe.com/v1/account` request.
agent-workspace/domain-skills/substack/scraping.md
- Network accessline 30
`GET https://{subdomain}.substack.com/api/v1/posts?limit=N&offset=N` - Network accessline 41
Args: publication_url: Base URL of the publication, e.g. 'https://www.slowboring.com' or - Network accessline 42
publication_url: Base URL of the publication, e.g. 'https://www.slowboring.com' or 'https://simonwillison.substack.com' - Network accessline 43
'https://www.slowboring.com' or - Network accessline 44
'https://simonwillison.substack.com' - Network accessline 71
posts = substack_list_posts("https://www.slowboring.com", limit=10) - Network accessline 75
# "subtitle": "Plus ties, Mamdani, the Obama legacy, and fundraising's diminishing returns", # "slug": "what-to-make-of-the-generic-ballot", # "url": "https://www.slowboring.com/p/what-to-make-of-the-generic-ballot", - Network accessline 76
# "slug": "what-to-make-of-the-generic-ballot", # "url": "https://www.slowboring.com/p/what-to-make-of-the-generic-ballot", # "post_date": "2026-04-24T10:03:26.581Z", - Network accessline 77
# "url": "https://www.slowboring.com/p/what-to-make-of-the-generic-ballot", - Network accessline 115
`GET https://{subdomain}.substack.com/api/v1/posts/{slug}` - Network accessline 157
post = substack_get_post( "https://www.slowboring.com", - Network accessline 158
"https://www.slowboring.com", - Network accessline 182
`GET https://{subdomain}.substack.com/api/v1/post/{post_id}/comments?limit=N` - Network accessline 219
comments = substack_get_comments("https://www.slowboring.com", 194950421, limit=10) - Network accessline 237
`GET https://{subdomain}.substack.com/feed` - Network accessline 273
feed = substack_rss("https://www.slowboring.com", max_items=5) - Network accessline 275
# { # "title": "Sunday Mailbag + Thread", # "link": "https://www.slowboring.com/p/sunday-mailbag-thread-48b", - Network accessline 276
# "title": "Sunday Mailbag + Thread", # "link": "https://www.slowboring.com/p/sunday-mailbag-thread-48b", # "pub_date": "Sun, 26 Apr 2026 17:02:04 GMT", - Network accessline 277
# "link": "https://www.slowboring.com/p/sunday-mailbag-thread-48b", - Network accessline 292
# Format 1: native subdomain (older or simpler publications) "https://simonwillison.substack.com" - Network accessline 293
"https://simonwillison.substack.com" - Network accessline 295
# Format 2: custom domain (larger publications, purchased domain) "https://www.slowboring.com" # Matthew Yglesias — Slow Boring - Network accessline 296
"https://www.slowboring.com" # Matthew Yglesias — Slow Boring - Network accessline 297
"https://unchartedterritories.tomaspueyo.com" # Tomas Pueyo - Network accessline 306
If you only know a publication's Substack handle (e.g., `matthewyglesias`), the canonical subdomain URL is `https://matthewyglesias.substack.com`. Custom - Network accessline 307
the canonical subdomain URL is `https://matthewyglesias.substack.com`. Custom
agent-workspace/domain-skills/target/scraping.md
- Network accessline 22
CATEGORY_URL = "https://www.target.com/c/air-fryers-kitchen-appliances-dining/-/N-ncrpx" # any /c/<slug>/-/N-<id> page - Network accessline 25
if not re.fullmatch(r"https://www\.target\.com/c/[^?#]+/-/N-[0-9A-Za-z]+", CATEGORY_URL): - Network accessline 26
raise SystemExit("CATEGORY_URL must be https://www.target.com/c/<slug>/-/N-<id> with no query string") - Possible obfuscationline 37
return json.loads(base64.b64decode(r["body"]) if r.get("base64Encoded") else r["body"]) - Network accessline 175
"rating": 4.01, "rating_count": 761, "url": "https://www.target.com/p/cuisinart-1800w-air-fryer-toaster-oven-stainless-steel-finish/-/A-92969684", - Network accessline 176
"rating_count": 761, "url": "https://www.target.com/p/cuisinart-1800w-air-fryer-toaster-oven-stainless-steel-finish/-/A-92969684", "ship_status": "IN_STOCK", - Network accessline 177
"url": "https://www.target.com/p/cuisinart-1800w-air-fryer-toaster-oven-stainless-steel-finish/-/A-92969684", - Network accessline 197
page = http_get(f"https://www.target.com/p/-/A-{TCIN}", headers={ - Network accessline 272
URL = f"https://www.target.com/p/-/A-{TCIN}" - Network accessline 342
| Rating | `ratings_and_reviews.statistics.rating.average` | `4.01`; falls back to `parent.ratings_and_reviews`; `None` on 85 of 270 air fryer rows (unrated) | | Rating count | `ratings_and_reviews.statistics.rating.count` | `761` (star rat - Network accessline 343
| Rating count | `ratings_and_reviews.statistics.rating.count` | `761` (star ratings; written reviews are fewer, see PDP `review_count`) | | URL | `item.enrichment.buy_url` | absolute `https://www.target.com/p/<slug>/-/A-<tcin>` | | Shippin - Network accessline 344
| URL | `item.enrichment.buy_url` | absolute `https://www.target.com/p/<slug>/-/A-<tcin>` | - Network accessline 372
- **Search pages (`/s?searchTerm=...`)**: disallowed for all user agents by robots.txt, so this skill does not use them. Start from a category page (block 1) or from known TCINs or product URLs (blocks 2 and 3). - **Plain HTTP category page - Network accessline 373
- **Plain HTTP category page**: `https://www.target.com/c/air-fryers-kitchen-appliances-dining/-/N-ncrpx` returned 200 and a 164 KB page whose `__NEXT_DATA__` held no products (6 `/p/` links in the whole HTML); the grid is filled client-sid
agent-workspace/domain-skills/tasksquad-ai/agents.md
- Network accessline 8
https://tasksquad.ai/dashboard/agents # Agents list for current project
agent-workspace/domain-skills/tasksquad-ai/auth.md
agent-workspace/domain-skills/tasksquad-ai/tasks.md
agent-workspace/domain-skills/tcgplayer/scraping.md
- Network accessline 28
raise ValueError("line must be a productLineUrlName like 'magic' and q must be non-empty") qs = urllib.parse.urlencode({"productLineName": line, "q": q, "view": "grid", "page": page}) url = f"https://www.tcgplayer.com/search/{line}/ - Network accessline 29
qs = urllib.parse.urlencode({"productLineName": line, "q": q, "view": "grid", "page": page}) url = f"https://www.tcgplayer.com/search/{line}/product?{qs}" if "seller=" in url: # robots.txt: Disallow: /search/*/product?seller=* - Network accessline 30
url = f"https://www.tcgplayer.com/search/{line}/product?{qs}" - Possible obfuscationline 67
data = json.loads(base64.b64decode(b["body"]) if b.get("base64Encoded") else b["body"]) - Network accessline 88
"listings": int(it.get("totalListings") or 0), "sealed": it.get("sealed"), "url": f"https://www.tcgplayer.com/product/{pid}", - Network accessline 89
"sealed": it.get("sealed"), "url": f"https://www.tcgplayer.com/product/{pid}", } - Network accessline 90
"url": f"https://www.tcgplayer.com/product/{pid}", - Network accessline 138
magic 'lightning bolt' page 2: 24 products, 22 new, total=104 46 products of 104 status: truncated_max_pages {"product_id": 1479, "name": "Lightning Bolt", "set": "Revised Edition", "set_code": "3ED", "rarity": "Common", "number": null, "ma - Network accessline 139
46 products of 104 status: truncated_max_pages {"product_id": 1479, "name": "Lightning Bolt", "set": "Revised Edition", "set_code": "3ED", "rarity": "Common", "number": null, "market_price": 2.84, "lowest_price": 0.7, "lowest_price_with_shi - Network accessline 140
{"product_id": 1479, "name": "Lightning Bolt", "set": "Revised Edition", "set_code": "3ED", "rarity": "Common", "number": null, "market_price": 2.84, "lowest_price": 0.7, "lowest_price_with_shipping": 0.7, "listings": 606, "sealed": false, - Network accessline 141
{"product_id": 719091, "name": "Lightning Bolt", "set": "Commander: Foundations", "set_code": "FDC", "rarity": "Uncommon", "number": "163", "market_price": 0.85, "lowest_price": 0.39, "lowest_price_with_shipping": 0.74, "listings": 51, "sea - Network accessline 142
{"product_id": 697344, "name": "Lightning Bolt", "set": "Commander: Marvel Super Heroes", "set_code": "MSC", "rarity": "Uncommon", "number": "806", "market_price": 0.89, "lowest_price": 0.79, "lowest_price_with_shipping": 0.79, "listings": - Network accessline 143
pokemon 'charizard ex' page 1: 24 products, 24 new, total=157 24 products of 157 status: truncated_max_pages {"product_id": 124025, "name": "M Charizard EX", "set": "XY - Evolutions", "set_code": "EVO", "rarity": "Ultra Rare", "number": "13 - Network accessline 144
24 products of 157 status: truncated_max_pages {"product_id": 124025, "name": "M Charizard EX", "set": "XY - Evolutions", "set_code": "EVO", "rarity": "Ultra Rare", "number": "13/108", "market_price": 38.27, "lowest_price": 6.54, "lowest_pr - Network accessline 145
{"product_id": 124025, "name": "M Charizard EX", "set": "XY - Evolutions", "set_code": "EVO", "rarity": "Ultra Rare", "number": "13/108", "market_price": 38.27, "lowest_price": 6.54, "lowest_price_with_shipping": 6.54, "listings": 239, "sea - Possible obfuscationline 201
got[r["kind"]] = (size, json.loads(base64.b64decode(b["body"]) if b.get("base64Encoded") else b["body"])) - Network accessline 237
} for s in sales.get("data") or []], "sales_meta": {k: sales.get(k) for k in ("totalResults", "nextPage")}, "url": f"https://www.tcgplayer.com/product/{pid}", - Network accessline 238
"sales_meta": {k: sales.get(k) for k in ("totalResults", "nextPage")}, "url": f"https://www.tcgplayer.com/product/{pid}", } - Network accessline 239
"url": f"https://www.tcgplayer.com/product/{pid}", - Network accessline 248
time.sleep(CRAWL_DELAY_S) drain_events() goto_url(f"https://www.tcgplayer.com/product/{int(pid)}") - Network accessline 249
drain_events() goto_url(f"https://www.tcgplayer.com/product/{int(pid)}") out.append(parse(int(pid), read_product(session, int(pid)))) - Network accessline 250
goto_url(f"https://www.tcgplayer.com/product/{int(pid)}") - Network accessline 266
{"product_id": 1479, "name": "Lightning Bolt", "set": "Revised Edition", "line": "Magic: The Gathering", "rarity": "Common", "market_price": 2.84, "median_price": 2.84, "lowest_price": 0.7, "lowest_price_with_shipping": 0.7, "listings_total - Network accessline 268
cheapest: [{"condition": "Heavily Played", "printing": "Normal", "language": "English", "price": 0.75, "shipping": 1.49, "quantity": 2, "seller_rating": 100.0, "seller_sales": "1401", "direct": false, "listing_type": "standard"}, {"conditio - Network accessline 269
latest sale: [{"date": "2026-10-31T13:06:45.887+00:00", "condition": "Lightly Played", "variant": "Normal", "price": 2.38, "shipping": 0.0, "quantity": 1}] {"product_id": 719091, "name": "Lightning Bolt", "set": "Commander: Foundations", "l - Network accessline 270
{"product_id": 719091, "name": "Lightning Bolt", "set": "Commander: Foundations", "line": "Magic: The Gathering", "rarity": "Uncommon", "market_price": 0.85, "median_price": 0.96, "lowest_price": 0.39, "lowest_price_with_shipping": 0.74, "l - Network accessline 272
cheapest: [{"condition": "Near Mint", "printing": "Normal", "language": "English", "price": 0.76, "shipping": 3.99, "quantity": 4, "seller_rating": 100.0, "seller_sales": "25000+", "direct": true, "listing_type": "standard"}, {"condition": - Network accessline 273
latest sale: [{"date": "2026-10-31T18:17:55.253+00:00", "condition": "Near Mint", "variant": "Normal", "price": 0.74, "shipping": 1.49, "quantity": 1}] {"product_id": 1032, "name": "Aspect of Wolf", "set": "Alpha Edition", "line": "Magic: T - Network accessline 274
{"product_id": 1032, "name": "Aspect of Wolf", "set": "Alpha Edition", "line": "Magic: The Gathering", "rarity": "Rare", "market_price": null, "median_price": null, "lowest_price": 375.0, "lowest_price_with_shipping": null, "listings_total"
agent-workspace/domain-skills/thetechgeeks/pricing.md
- Network accessline 3
`https://thetechgeeks.com` — Shopify Online Store 2.0, AU Ubiquiti reseller. Prices GST-inclusive ("All Prices Include Australian GST At 10%" in footer). - Network accessline 10
import json d = json.loads(http_get(f"https://thetechgeeks.com/products/{handle}.js")) - Network accessline 11
d = json.loads(http_get(f"https://thetechgeeks.com/products/{handle}.js")) - Network accessline 41
- `https://thetechgeeks.com/search?q=<SKU>` → scrape first `a[href*="/products/"]` link
agent-workspace/domain-skills/ticketmaster/scraping.md
- Network accessline 25
BASE = "https://www.ticketmaster.com" - Network accessline 27
# robots.txt, group "User-agent: *", Google-style matching: longest pattern wins, Allow wins a tie. # Read in the browser tab: plain urllib got HTTP 403 for robots.txt (curl got 200), and this skill does not change its UA. - Network accessline 28
# Read in the browser tab: plain urllib got HTTP 403 for robots.txt (curl got 200), and this skill does not change its UA. - Network accessline 286
search jazz: 40 of 3889 truncated_max_pages 2026-10-31 21:00 | Halloween with Sally Baby's Silver Dollars | Snug Harbor Jazz Bistro, New Orleans LA | https://www.ticketweb.com/event/halloween-with-sally-babys-silver-snug-harbor-jazz-bist - Network accessline 287
2026-10-31 21:00 | Halloween with Sally Baby's Silver Dollars | Snug Harbor Jazz Bistro, New Orleans LA | https://www.ticketweb.com/event/halloween-with-sally-babys-silver-snug-harbor-jazz-bistro-tickets/14410584 - Network accessline 288
2026-11-01 15:00 | Fresh Takes On Jazz: Ava Preston | Mickey's Black Box, Lititz PA | https://www.ticketmaster.com/fresh-takes-on-jazz-ava-preston-lititz-pennsylvania-11-01-2026/event/0200651B00735077 - Network accessline 289
2026-11-01 18:00 | Johnny Britt "You Are Beautiful" Tour | Humphreys Backstage Live, San Diego CA | https://www.ticketmaster.com/johnny-britt-you-are-beautiful-tour-san-diego-california-11-01-2026/event/0A0065159E4494E2 - Network accessline 290
discover concerts/Country 2026-11-07..2026-11-08: 40 of 108 truncated_max_pages 2026-11-06 20:00 | Saddle Up: Country Grammar | Diamondback Music Hall, Belleville MI | https://www.ticketweb.com/event/saddle-up-country-grammar-diamondback - Network accessline 291
2026-11-06 20:00 | Saddle Up: Country Grammar | Diamondback Music Hall, Belleville MI | https://www.ticketweb.com/event/saddle-up-country-grammar-diamondback-music-hall-tickets/14407284 - Network accessline 292
2026-11-07 12:30 | BACKSTAGE NASHVILLE! DAYTIME HIT SONGWRITERS SHOW featuring | 3rd and Lindsley, Nashville TN | https://www.ticketweb.com/event/backstage-nashville-daytime-hit-songwriters-3rd-and-lindsley-tickets/14637713 - Network accessline 293
discover chicago: 20 of 2425 truncated_max_pages | off-site: 10 slug date == local_date: 32 of 32 | date_display: Counter({'showDateTime': 100}) {"id": "0200651B00735077", "name": "Fresh Takes On Jazz: Ava Preston", "start_local": "2026-11- - Network accessline 294
slug date == local_date: 32 of 32 | date_display: Counter({'showDateTime': 100}) {"id": "0200651B00735077", "name": "Fresh Takes On Jazz: Ava Preston", "start_local": "2026-11-01T15:00", "status": "EventScheduled", "venue": "Mickey's Black - Network accessline 295
{"id": "0200651B00735077", "name": "Fresh Takes On Jazz: Ava Preston", "start_local": "2026-11-01T15:00", "status": "EventScheduled", "venue": "Mickey's Black Box", "address": "101 Rock Lititz Blvd, Lititz, PA, 17543", "performers": [], "av - Network accessline 296
list row said: 2026-11-01 15:00 | page says: 2026-11-01T15:00 {"id": "010064CB19BF6123", "name": "Huntertones", "start_local": "2026-11-01T19:30:00", "status": "EventScheduled", "venue": "Jimmy's Jazz and Blues Club", "address": "135 Congre - Network accessline 297
{"id": "010064CB19BF6123", "name": "Huntertones", "start_local": "2026-11-01T19:30:00", "status": "EventScheduled", "venue": "Jimmy's Jazz and Blues Club", "address": "135 Congress Street, Portsmouth, NH, 03801", "performers": ["Huntertones - Network accessline 298
list row said: 2026-11-01 19:30 | page says: 2026-11-01T19:30:00 {"id": "Z7r9jZ1AAZd8O", "name": "Jon Pardi w/ Alexandra Kay", "start_local": "2026-11-07T17:30", "status": "EventScheduled", "venue": "Round Rock Amp", "address": "3701 N IH 3 - Network accessline 299
{"id": "Z7r9jZ1AAZd8O", "name": "Jon Pardi w/ Alexandra Kay", "start_local": "2026-11-07T17:30", "status": "EventScheduled", "venue": "Round Rock Amp", "address": "3701 N IH 35, Round Rock, TX, 78665", "performers": [], "availability": null - Network accessline 346
- Plain `urllib` with its default User-Agent got HTTP 403 for `/robots.txt` (curl got 200), so the block reads robots.txt in the browser tab instead of changing its User-Agent.
agent-workspace/domain-skills/tiktok/upload.md
- Network accessline 3
URL: `https://www.tiktok.com/tiktokstudio/upload?from=upload&lang=en` (always append `&lang=en`)
agent-workspace/domain-skills/tradingview/scraping.md
- Network accessline 3
`https://www.tradingview.com` — charting platform with multiple internal REST APIs. Stock/crypto/forex screener and symbol search work without auth. Use `http_get` or raw `urllib` for all workflows except JS-rendered chart pages. - Network accessline 12
def tv_scan(payload, market="america"): data = json.dumps(payload).encode() req = urllib.request.Request( - Network accessline 13
data = json.dumps(payload).encode() req = urllib.request.Request( f"https://scanner.tradingview.com/{market}/scan", - Network accessline 14
req = urllib.request.Request( - Network accessline 15
f"https://scanner.tradingview.com/{market}/scan", - Network accessline 17
headers={"Content-Type": "application/json", "User-Agent": "Mozilla/5.0"} ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 18
) with urllib.request.urlopen(req, timeout=20) as r: return json.loads(r.read()) - Network accessline 19
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 40
data = json.dumps(payload).encode() req = urllib.request.Request( - Network accessline 41
req = urllib.request.Request( - Network accessline 42
"https://scanner.tradingview.com/america/scan", - Network accessline 44
headers={"Content-Type": "application/json", "User-Agent": "Mozilla/5.0"} ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 45
) with urllib.request.urlopen(req, timeout=20) as r: resp = json.loads(r.read()) - Network accessline 46
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 171
def symbol_search(query, exchange="", type_filter="", limit=50): url = ( f"https://symbol-search.tradingview.com/symbol_search/v3/" - Network accessline 172
url = ( f"https://symbol-search.tradingview.com/symbol_search/v3/" f"?text={query}&hl=1&exchange={exchange}&lang=en" - Network accessline 173
f"https://symbol-search.tradingview.com/symbol_search/v3/" - Network accessline 175
f"&search_type={type_filter or 'undefined'}&domain=production" ) req = urllib.request.Request(url, headers={ - Network accessline 176
) req = urllib.request.Request(url, headers={ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", - Network accessline 177
req = urllib.request.Request(url, headers={ - Network accessline 178
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", "Origin": "https://www.tradingview.com", # REQUIRED — 403 without this }) - Network accessline 179
"Origin": "https://www.tradingview.com", # REQUIRED — 403 without this }) with urllib.request.urlopen(req, timeout=15) as r: - Network accessline 180
}) with urllib.request.urlopen(req, timeout=15) as r: return json.loads(r.read()) - Network accessline 181
with urllib.request.urlopen(req, timeout=15) as r: - Network accessline 193
**Gotcha**: `symbol-search.tradingview.com` requires `Origin: https://www.tradingview.com`. Referer alone is not enough. The scanner API does NOT need Origin or Referer. - Network accessline 209
# symbol format: "NASDAQ:AAPL", "NYSE:TSLA" url = ( f"https://news-headlines.tradingview.com/v2/view/headlines/symbol" - Network accessline 210
url = ( f"https://news-headlines.tradingview.com/v2/view/headlines/symbol" f"?symbol={symbol}&client=web&streaming=false&lang=en&limit={limit}" - Network accessline 211
f"https://news-headlines.tradingview.com/v2/view/headlines/symbol" - Network accessline 212
f"?symbol={symbol}&client=web&streaming=false&lang=en&limit={limit}" ) req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 213
) req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=15) as r: - Network accessline 214
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 215
with urllib.request.urlopen(req, timeout=15) as r: - Network accessline 223
# items[0]["title"] = "Apple Clears Major Legal Hurdle..." # items[0]["published"] = 1776472317 (unix timestamp) # items[0]["link"] = "https://stocktwits.com/..." - Network accessline 224
# items[0]["published"] = 1776472317 (unix timestamp) # items[0]["link"] = "https://stocktwits.com/..." # items[0]["relatedSymbols"] = [{"symbol": "NASDAQ:AAPL", "logoid": "apple"}] - Network accessline 225
# items[0]["link"] = "https://stocktwits.com/..." - Network accessline 238
# "trending", "recent", "latest_popular", "week_popular", # "suggested", "recent_extended", "picked_time" url = f"https://www.tradingview.com/api/v1/ideas/?lang=en&sort={sort}&page={page}" - Network accessline 239
# "suggested", "recent_extended", "picked_time" url = f"https://www.tradingview.com/api/v1/ideas/?lang=en&sort={sort}&page={page}" if symbol: - Network accessline 240
url = f"https://www.tradingview.com/api/v1/ideas/?lang=en&sort={sort}&page={page}" - Network accessline 241
if symbol: url += f"&symbol={symbol}" # e.g. "NASDAQ:AAPL" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 242
url += f"&symbol={symbol}" # e.g. "NASDAQ:AAPL" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=15) as r: - Network accessline 243
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - Network accessline 244
with urllib.request.urlopen(req, timeout=15) as r: - Network accessline 249
# data["page_size"] = 20 # data["page_count"] = 50 # data["next"] = "https://www.tradingview.com/api/v1/ideas/?page=2" - Network accessline 250
# data["page_count"] = 50 # data["next"] = "https://www.tradingview.com/api/v1/ideas/?page=2" # data["results"] = list of idea objects - Network accessline 251
# data["next"] = "https://www.tradingview.com/api/v1/ideas/?page=2" - Network accessline 268
|---|---|---|---| | `scanner.tradingview.com/{market}/scan` | None | None | ~200ms | | `symbol-search.tradingview.com/symbol_search/v3/` | None | `Origin: https://www.tradingview.com` | ~150ms | - Network accessline 269
| `scanner.tradingview.com/{market}/scan` | None | None | ~200ms | | `symbol-search.tradingview.com/symbol_search/v3/` | None | `Origin: https://www.tradingview.com` | ~150ms | | `symbol-search.tradingview.com/symbol_search/` (v1) | None | - Network accessline 270
| `symbol-search.tradingview.com/symbol_search/v3/` | None | `Origin: https://www.tradingview.com` | ~150ms | - Network accessline 271
| `symbol-search.tradingview.com/symbol_search/` (v1) | None | `Origin: https://www.tradingview.com` | ~100ms | - Network accessline 283
**`data.tradingview.com/quotes/` is dead**: The URL `https://data.tradingview.com/quotes/?symbols=NASDAQ:AAPL` closes the connection without a response. Use the scanner API instead for real-time quotes. - Network accessline 304
# Only if you need a chart screenshot: goto_url("https://www.tradingview.com/chart/?symbol=NASDAQ:AAPL") - Network accessline 305
goto_url("https://www.tradingview.com/chart/?symbol=NASDAQ:AAPL")
agent-workspace/domain-skills/trello/boards-and-lists.md
- Network accessline 9
- `https://trello.com/` — marketing home for anonymous; when signed in, - Network accessline 10
redirects to `https://trello.com/u/<username>/boards` (the dashboard). - Network accessline 11
Note: `https://trello.com/boards` (no `/u/<username>`) returns an - Network accessline 12
error page for signed-in users. Always route via `/u/<username>/boards`. - Board URL: `https://trello.com/b/<8-char-boardId>/<slug>`. The `slug` is cosmetic — the boardId is the canonical identifier. - Network accessline 13
- Board URL: `https://trello.com/b/<8-char-boardId>/<slug>`. The `slug` - Network accessline 14
is cosmetic — the boardId is the canonical identifier. - Card URL: `https://trello.com/c/<8-char-cardId>/<n>-<slug>`, where `<n>` is the card's 1-based position within its list at creation time. - Network accessline 15
- Card URL: `https://trello.com/c/<8-char-cardId>/<n>-<slug>`, where - Network accessline 40
- `goto_url('https://trello.com/')` redirects asynchronously to the user's - Network accessline 85
Private API endpoints (Trello exposes `https://trello.com/1/...` REST
agent-workspace/domain-skills/tripadvisor/scraping.md
- Network accessline 27
new_tab("https://www.tripadvisor.com/") - Network accessline 49
for o in cities: m = re.search(r"/Tourism-(g\d+)-(.+)-Vacations\.html", o["href"]) o["restaurants_url"] = f"https://www.tripadvisor.com/Restaurants-{m.group(1)}-{m.group(2)}.html" - Network accessline 50
m = re.search(r"/Tourism-(g\d+)-(.+)-Vacations\.html", o["href"]) o["restaurants_url"] = f"https://www.tripadvisor.com/Restaurants-{m.group(1)}-{m.group(2)}.html" o["hotels_url"] = f"https://www.tripadvisor.com/Hotels-{m.group(1)}-{ - Network accessline 51
o["restaurants_url"] = f"https://www.tripadvisor.com/Restaurants-{m.group(1)}-{m.group(2)}.html" - Network accessline 52
o["hotels_url"] = f"https://www.tripadvisor.com/Hotels-{m.group(1)}-{m.group(2)}-Hotels.html" - Network accessline 60
{'label': 'Lisbon | Central Portugal, Portugal', 'href': 'https://www.tripadvisor.com/Tourism-g189158-Lisbon_Lisbon_District_Central_Portugal-Vacations.html', 'restaurants_url': 'https://www.tripadvisor.com/Restaurants-g189158-Lisbon_Lisbon - Network accessline 61
{'label': 'Lisbon | Ohio, United States', 'href': 'https://www.tripadvisor.com/Tourism-g50559-Lisbon_Ohio-Vacations.html', ...} - Network accessline 72
CITY_URL = "https://www.tripadvisor.com/Restaurants-g60745-Boston_Massachusetts.html" - Network accessline 139
"address": addr.get("streetAddress"), "telephone": j.get("telephone"), "url": urljoin("https://www.tripadvisor.com", c["href"]).split("?")[0].split("#")[0], - Network accessline 140
"telephone": j.get("telephone"), "url": urljoin("https://www.tripadvisor.com", c["href"]).split("?")[0].split("#")[0], "location_id": lid, - Network accessline 141
"url": urljoin("https://www.tripadvisor.com", c["href"]).split("?")[0].split("#")[0], - Network accessline 155
page 1: https://www.tripadvisor.com/Restaurants-g60745-Boston_Massachusetts.html total=2,561 results rows so far=30 - Network accessline 156
page 2: https://www.tripadvisor.com/Restaurants-g60745-oa30-Boston_Massachusetts.html total=2,561 results rows so far=60 - Network accessline 157
page 3: https://www.tripadvisor.com/Restaurants-g60745-oa60-Boston_Massachusetts.html total=2,561 results rows so far=90 - Network accessline 166
"address": "55 Temple Place, Boston, MA 02111", "telephone": "+1 617-779-0062", "url": "https://www.tripadvisor.com/Restaurant_Review-g60745-d19799010-Reviews-Cafe_Bonjour-Boston_Massachusetts.html", - Network accessline 167
"telephone": "+1 617-779-0062", "url": "https://www.tripadvisor.com/Restaurant_Review-g60745-d19799010-Reviews-Cafe_Bonjour-Boston_Massachusetts.html", "location_id": "19799010" - Network accessline 168
"url": "https://www.tripadvisor.com/Restaurant_Review-g60745-d19799010-Reviews-Cafe_Bonjour-Boston_Massachusetts.html", - Network accessline 184
CITY_URL = "https://www.tripadvisor.com/Hotels-g60745-Boston_Massachusetts-Hotels.html" - Network accessline 279
"price_tier": j.get("priceRange"), "address": ", ".join(filter(None, [addr.get("streetAddress"), addr.get("addressLocality")])) or None, "url": urljoin("https://www.tripadvisor.com", c["href"]).split("?")[0].split("# - Network accessline 280
"address": ", ".join(filter(None, [addr.get("streetAddress"), addr.get("addressLocality")])) or None, "url": urljoin("https://www.tripadvisor.com", c["href"]).split("?")[0].split("#")[0], "location_id": lid, - Network accessline 281
"url": urljoin("https://www.tripadvisor.com", c["href"]).split("?")[0].split("#")[0], - Network accessline 297
page 1: https://www.tripadvisor.com/Hotels-g60745-Boston_Massachusetts-Hotels.html rows so far=30 - Network accessline 298
page 2: https://www.tripadvisor.com/Hotels-g60745-oa30-Boston_Massachusetts-Hotels.html rows so far=60 - Network accessline 307
"price_tier": "€", "address": "6 W Broadway, Boston", "url": "https://www.tripadvisor.com/Hotel_Review-g60745-d15618152-Reviews-Cambria_Hotel_Boston_Downtown-Boston_Massachusetts.html", - Network accessline 308
"address": "6 W Broadway, Boston", "url": "https://www.tripadvisor.com/Hotel_Review-g60745-d15618152-Reviews-Cambria_Hotel_Boston_Downtown-Boston_Massachusetts.html", "location_id": "15618152" - Network accessline 309
"url": "https://www.tripadvisor.com/Hotel_Review-g60745-d15618152-Reviews-Cambria_Hotel_Boston_Downtown-Boston_Massachusetts.html", - Network accessline 326
URLS = [ "https://www.tripadvisor.com/Hotel_Review-g60745-d15618152-Reviews-Cambria_Hotel_Boston_Downtown-Boston_Massachusetts.html", - Network accessline 327
"https://www.tripadvisor.com/Hotel_Review-g60745-d15618152-Reviews-Cambria_Hotel_Boston_Downtown-Boston_Massachusetts.html", - Network accessline 328
"https://www.tripadvisor.com/Restaurant_Review-g60745-d19799010-Reviews-Cafe_Bonjour-Boston_Massachusetts.html",
agent-workspace/domain-skills/trulia/scraping.md
- Network accessline 45
def search_url(city, state, mode, page): slug = quote(city.strip().replace(" ", "_"), safe="_-") base = (f"https://www.trulia.com/{state.upper()}/{slug}/" if mode == "sale" - Network accessline 46
slug = quote(city.strip().replace(" ", "_"), safe="_-") base = (f"https://www.trulia.com/{state.upper()}/{slug}/" if mode == "sale" else f"https://www.trulia.com/for_rent/{slug},{state.upper()}/") - Network accessline 47
base = (f"https://www.trulia.com/{state.upper()}/{slug}/" if mode == "sale" - Network accessline 48
else f"https://www.trulia.com/for_rent/{slug},{state.upper()}/") - Network accessline 93
"sqft": val(h, "floorSpace", "formattedDimension"), "type": h.get("__typename"), "url": "https://www.trulia.com" + h["url"] if h.get("url") else None, - Network accessline 94
"type": h.get("__typename"), "url": "https://www.trulia.com" + h["url"] if h.get("url") else None, } - Network accessline 95
"url": "https://www.trulia.com" + h["url"] if h.get("url") else None, - Network accessline 169
PARTIAL: 23 of 25 pages not read yet; next run START_PAGE = 3 TRUNCATED: the site links only 25 pages, so at most 1000 of 5634 results are reachable; this cap is a hard stop {"address": "Cloverleaf 1657 Plan in Cloverleaf, Austin, TX 78747" - Network accessline 170
TRUNCATED: the site links only 25 pages, so at most 1000 of 5634 results are reachable; this cap is a hard stop {"address": "Cloverleaf 1657 Plan in Cloverleaf, Austin, TX 78747", "price": "$368,990+", "price_min": 368990, "price_max": null - Network accessline 171
{"address": "Cloverleaf 1657 Plan in Cloverleaf, Austin, TX 78747", "price": "$368,990+", "price_min": 368990, "price_max": null, "beds": "4 Beds", "baths": "2 Baths", "sqft": "1,657 sqft", "type": "HOME_FloorPlan", "url": "https://www.trul - Network accessline 172
{"address": "1900 Barton Springs Rd #2006, Austin, TX 78704", "price": "$419,000", "price_min": 419000, "price_max": 419000, "beds": "1 Bed", "baths": "1 Bath", "sqft": "887 sqft", "type": "HOME_Property", "url": "https://www.trulia.com/hom - Network accessline 178
{"address": "1188 Mission St, San Francisco, CA 94103", "price": "$3,946 - $4,952/mo", "price_min": 3946, "price_max": 4952, "beds": "1 Bed", "baths": "1 Bath", "sqft": "450-688 sqft", "type": "HOME_RentalCommunity", "url": "https://www.tru - Network accessline 189
SEARCH_URL = "https://www.trulia.com/CA/San_Francisco/" # any for-sale search page - Network accessline 223
if not homes: raise RuntimeError("no /home/ listings on the search page") detail_url = "https://www.trulia.com" + homes[0]["url"] - Network accessline 224
raise RuntimeError("no /home/ listings on the search page") detail_url = "https://www.trulia.com" + homes[0]["url"] time.sleep(PAUSE_S) - Network accessline 225
detail_url = "https://www.trulia.com" + homes[0]["url"] - Network accessline 277
{ "url": "https://www.trulia.com/home/355-chester-ave-san-francisco-ca-94132-15195820", - Network accessline 278
"url": "https://www.trulia.com/home/355-chester-ave-san-francisco-ca-94132-15195820", - Network accessline 306
RENT_SEARCH_URL = "https://www.trulia.com/for_rent/San_Francisco,CA/" - Network accessline 344
url = "https://www.trulia.com" + buildings[0]
agent-workspace/domain-skills/trustpilot/scraping.md
- Network accessline 23
Returns (None, [], {}, {}) if page is beyond the cap or no data. """ url = f"https://www.trustpilot.com/review/{domain}?languages={languages}&page={page}" - Network accessline 24
""" url = f"https://www.trustpilot.com/review/{domain}?languages={languages}&page={page}" if stars: - Network accessline 25
url = f"https://www.trustpilot.com/review/{domain}?languages={languages}&page={page}" - Network accessline 62
bu['stars'] # 1.5 (display stars: 1, 1.5, 2, 2.5 … 5) bu['numberOfReviews'] # 45228 — total across all languages bu['websiteUrl'] # 'https://www.amazon.com' - Network accessline 63
bu['numberOfReviews'] # 45228 — total across all languages bu['websiteUrl'] # 'https://www.amazon.com' bu['isClaimed'] # True/False - Network accessline 64
bu['websiteUrl'] # 'https://www.amazon.com' - Network accessline 102
'id': '5cafe2feb158a8533b443467', 'displayName': 'Baldy Bloke', 'imageUrl': 'https://user-images.trustpilot.com/...', - Network accessline 103
'displayName': 'Baldy Bloke', 'imageUrl': 'https://user-images.trustpilot.com/...', 'numberOfReviews': 17, - Network accessline 104
'imageUrl': 'https://user-images.trustpilot.com/...', - Network accessline 146
delay: seconds between requests (0.5 is safe; tested 5 rapid reqs with no block) """ base = f"https://www.trustpilot.com/review/{domain}" - Network accessline 147
""" base = f"https://www.trustpilot.com/review/{domain}" params = f"?languages={languages}" - Network accessline 148
base = f"https://www.trustpilot.com/review/{domain}" - Network accessline 204
All filter params are appended to the base URL `https://www.trustpilot.com/review/{domain}`: - Network accessline 254
GET https://api.trustpilot.com/v1/business-units/find?name=amazon.com → 403 Forbidden - Network accessline 255
GET https://api.trustpilot.com/v1/business-units/{id}/reviews → 403 Forbidden - Network accessline 307
""" def _fetch_page(domain, page, stars=None, languages='en'): url = f"https://www.trustpilot.com/review/{domain}?languages={languages}&page={page}" - Network accessline 308
def _fetch_page(domain, page, stars=None, languages='en'): url = f"https://www.trustpilot.com/review/{domain}?languages={languages}&page={page}" if stars: - Network accessline 309
url = f"https://www.trustpilot.com/review/{domain}?languages={languages}&page={page}"
agent-workspace/domain-skills/twitch/scraping.md
- Network accessline 26
BASE = "https://www.twitch.tv/directory/category/" + urllib.parse.quote(CATEGORY_SLUG, safe="") - Network accessline 43
"""Navigate the attached tab (new tab only if it is not on twitch yet); confirm the exact URL, query included.""" href = safe_js("location.href") or "" if href.startswith("https://www.twitch.tv/"): - Network accessline 44
href = safe_js("location.href") or "" if href.startswith("https://www.twitch.tv/"): goto_url(url) - Network accessline 45
if href.startswith("https://www.twitch.tv/"): - Network accessline 163
c["grid_position"] = pos # order the cards were appended while scrolling c["viewers"] = viewers_to_int(c["viewers_text"]) c["url"] = "https://www.twitch.tv/" + c["login"] - Network accessline 164
c["viewers"] = viewers_to_int(c["viewers_text"]) c["url"] = "https://www.twitch.tv/" + c["login"] # Counts change while you scroll, so grid order is only roughly sorted; re-sort by the card counts. - Network accessline 165
c["url"] = "https://www.twitch.tv/" + c["login"] - Network accessline 193
"tags": ["<tag>", "<tag>", "<tag>"], "verified": false, "thumbnail": "https://static-cdn.jtvnw.net/previews-ttv/live_user_<login>-640x360.jpg", - Network accessline 194
"verified": false, "thumbnail": "https://static-cdn.jtvnw.net/previews-ttv/live_user_<login>-640x360.jpg", "grid_position": 27, - Network accessline 195
"thumbnail": "https://static-cdn.jtvnw.net/previews-ttv/live_user_<login>-640x360.jpg", - Network accessline 196
"grid_position": 27, "viewers": 6400, "url": "https://www.twitch.tv/<login>", - Network accessline 197
"viewers": 6400, "url": "https://www.twitch.tv/<login>", "rank": 1 - Network accessline 198
"url": "https://www.twitch.tv/<login>", - Network accessline 233
"""Navigate the attached tab (new tab only if it is not on twitch yet); confirm the exact URL, query included.""" href = safe_js("location.href") or "" if href.startswith("https://www.twitch.tv/"): - Network accessline 234
href = safe_js("location.href") or "" if href.startswith("https://www.twitch.tv/"): goto_url(url) - Network accessline 235
if href.startswith("https://www.twitch.tv/"): - Network accessline 286
open_page("https://www.twitch.tv/directory") - Network accessline 320
cats.append({**c, "rank": rank, "kind": kind, "slug": slug, "viewers": viewers_to_int(c["viewers_text"]), "url": "https://www.twitch.tv" + c["path"]}) - Network accessline 322
"url": "https://www.twitch.tv" + c["path"]}) - Network accessline 340
{"name": "Stream-o-Ween", "path": "/directory/event/stream-o-ween-2026", "viewers_text": "34.4K viewers", "tags": [], "kind": "event", "slug": "stream-o-ween-2026", "viewers": 34400, ...}, {"name": "Just Chatting", "path": "/directory/cate - Network accessline 341
{"name": "Just Chatting", "path": "/directory/category/just-chatting", "viewers_text": "200K viewers", "tags": ["IRL"], "box_art": "https://static-cdn.jtvnw.net/ttv-boxart/509658-285x380.jpg", "rank": 2, "kind": "category", "slug": "just- - Network accessline 342
"box_art": "https://static-cdn.jtvnw.net/ttv-boxart/509658-285x380.jpg", "rank": 2, "kind": "category", "slug": "just-chatting", "viewers": 200000, - Network accessline 343
"url": "https://www.twitch.tv/directory/category/just-chatting"}, - Network accessline 387
def fetch(url, deadline): - Network accessline 393
if left <= 0: raise TimeoutError(f"{url}: deadline reached") req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Encoding": "gzip", "Accept-Language": "en-US"}) - Network accessline 394
raise TimeoutError(f"{url}: deadline reached") req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Encoding": "gzip", "Accept-Language": "en-US"}) try: - Network accessline 395
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Encoding": "gzip", "Accept-Language": "en-US"}) - Network accessline 396
try: with urllib.request.urlopen(req, timeout=min(20, left)) as r: page = body(r.read(), r.headers) - Network accessline 397
with urllib.request.urlopen(req, timeout=min(20, left)) as r: - Network accessline 420
def channel_about(login, attempts=4): url = "https://www.twitch.tv/" + urllib.parse.quote(login.lower(), safe="") - Network accessline 421
url = "https://www.twitch.tv/" + urllib.parse.quote(login.lower(), safe="") - Network accessline 422
deadline = time.time() + BUDGET # all requests and waits for one login share this deadline for attempt in range(attempts): page = fetch(url, deadline) - Network accessline 423
for attempt in range(attempts): page = fetch(url, deadline) graph = [] - Network accessline 424
page = fetch(url, deadline) - Network accessline 486
"login": "twitchgaming", "display_name": "twitchgaming", "url": "https://www.twitch.tv/twitchgaming", - Network accessline 487
"display_name": "twitchgaming", "url": "https://www.twitch.tv/twitchgaming", "bio": "Join /twitchgaming and be a part of the conversation! ...", - Network accessline 488
"url": "https://www.twitch.tv/twitchgaming", - Network accessline 489
"bio": "Join /twitchgaming and be a part of the conversation! ...", "profile_image": "https://static-cdn.jtvnw.net/jtv_user_pictures/77eb821f-...-profile_image-300x300.jpeg", "followers": 584895, - Network accessline 490
"profile_image": "https://static-cdn.jtvnw.net/jtv_user_pictures/77eb821f-...-profile_image-300x300.jpeg", - Network accessline 491
"followers": 584895, "social_links": ["https://twitter.com/twitch", "https://instagram.com/twitch"], "live": false, "live_title": null, "live_category": null, - Network accessline 492
"social_links": ["https://twitter.com/twitch", "https://instagram.com/twitch"], - Network accessline 497
{ "login": "twitch", "display_name": "Twitch", "followers": 2483231, "social_links": ["https://twitter.com/twitch", "https://www.instagram.com/twitch/", "https://www.tiktok.com/@twitch", "https://www.youtube.com/twitch"], - Network accessline 498
"login": "twitch", "display_name": "Twitch", "followers": 2483231, "social_links": ["https://twitter.com/twitch", "https://www.instagram.com/twitch/", "https://www.tiktok.com/@twitch", "https://www.youtube.com/twitch"], "recent_videos": - Network accessline 499
"social_links": ["https://twitter.com/twitch", "https://www.instagram.com/twitch/", "https://www.tiktok.com/@twitch", "https://www.youtube.com/twitch"], - Network accessline 500
"recent_videos": [ {"title": "Let's Chat Episode 14 | ...", "url": "https://www.twitch.tv/videos/2908640776", "uploaded": "2026-10-23T16:55:16Z", "duration": "PT3353S", "views": 8}, ... - Network accessline 501
{"title": "Let's Chat Episode 14 | ...", "url": "https://www.twitch.tv/videos/2908640776", "uploaded": "2026-10-23T16:55:16Z", "duration": "PT3353S", "views": 8}, - Network accessline 534
"""Navigate the attached tab (new tab only if it is not on twitch yet); confirm the exact URL, query included.""" href = safe_js("location.href") or "" if href.startswith("https://www.twitch.tv/"): - Network accessline 535
href = safe_js("location.href") or "" if href.startswith("https://www.twitch.tv/"): goto_url(url) - Network accessline 536
if href.startswith("https://www.twitch.tv/"): - Network accessline 631
if i: time.sleep(PAUSE) base = "https://www.twitch.tv/" + urllib.parse.quote(login.lower(), safe="") - Network accessline 632
time.sleep(PAUSE) base = "https://www.twitch.tv/" + urllib.parse.quote(login.lower(), safe="") open_page(base + "/about") - Network accessline 633
base = "https://www.twitch.tv/" + urllib.parse.quote(login.lower(), safe="") - Network accessline 660
{ "login": "twitchgaming", "url": "https://www.twitch.tv/twitchgaming", - Network accessline 661
"login": "twitchgaming", "url": "https://www.twitch.tv/twitchgaming", "display_name": "twitchgaming", - Network accessline 662
"url": "https://www.twitch.tv/twitchgaming", - Network accessline 666
"bio": "Join /twitchgaming and be a part of the conversation! ...", "partner": true, "social_links": [{"label": "Twitter", "url": "https://twitter.com/twitch"}, {"label": "Instagram", "url": "https://instagram.com/twitch"}], - Network accessline 667
"partner": true, "social_links": [{"label": "Twitter", "url": "https://twitter.com/twitch"}, {"label": "Instagram", "url": "https://instagram.com/twitch"}], "panels": [{"text": "", "images": [...], "links": []}, ...], - Network accessline 668
"social_links": [{"label": "Twitter", "url": "https://twitter.com/twitch"}, {"label": "Instagram", "url": "https://instagram.com/twitch"}], - Network accessline 672
}, {"login": "twitch", "display_name": "Twitch", "followers_text": "2.5M followers", "partner": true, "panels": [{"text": "", "images": [{"src": "https://panels.twitch.tv/panel-12826-image-...", "alt": "Panel Content"}], "links": ["https - Network accessline 673
{"login": "twitch", "display_name": "Twitch", "followers_text": "2.5M followers", "partner": true, "panels": [{"text": "", "images": [{"src": "https://panels.twitch.tv/panel-12826-image-...", "alt": "Panel Content"}], "links": ["https://t - Network accessline 674
"panels": [{"text": "", "images": [{"src": "https://panels.twitch.tv/panel-12826-image-...", "alt": "Panel Content"}], "links": ["https://twitter.com/Twitch"]}, ...], - Network accessline 679
With `LOGINS` set to the top 3 VALORANT channels plus an unknown login, the live part read: `"live": true, "stream_title": "<stream title>", "category": "VALORANT", "category_url": "https://www.twitch.tv/directory/category/valorant", "viewe - Network accessline 683
| Field | Source | Notes | |---|---|---| | `login` | block 1 card `a[data-a-target="preview-card-channel-link"]` href; block 3 JSON-LD `alternateName` | lowercase, unique key; URL is `https://www.twitch.tv/<login>` | - Network accessline 684
|---|---|---| | `login` | block 1 card `a[data-a-target="preview-card-channel-link"]` href; block 3 JSON-LD `alternateName` | lowercase, unique key; URL is `https://www.twitch.tv/<login>` | | `display_name` | card `p[title]`; JSON-LD `mainE - Network accessline 685
| `login` | block 1 card `a[data-a-target="preview-card-channel-link"]` href; block 3 JSON-LD `alternateName` | lowercase, unique key; URL is `https://www.twitch.tv/<login>` | - Access to secretsline 718
[Credential-related source omitted] - Network accessline 725
- **Plain HTTP for live channel lists:** `/directory/category/<slug>` returned 200 with only `BreadcrumbList` and `CollectionPage` JSON-LD and no stream cards. Use the browser (block 1). - **`gql.twitch.tv`** (the endpoint the page itself u - Network accessline 726
- **`gql.twitch.tv`** (the endpoint the page itself uses for the grid) is `Disallow: /` in its robots.txt; this skill does not call it. - **Helix API without credentials:** `GET https://api.twitch.tv/helix/streams?first=5` returned `401 {"e - Network accessline 727
- **Helix API without credentials:** `GET https://api.twitch.tv/helix/streams?first=5` returned `401 {"error":"Unauthorized","message":"OAuth token is missing"}`. The official API needs a registered app and token; not covered here.
agent-workspace/domain-skills/ulta/scraping.md
- Network accessline 10
- **Search (`/search?search=...`) is client-rendered.** Over plain HTTP the same module is present but has no items, so block 2 loads the search page in the browser and reads the rendered product cards (`li[data-test="products-list-item"]`) - Network accessline 12
- Category URLs: `https://www.ulta.com/sitemap/shop.xml` listed 288 `/shop/` URLs on 2026-10-23 (`/sitemap/index.xml` lists the other sitemaps, including `brand.xml`). - Network accessline 23
LISTING_URL = "https://www.ulta.com/shop/makeup/face/foundation" # any /shop/... or /brand/... listing page MAX_PAGES = 3 # 64 products per page; a hard cap: hitting it with pages left prints PARTIAL UA = "browser-harness/1.0 (ul - Network accessline 28
import gzip, json, sys, urllib.error, urllib.request url, ua = sys.argv[1], sys.argv[2] req = urllib.request.Request(url, headers={"User-Agent": ua, "Accept": "text/html", "Accept-Encoding": "gzip"}) - Network accessline 29
url, ua = sys.argv[1], sys.argv[2] req = urllib.request.Request(url, headers={"User-Agent": ua, "Accept": "text/html", "Accept-Encoding": "gzip"}) try: - Network accessline 30
req = urllib.request.Request(url, headers={"User-Agent": ua, "Accept": "text/html", "Accept-Encoding": "gzip"}) - Network accessline 31
try: with urllib.request.urlopen(req) as r: status, final, body, enc = r.status, r.geturl(), r.read(), r.headers.get("Content-Encoding") - Network accessline 32
with urllib.request.urlopen(req) as r: - Network accessline 54
def fetch(url, deadline_s=120): - Network accessline 102
parts = urllib.parse.urlsplit(LISTING_URL) if parts.netloc != "www.ulta.com" or not re.match(r"^/(shop|brand)/", parts.path) or parts.query: raise SystemExit("LISTING_URL must be https://www.ulta.com/shop/... or /brand/... with no query - Network accessline 104
raise SystemExit("LISTING_URL must be https://www.ulta.com/shop/... or /brand/... with no query string") - Network accessline 111
time.sleep(3) # polite pacing between pages url = LISTING_URL if page == 1 else f"{LISTING_URL}?page={page}" plr = find_module(apollo_state(fetch(url)), "ProductListingResults") - Network accessline 112
url = LISTING_URL if page == 1 else f"{LISTING_URL}?page={page}" plr = find_module(apollo_state(fetch(url)), "ProductListingResults") if plr is None: - Network accessline 113
plr = find_module(apollo_state(fetch(url)), "ProductListingResults") - Network accessline 114
if plr is None: raise RuntimeError(f"{url} has no ProductListingResults module: a department landing page? " "Use a deeper /shop/... URL from https://www.ulta.com/sitemap/shop.xml") - Network accessline 115
raise RuntimeError(f"{url} has no ProductListingResults module: a department landing page? " "Use a deeper /shop/... URL from https://www.ulta.com/sitemap/shop.xml") if plr.get("page") != page: - Network accessline 116
"Use a deeper /shop/... URL from https://www.ulta.com/sitemap/shop.xml") - Network accessline 174
page 1: 64 items, 64 unique so far, resultCount 254, next https://www.ulta.com/shop/makeup/face/foundation?page=2 - Network accessline 175
page 2: 64 items, 128 unique so far, resultCount 254, next https://www.ulta.com/shop/makeup/face/foundation?page=3 - Network accessline 176
page 3: 64 items, 192 unique so far, resultCount 254, next https://www.ulta.com/shop/makeup/face/foundation?page=4 - Network accessline 177
PARTIAL: stopped at MAX_PAGES=3 with 192 of 254 rows; more pages exist (next https://www.ulta.com/shop/makeup/face/foundation?page=4). Raise MAX_PAGES to collect them. - Network accessline 190
"promo": "Bundle & Save!", "sponsored": false, "url": "https://www.ulta.com/p/double-wear-stay-in-place-longwear-matte-foundation-pimprod2057355?sku=2651970", - Network accessline 191
"sponsored": false, "url": "https://www.ulta.com/p/double-wear-stay-in-place-longwear-matte-foundation-pimprod2057355?sku=2651970", "image": "https://media.ultainc.com/i/ulta/2651970" - Network accessline 192
"url": "https://www.ulta.com/p/double-wear-stay-in-place-longwear-matte-foundation-pimprod2057355?sku=2651970", - Network accessline 193
"image": "https://media.ultainc.com/i/ulta/2651970" - Network accessline 283
if "/search/no-results" in href: return None if href and not href.startswith(("https://www.ulta.com/search?", "about:blank")): - Network accessline 284
return None if href and not href.startswith(("https://www.ulta.com/search?", "about:blank")): raise SystemExit(f"Ulta redirected the search to {href} (brand or category page): " - Network accessline 285
if href and not href.startswith(("https://www.ulta.com/search?", "about:blank")): - Network accessline 301
url = "https://www.ulta.com/search?" + urllib.parse.urlencode({"search": QUERY}) - Network accessline 344
page 2: 64 cards, 64 kept, 125 total, heading '400+ results for "mascara"' page 3: 64 cards, 64 kept, 189 total, heading '400+ results for "mascara"' PARTIAL: stopped at MAX_PAGES=3 with 189 rows; the page still has a Load More link (https: - Network accessline 345
page 3: 64 cards, 64 kept, 189 total, heading '400+ results for "mascara"' PARTIAL: stopped at MAX_PAGES=3 with 189 rows; the page still has a Load More link (https://www.ulta.com/search?search=mascara&page=4), heading '400+ results for "ma - Network accessline 346
PARTIAL: stopped at MAX_PAGES=3 with 189 rows; the page still has a Load More link (https://www.ulta.com/search?search=mascara&page=4), heading '400+ results for "mascara"'. Raise MAX_PAGES to collect more. - Network accessline 360
"sponsored": false, "tags": ["Free Gift with purchase"], "url": "https://www.ulta.com/p/lash-sensational-sky-high-mascara-pimprod2020260?sku=2574523" - Network accessline 361
"tags": ["Free Gift with purchase"], "url": "https://www.ulta.com/p/lash-sensational-sky-high-mascara-pimprod2020260?sku=2574523" }, - Network accessline 362
"url": "https://www.ulta.com/p/lash-sensational-sky-high-mascara-pimprod2020260?sku=2574523" - Network accessline 368
The search heading only says `400+`, so with a Load More link still present the block prints `PARTIAL` and sets `complete = False`; it does not guess a total. Earlier runs of the same query gave 73/73/64, 74/75/64, 74/73/64 (2026-10-23) and - Network accessline 375
PRODUCT_URL = "https://www.ulta.com/p/double-wear-stay-in-place-longwear-matte-foundation-pimprod2057355?sku=2651970" # any /p/... URL from block 1 or 2 UA = "browser-harness/1.0 (ulta domain skill; plain urllib)" - Network accessline 379
import gzip, json, sys, urllib.error, urllib.request url, ua = sys.argv[1], sys.argv[2] req = urllib.request.Request(url, headers={"User-Agent": ua, "Accept": "text/html", "Accept-Encoding": "gzip"}) - Network accessline 380
url, ua = sys.argv[1], sys.argv[2] req = urllib.request.Request(url, headers={"User-Agent": ua, "Accept": "text/html", "Accept-Encoding": "gzip"}) try: - Network accessline 381
req = urllib.request.Request(url, headers={"User-Agent": ua, "Accept": "text/html", "Accept-Encoding": "gzip"}) - Network accessline 382
try: with urllib.request.urlopen(req) as r: status, final, body, enc = r.status, r.geturl(), r.read(), r.headers.get("Content-Encoding") - Network accessline 383
with urllib.request.urlopen(req) as r: - Network accessline 404
def fetch(url, deadline_s=120): - Network accessline 445
if not re.match(r"^https://www\.ulta\.com/p/[^?#]+$", PRODUCT_URL.split("?")[0]): - Network accessline 446
raise SystemExit("PRODUCT_URL must be an https://www.ulta.com/p/... product URL") - Network accessline 448
html = fetch(PRODUCT_URL) - Network accessline 536
"ingredients": "Water\\Aqua\\Eau, Methyl Trimethicone, Dimethicone, Trimethylsiloxysilicate, Niacinamide, ...", "attributes": {"Face Coverage": ["Medium"], "Face Finish": ["Natural"], "Face Form": ["Liquid"], "Skin Type": ["Combination", " - Network accessline 537
"attributes": {"Face Coverage": ["Medium"], "Face Finish": ["Natural"], "Face Form": ["Liquid"], "Skin Type": ["Combination", "Dry", "Normal", "Oily", "Sensitive"]}, "images": ["https://media.ulta.com/i/ulta/2651970?w=500&h=500", "..._alt0 - Network accessline 538
"images": ["https://media.ulta.com/i/ulta/2651970?w=500&h=500", "..._alt01?w=500&h=500", ...], - Network accessline 581
- **Unrated items.** 27 of 254 Foundation rows had no rating; search cards for unrated items have no ratings label, so `rating` and `review_count` are `None`. - **Selector drift (block 2 is the fragile part).** Search cards are read through - Network accessline 582
- **Selector drift (block 2 is the fragile part).** Search cards are read through design-system class names: `.pal-c-ProductCardBody--brandName`, `--title`, `--price`, `.pal-c-Ratings`, `.pal-c-ProductCardHeader__variant`, `.pal-c-Tag__mess - Network accessline 583
- **Region.** Ulta is a US storefront. Every load in this run, from the cloud browser and from plain HTTP, stayed on `https://www.ulta.com/` with no geo redirect, `lang="en-US"`, prices in `$` and JSON-LD `priceCurrency` `USD`; no country o - Access to secretsline 584
[Credential-related source omitted]
agent-workspace/domain-skills/upwork/scraping.md
- Network accessline 27
BASE = "https://www.upwork.com" - Network accessline 215
"workload": null, "duration": "1 to 3 months", "url": "https://www.upwork.com/freelance-jobs/apply/commerce-Product-Monitoring-System_~022112614550818987209/", - Network accessline 216
"duration": "1 to 3 months", "url": "https://www.upwork.com/freelance-jobs/apply/commerce-Product-Monitoring-System_~022112614550818987209/", "detail_error": null - Network accessline 217
"url": "https://www.upwork.com/freelance-jobs/apply/commerce-Product-Monitoring-System_~022112614550818987209/", - Network accessline 267
Opening `https://www.upwork.com/o/jobs/browse/?q=<keyword>` (URL-encode the keyword with `quote(kw, safe='')`) in the browser redirected to the matching skill page for known skills (`shopify` -> `/freelance-jobs/shopify/`, `data entry` -> ` - Network accessline 286
| `workload` | detail `job.workload` / card `engagement` | `null` on fixed-price jobs | | `duration` | `durationLabel` | e.g. `"1 to 3 months"` | | `url` | `https://www.upwork.com` + card `url` | `/freelance-jobs/apply/<slug>_~<ciphertext>/ - Network accessline 287
| `duration` | `durationLabel` | e.g. `"1 to 3 months"` | | `url` | `https://www.upwork.com` + card `url` | `/freelance-jobs/apply/<slug>_~<ciphertext>/` | | `detail_error` | | `null` when the detail page was read; else why not (`"HTTP 403" - Network accessline 288
| `url` | `https://www.upwork.com` + card `url` | `/freelance-jobs/apply/<slug>_~<ciphertext>/` | - Network accessline 300
- **No consent banner or login wall** appeared on `/freelance-jobs/` pages in the cloud browser. - The HTTP status comes from `performance.getEntriesByType('navigation')[0].responseStatus` (Chrome 109+). - `js()` calls time out after 5 s, s - Network accessline 301
- The HTTP status comes from `performance.getEntriesByType('navigation')[0].responseStatus` (Chrome 109+). - `js()` calls time out after 5 s, so do not run slow multi-request `fetch()` loops inside the page; navigate instead. - Pages are la - Network accessline 302
- `js()` calls time out after 5 s, so do not run slow multi-request `fetch()` loops inside the page; navigate instead.
agent-workspace/domain-skills/vercel/archive-and-audit.md
- Network accessline 7
- Team overview: `https://vercel.com/<team>`. - Network accessline 8
- Project overview: `https://vercel.com/<team>/<project>`. - Network accessline 9
- Project analytics: `https://vercel.com/<team>/<project>/analytics`. - Network accessline 23
A `.mp4` URL can return HTTP 200 with `Content-Type: video/mp4` but contain a **Git LFS pointer**, not video. The body starts with `version https://git-lfs.github.com/spec/v1` and is only about 130 bytes. Check bytes/magic and decode media,
agent-workspace/domain-skills/vercel/vercel.md
- Access to secretsline 3
[Credential-related source omitted] - Access to secretsline 5
[Credential-related source omitted] - Network accessline 8
import json cookies = cdp("Network.getCookies", urls=["https://vercel.com"]) - Network accessline 9
cookies = cdp("Network.getCookies", urls=["https://vercel.com"]) - Network accessline 33
resp = http_get( "https://vercel.com/api/v6/deployments?limit=100&teamId=<team-slug>", - Network accessline 34
"https://vercel.com/api/v6/deployments?limit=100&teamId=<team-slug>", - Network accessline 54
data = json.loads(http_get( "https://vercel.com/api/v9/projects?teamId=<team-slug>&limit=50", - Network accessline 55
"https://vercel.com/api/v9/projects?teamId=<team-slug>&limit=50", - Network accessline 67
uid = dep["uid"] # e.g. "dpl_2tySoj6ceJkTgtsWHvd5r1Hpgyd1" — already includes dpl_ prefix resp = http_get( "https://vercel.com/api/v3/deployments/" + uid + "/events?builds=1&limit=5000&teamId=<team-slug>", - Network accessline 68
resp = http_get( "https://vercel.com/api/v3/deployments/" + uid + "/events?builds=1&limit=5000&teamId=<team-slug>", headers=headers - Network accessline 69
"https://vercel.com/api/v3/deployments/" + uid + "/events?builds=1&limit=5000&teamId=<team-slug>", - Network accessline 89
new_tab("https://vercel.com/dashboard")
agent-workspace/domain-skills/vinted/scraping.md
- Network accessline 23
BASE = "https://www.vinted.com" - Network accessline 106
u = urllib.parse.urlparse(url) if u.scheme != "https" or u.netloc != "www.vinted.com" or u.path != "/catalog": raise ValueError(f"refusing {url}: only https://www.vinted.com/catalog?... pages are used") - Network accessline 107
if u.scheme != "https" or u.netloc != "www.vinted.com" or u.path != "/catalog": raise ValueError(f"refusing {url}: only https://www.vinted.com/catalog?... pages are used") goto_url(url) if _tab["open"] else new_tab(url) - Network accessline 108
raise ValueError(f"refusing {url}: only https://www.vinted.com/catalog?... pages are used") - Network accessline 168
try: # robots.txt disallows /member/: refused before the tab navigates open_page("https://www.vinted.com/member/12345") - Network accessline 169
open_page("https://www.vinted.com/member/12345") - Network accessline 179
page 3: 96 rows, 84 new, total_entries=960, total_pages=10 269 listings, status: truncated_max_pages {"id": 10611858188, "title": "Nike Zip", "brand": "Nike", "size": "M / US 8-10", "condition": "Good", "price": 4.0, "discounted_price": nul - Network accessline 180
269 listings, status: truncated_max_pages {"id": 10611858188, "title": "Nike Zip", "brand": "Nike", "size": "M / US 8-10", "condition": "Good", "price": 4.0, "discounted_price": null, "total_price": 4.9, "currency": "USD", "promoted": false - Network accessline 181
{"id": 10611858188, "title": "Nike Zip", "brand": "Nike", "size": "M / US 8-10", "condition": "Good", "price": 4.0, "discounted_price": null, "total_price": 4.9, "currency": "USD", "promoted": false, "url": "https://www.vinted.com/items/106 - Network accessline 182
{"id": 10611815068, "title": "Nike Dri-Fit Tshirt", "brand": "Nike", "size": "M", "condition": "Very good", "price": 5.0, "discounted_price": null, "total_price": 5.95, "currency": "USD", "promoted": true, "url": "https://www.vinted.com/ite - Network accessline 185
page 1: 96 rows, 96 new, total_entries=960, total_pages=10 96 listings, 23 without a brand {"id": 10610445929, "title": "True vintage handmade dress", "brand": null, "size": "XXS / US 0", "condition": "Very good", "price": 10.0, "discounted - Network accessline 186
96 listings, 23 without a brand {"id": 10610445929, "title": "True vintage handmade dress", "brand": null, "size": "XXS / US 0", "condition": "Very good", "price": 10.0, "discounted_price": null, "total_price": 11.2, "currency": "USD", "pro - Network accessline 187
{"id": 10610445929, "title": "True vintage handmade dress", "brand": null, "size": "XXS / US 0", "condition": "Very good", "price": 10.0, "discounted_price": null, "total_price": 11.2, "currency": "USD", "promoted": false, "url": "https://w - Network accessline 188
page 1: 0 rows, 0 new, total_entries=0, total_pages=1 0 listings for a nonsense query, status: complete refused: refusing https://www.vinted.com/member/12345: only https://www.vinted.com/catalog?... pages are used - Network accessline 190
refused: refusing https://www.vinted.com/member/12345: only https://www.vinted.com/catalog?... pages are used - Network accessline 222
| `currency` | `price.currencyCode` | `USD` on www.vinted.com | | `promoted` | `isPromoted` | 87 of 384 sampled rows were promoted ("bumped") listings mixed into the results | | `url` | built from `id`: `https://www.vinted.com/items/<id>` | - Network accessline 223
| `promoted` | `isPromoted` | 87 of 384 sampled rows were promoted ("bumped") listings mixed into the results | | `url` | built from `id`: `https://www.vinted.com/items/<id>` | redirects to the canonical slug URL; the slug repeats the selle - Network accessline 224
| `url` | built from `id`: `https://www.vinted.com/items/<id>` | redirects to the canonical slug URL; the slug repeats the seller-written title, so it is left out | - Network accessline 235
- Promoted ("bumped") rows sit inside the normal result order (28 of 96 on each of two `nike` pages); filter on `promoted` if you want organic rows only. - `EXTRACT` returns `error` on a DataDome challenge frame (`captcha-delivery.com`); th - Network accessline 237
- The code refuses any URL other than `https://www.vinted.com/catalog?...` before navigating, refuses a page whose URL differs from the one requested, and refuses a row whose label and tile text disagree.
agent-workspace/domain-skills/walmart/scraping.md
- Network accessline 36
Raises RuntimeError if PerimeterX bot challenge is returned. """ req = urllib.request.Request( - Network accessline 37
""" req = urllib.request.Request( url, - Network accessline 38
req = urllib.request.Request( - Network accessline 40
headers={"User-Agent": "Mozilla/5.0", "Accept-Encoding": "gzip"}, ) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 41
) with urllib.request.urlopen(req, timeout=20) as r: data = r.read() - Network accessline 42
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 65
# Keyword search "https://www.walmart.com/search?q=laptop" - Network accessline 66
"https://www.walmart.com/search?q=laptop" - Network accessline 68
# Pagination — append &page=N "https://www.walmart.com/search?q=laptop&page=2" - Network accessline 69
"https://www.walmart.com/search?q=laptop&page=2" - Network accessline 71
# Sort options (confirmed working) "https://www.walmart.com/search?q=laptop&sort=best_match" # default - Network accessline 72
"https://www.walmart.com/search?q=laptop&sort=best_match" # default - Network accessline 73
"https://www.walmart.com/search?q=laptop&sort=best_seller" - Network accessline 74
"https://www.walmart.com/search?q=laptop&sort=price_low" - Network accessline 75
"https://www.walmart.com/search?q=laptop&sort=customer_rating" - Network accessline 77
# Price filter "https://www.walmart.com/search?q=laptop&min_price=200&max_price=500" - Network accessline 78
"https://www.walmart.com/search?q=laptop&min_price=200&max_price=500" - Network accessline 80
# Browse by category (department ID path) "https://www.walmart.com/browse/electronics/laptops/3944_1089430_3951" - Network accessline 81
"https://www.walmart.com/browse/electronics/laptops/3944_1089430_3951" - Network accessline 123
"availability": avail.get("value"), # "IN_STOCK" / "OUT_OF_STOCK" "isSponsored": bool(item.get("isSponsoredFlag")), "url": "https://www.walmart.com" + (item.get("canonicalUrl") - Network accessline 124
"isSponsored": bool(item.get("isSponsoredFlag")), "url": "https://www.walmart.com" + (item.get("canonicalUrl") or "").split("?")[0], "thumbnailUrl": img.get("thumbnailUrl"), - Network accessline 125
"url": "https://www.walmart.com" + (item.get("canonicalUrl") or "").split("?")[0], - Network accessline 134
# Usage html = fetch_walmart("https://www.walmart.com/search?q=laptop") - Network accessline 135
html = fetch_walmart("https://www.walmart.com/search?q=laptop") - Network accessline 161
for page in range(1, max_page + 1): html = fetch_walmart(f"https://www.walmart.com/search?q=laptop&page={page}") - Network accessline 162
html = fetch_walmart(f"https://www.walmart.com/search?q=laptop&page={page}") - Network accessline 177
https://www.walmart.com/ip/{slug}/{usItemId} - Network accessline 183
https://www.walmart.com/ip/anything/19717318352 - Network accessline 184
https://www.walmart.com/ip/Apple-MacBook-Neo/19717318352 - Network accessline 267
], # URL "canonicalUrl": "https://www.walmart.com" + (product.get("canonicalUrl") or ""), - Network accessline 268
# URL "canonicalUrl": "https://www.walmart.com" + (product.get("canonicalUrl") or ""), # fulfillment - Network accessline 269
"canonicalUrl": "https://www.walmart.com" + (product.get("canonicalUrl") or ""), - Network accessline 283
# Usage url = "https://www.walmart.com/ip/Apple-MacBook-Neo/19717318352" - Network accessline 284
url = "https://www.walmart.com/ip/Apple-MacBook-Neo/19717318352" - Network accessline 386
# Browser-based search extraction new_tab("https://www.walmart.com/search?q=laptop") - Network accessline 387
new_tab("https://www.walmart.com/search?q=laptop") - Network accessline 428
new_tab("https://www.walmart.com/search?q=laptop")
agent-workspace/domain-skills/wayback-machine/scraping.md
- Network accessline 3
`https://web.archive.org` — all public data, no auth or API key required. Everything here is pure `http_get` — no browser needed. - Network accessline 14
# Find all snapshots of a URL — the minimal starting query r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 15
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=example.com&output=json&limit=10" - Network accessline 16
"https://web.archive.org/cdx/search/cdx" - Network accessline 22
# rows[0] is ALWAYS the header row — slice rows[1:] for data for ts, orig, status, mime, length in rows[1:]: print(f"https://web.archive.org/web/{ts}/{orig} [{status}]") - Network accessline 24
print(f"https://web.archive.org/web/{ts}/{orig} [{status}]") - Network accessline 38
r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 39
"https://web.archive.org/cdx/search/cdx" - Network accessline 45
rows = json.loads(r) ts, orig, status = rows[1] # rows[0] is header snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 46
ts, orig, status = rows[1] # rows[0] is header snap_url = f"https://web.archive.org/web/{ts}/{orig}" # Timestamp format: 14-digit YYYYMMDDHHMMSS - Network accessline 47
snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 57
r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 58
"https://web.archive.org/cdx/search/cdx" - Network accessline 65
rows = json.loads(r) for ts, orig, status in rows[1:]: print(f"{ts[:4]}-{ts[4:6]} https://web.archive.org/web/{ts}/{orig}") - Network accessline 67
print(f"{ts[:4]}-{ts[4:6]} https://web.archive.org/web/{ts}/{orig}") - Network accessline 82
# matchType=prefix — all URLs starting with the given path r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 83
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=example.com/blog/&matchType=prefix&output=json" - Network accessline 84
"https://web.archive.org/cdx/search/cdx" - Network accessline 106
# Only successful HTML captures — combine multiple filters r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 107
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=example.com&output=json" - Network accessline 108
"https://web.archive.org/cdx/search/cdx" - Network accessline 131
| `urlkey` | SURT-format URL (reversed domain) | `com,example)/` | | `timestamp` | Capture time, 14-digit `YYYYMMDDHHMMSS` | `20230601114925` | | `original` | Original crawled URL (includes port if non-standard) | `https://example.com/` | - Network accessline 132
| `timestamp` | Capture time, 14-digit `YYYYMMDDHHMMSS` | `20230601114925` | | `original` | Original crawled URL (includes port if non-standard) | `https://example.com/` | | `mimetype` | Content-Type at crawl time | `text/html` | - Network accessline 133
| `original` | Original crawled URL (includes port if non-standard) | `https://example.com/` | - Network accessline 152
# Left here for reference only — do not rely on it: r = http_get( "https://archive.org/wayback/available" - Network accessline 153
r = http_get( "https://archive.org/wayback/available" "?url=example.com×tamp=20240101", - Network accessline 154
"https://archive.org/wayback/available" - Network accessline 162
# CORRECT replacement: r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 163
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=example.com&output=json&limit=1" - Network accessline 164
"https://web.archive.org/cdx/search/cdx" - Network accessline 171
if len(rows) > 1: ts, orig, status = rows[1] snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 173
snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 185
"""Yield all CDX rows for a URL, page by page.""" base = ( "https://web.archive.org/cdx/search/cdx" - Network accessline 186
base = ( "https://web.archive.org/cdx/search/cdx" f"?url={quote(url, safe='')}&output=json" - Network accessline 187
"https://web.archive.org/cdx/search/cdx" - Network accessline 204
for ts, orig, status in cdx_all_snapshots("example.com"): snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 205
snap_url = f"https://web.archive.org/web/{ts}/{orig}" - Network accessline 214
# Direct snapshot URL: /web/{14-digit-timestamp}/{original-url} snap_url = "https://web.archive.org/web/20230601114925/https://example.com/" - Network accessline 215
snap_url = "https://web.archive.org/web/20230601114925/https://example.com/" - Network accessline 221
# Canonical form for "get latest available" — use 14 zeros: latest = "https://web.archive.org/web/20240101000000*/example.com" - Network accessline 222
latest = "https://web.archive.org/web/20240101000000*/example.com" # The * suffix returns a calendar page (HTML), not the archived page itself. # Use CDX to find the real timestamp, then fetch the direct URL. - Network accessline 234
# Find only snapshots where the content CHANGED — dedup by SHA-1 digest r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 235
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=example.com&output=json" - Network accessline 236
"https://web.archive.org/cdx/search/cdx" - Network accessline 256
# Use for estimating result size before a full fetch r = http_get( "https://web.archive.org/cdx/search/cdx" - Network accessline 257
r = http_get( "https://web.archive.org/cdx/search/cdx" "?url=example.com&matchType=prefix" - Network accessline 258
"https://web.archive.org/cdx/search/cdx" - Network accessline 274
|---|---|---|---| | CDX search | 5–40s | 60s | Intermittently slow; retry on timeout | | Snapshot fetch (`/web/`) | 2–10s | 30s | Reliable | - Network accessline 275
| CDX search | 5–40s | 60s | Intermittently slow; retry on timeout | | Snapshot fetch (`/web/`) | 2–10s | 30s | Reliable | | Metadata (`/metadata/`) | <1s | 20s | Fast, stable | - Network accessline 276
| Snapshot fetch (`/web/`) | 2–10s | 30s | Reliable | - Network accessline 296
- **`original` preserves non-standard ports.** Old crawls captured `http://www.example.com:80/` — the `:80` is part of the `original` field. Build playback URLs verbatim: `f"https://web.archive.org/web/{ts}/{orig}"` works correctly with the
agent-workspace/domain-skills/weather/scraping.md
- Network accessline 23
import json data = json.loads(http_get("https://wttr.in/San+Francisco?format=j1")) - Network accessline 24
data = json.loads(http_get("https://wttr.in/San+Francisco?format=j1")) - Network accessline 71
import json geo = json.loads(http_get("https://geocoding-api.open-meteo.com/v1/search?name=Chicago&count=1")) - Network accessline 72
geo = json.loads(http_get("https://geocoding-api.open-meteo.com/v1/search?name=Chicago&count=1")) - Network accessline 86
data = json.loads(http_get( f"https://api.open-meteo.com/v1/forecast" - Network accessline 87
f"https://api.open-meteo.com/v1/forecast" - Network accessline 122
data = json.loads(http_get( f"https://api.open-meteo.com/v1/forecast" - Network accessline 123
f"https://api.open-meteo.com/v1/forecast" - Network accessline 160
data = json.loads(http_get( f"https://api.open-meteo.com/v1/forecast" - Network accessline 161
f"https://api.open-meteo.com/v1/forecast" - Network accessline 190
data = json.loads(http_get( "https://archive-api.open-meteo.com/v1/archive" - Network accessline 191
"https://archive-api.open-meteo.com/v1/archive" - Network accessline 225
"Accept": "application/geo+json", } req = urllib.request.Request(url, headers=h) - Network accessline 226
} req = urllib.request.Request(url, headers=h) with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 227
req = urllib.request.Request(url, headers=h) - Network accessline 228
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 234
# Call 1: resolve lat/lon to forecast office + grid cell (~90ms) pts = json.loads(nws_get("https://api.weather.gov/points/37.7749,-122.4194")) - Network accessline 235
pts = json.loads(nws_get("https://api.weather.gov/points/37.7749,-122.4194")) - Network accessline 303
# 1. Geocode geo = json.loads(http_get( f"https://geocoding-api.open-meteo.com/v1/search?name={city.replace(' ', '+')}&count=1" - Network accessline 304
geo = json.loads(http_get( f"https://geocoding-api.open-meteo.com/v1/search?name={city.replace(' ', '+')}&count=1" )) - Network accessline 305
f"https://geocoding-api.open-meteo.com/v1/search?name={city.replace(' ', '+')}&count=1" - Network accessline 312
# 2. Forecast (single call: current + daily) data = json.loads(http_get( f"https://api.open-meteo.com/v1/forecast" - Network accessline 313
data = json.loads(http_get( f"https://api.open-meteo.com/v1/forecast" f"?latitude={lat}&longitude={lon}" - Network accessline 314
f"https://api.open-meteo.com/v1/forecast" - Network accessline 352
def http_get_wttr(url): req = urllib.request.Request(url, headers={"User-Agent": "Wget/1.21", "Accept": "*/*"}) - Network accessline 353
req = urllib.request.Request(url, headers={"User-Agent": "Wget/1.21", "Accept": "*/*"}) - Network accessline 354
with urllib.request.urlopen(req, timeout=20) as r: - Network accessline 360
# Text format tokens (URL-encode %): %25l=location, %25C=condition desc, # %25t=temp, %25f=feels-like, %25h=humidity, %25w=wind print(http_get_wttr("https://wttr.in/London?format=%25t")) # '+55°F' - Network accessline 361
# %25t=temp, %25f=feels-like, %25h=humidity, %25w=wind print(http_get_wttr("https://wttr.in/London?format=%25t")) # '+55°F' print(http_get_wttr("https://wttr.in/Tokyo?format=3")) # 'tokyo: ☀<U+FE0F> +69°F' - Network accessline 362
print(http_get_wttr("https://wttr.in/London?format=%25t")) # '+55°F' - Network accessline 363
print(http_get_wttr("https://wttr.in/Tokyo?format=3")) # 'tokyo: ☀<U+FE0F> +69°F' - Network accessline 364
print(http_get_wttr("https://wttr.in/Berlin?format=%25l:+%25C+%25t+(feels+%25f)+%25h+%25w"))
agent-workspace/domain-skills/wehotel/hotels.md
- Access to secretsline 16
[Credential-related source omitted] - Network accessline 28
List page: https://www.bestwehotel.com/HotelSearch/ - Network accessline 29
https://www.bestwehotel.com/HotelSearch/ - Network accessline 37
Hotel detail page: https://www.bestwehotel.com/HotelDetail/ - Network accessline 38
https://www.bestwehotel.com/HotelDetail/ - Network accessline 62
new_tab("https://www.bestwehotel.com/") - Network accessline 80
url = ( "https://www.bestwehotel.com/HotelSearch/" - Network accessline 81
"https://www.bestwehotel.com/HotelSearch/" - Network accessline 236
url = ( "https://www.bestwehotel.com/HotelSearch/" - Network accessline 237
"https://www.bestwehotel.com/HotelSearch/"
agent-workspace/domain-skills/wellfound/scraping.md
- Network accessline 60
new_tab("https://wellfound.com/company/stripe") - Network accessline 87
| Goal | URL | |------|-----| | Company profile | `https://wellfound.com/company/{slug}` | - Network accessline 88
|------|-----| | Company profile | `https://wellfound.com/company/{slug}` | | Company jobs | `https://wellfound.com/company/{slug}/jobs` | - Network accessline 89
| Company profile | `https://wellfound.com/company/{slug}` | - Network accessline 90
| Company jobs | `https://wellfound.com/company/{slug}/jobs` | - Network accessline 91
| Company culture | `https://wellfound.com/company/{slug}/culture` | - Network accessline 92
| Job board (all) | `https://wellfound.com/jobs` | - Network accessline 93
| Job board filtered | `https://wellfound.com/jobs` — then use UI filters (query params are disallowed by robots.txt) | - Network accessline 94
| Investor profile | `https://wellfound.com/investor/{slug}` | - Network accessline 95
| User profile | `https://wellfound.com/u/{username}` (disallowed by robots.txt, login wall) | - Network accessline 109
new_tab("https://wellfound.com/company/stripe") - Network accessline 213
company_slug = "stripe" new_tab(f"https://wellfound.com/company/{company_slug}/jobs") - Network accessline 214
new_tab(f"https://wellfound.com/company/{company_slug}/jobs") - Network accessline 260
new_tab("https://wellfound.com/jobs") - Access to secretsline 304
[Credential-related source omitted] - Network accessline 313
# Step 1: Load any Wellfound page so the session cookie + DataDome cookie are set new_tab("https://wellfound.com/") - Network accessline 314
new_tab("https://wellfound.com/") - Network accessline 325
# Step 3: Execute GraphQL query via fetch() from within the browser - Access to secretsline 326
[Credential-related source omitted] - Network accessline 328
(async function() {{ try {{ var resp = await fetch('/graphql', {{ - Network accessline 329
try {{ var resp = await fetch('/graphql', {{ method: 'POST', - Network accessline 330
var resp = await fetch('/graphql', {{ - Network accessline 370
result_sync = js(""" var done = false, out = null; fetch('/graphql', { - Network accessline 371
var done = false, out = null; fetch('/graphql', { method: 'POST', - Network accessline 372
fetch('/graphql', { - Network accessline 468
# Usage new_tab("https://wellfound.com/company/stripe") - Network accessline 469
new_tab("https://wellfound.com/company/stripe") - Network accessline 519
[Credential-related source omitted] - Access to secretsline 519
[Credential-related source omitted] - Network accessline 520
per-session value from `<meta name="csrf-token">`. Cloudflare Bot Management blocks `POST /graphql` from non-browser sessions. Always fire GraphQL via `fetch()` inside the browser session (not from Python's `http_get`). - Network accessline 521
`POST /graphql` from non-browser sessions. Always fire GraphQL via `fetch()` inside the - Network accessline 546
<!-- DataDome challenge (page GETs) --> <script>var dd={'rt':'c','cid':'...','t':'bv','host':'geo.captcha-delivery.com',...}</script> <script src="https://ct.captcha-delivery.com/c.js"></script> - Network accessline 547
<script>var dd={'rt':'c','cid':'...','t':'bv','host':'geo.captcha-delivery.com',...}</script> <script src="https://ct.captcha-delivery.com/c.js"></script> <!-- rt='c' = captcha required; rt='i' = invisible solve; rt='b' = blocked --> - Network accessline 548
<script src="https://ct.captcha-delivery.com/c.js"></script> - Network accessline 565
# Open Wellfound company page new_tab("https://wellfound.com/company/openai") - Network accessline 566
new_tab("https://wellfound.com/company/openai")
agent-workspace/domain-skills/weread/read.md
- Network accessline 30
| Page | URL | |------|-----| | Home | `https://weread.qq.com/` | - Network accessline 31
|------|-----| | Home | `https://weread.qq.com/` | | Rising | `https://weread.qq.com/web/category/rising` | - Network accessline 32
| Home | `https://weread.qq.com/` | - Network accessline 33
| Rising | `https://weread.qq.com/web/category/rising` | - Network accessline 34
| Hot Search | `https://weread.qq.com/web/category/hot_search` | - Network accessline 35
| New Book | `https://weread.qq.com/web/category/newbook` | - Network accessline 36
| Book Detail | `https://weread.qq.com/web/bookDetail/{BOOK_ID}` | - Network accessline 37
| Reader | `https://weread.qq.com/web/reader/{BOOK_ID}k{CHAPTER_HASH}` | - Network accessline 42
https://weread.qq.com/web/reader/{BOOK_ID}k{CHAPTER_HASH} - Network accessline 66
1. Navigate to `https://weread.qq.com/` - Network accessline 165
def pick_book_from_new_ranking(): # Navigate to New Book ranking new_tab("https://weread.qq.com/web/category/newbook") - Network accessline 166
# Navigate to New Book ranking new_tab("https://weread.qq.com/web/category/newbook") wait_for_load() - Network accessline 167
new_tab("https://weread.qq.com/web/category/newbook")
agent-workspace/domain-skills/wikipedia/scraping.md
- Network accessline 9
- **Article page** (`/wiki/<Title>`, block 1): one `js()` call returns title, page id, revision, Wikidata id, short description, lead text, every section (level, heading, anchor, plain text), the infobox as label/value rows under their head - Network accessline 10
- **Redirects, disambiguation, missing pages** are reported, not guessed: `/wiki/Ada_Byron` serves Ada Lovelace with `redirected_from: "Ada_Byron"`; `Mercury` has `disambiguation: true`; an unknown title returns `missing: true` (`wgArticleI - Network accessline 11
- **Official API** (block 2, same-origin `fetch()` from a Wikipedia tab): search, batch metadata for up to 50 titles per call (redirects, disambiguation, short description, Wikidata id), the whole article as plain text split into sections ( - Network accessline 25
BASE = "https://en.wikipedia.org" - Network accessline 180
lead: 3186 chars: Augusta Ada King, Countess of Lovelace (née Byron; 10 December 1815 – 27 November 1852), also known as Ada Lovelace, was sections: 29 [(2, 'Biography', 0), (3, 'Childhood', 3977), (3, 'Adult years', 4032), (3, 'Education - Network accessline 181
sections: 29 [(2, 'Biography', 0), (3, 'Childhood', 3977), (3, 'Adult years', 4032), (3, 'Education', 1721), (3, 'Death', 756)] ... last: [('General and cited sources', 0), ('Further reading', 569), ('External links', 1451)] infobox: info - Network accessline 182
infobox: infobox biography vcard | 'The Right Honourable\nThe Countess of Lovelace' | 7 rows | image: https://thumb.wikimedia.org/wikipedia/commons/thumb/4/4c/Ada_Lovelace_ - Network accessline 187
lead: 3760 chars: Tokyo, officially the Tokyo Metropolis, is the capital and most populous city of Japan. The population of the city prope sections: 61 [(2, 'Etymology', 910), (2, 'History', 0), (3, 'Pre-Tokugawa period', 1595), (3, '1590 - Network accessline 188
sections: 61 [(2, 'Etymology', 910), (2, 'History', 0), (3, 'Pre-Tokugawa period', 1595), (3, '1590–1868: Tokugawa period', 1921), (3, '1868–1941', 3062)] ... last: [('Guides', 258), ('Contemporary', 1395), ('External links', 73)] infobox - Network accessline 189
infobox: infobox ib-settlement vcard | 'Tokyo\n東京都' | 35 rows | image: https://thumb.wikimedia.org/wikipedia/commons/thumb/b/b2/Skyscrapers_o - Network accessline 197
lead: 4209 chars: Barack Hussein Obama II (born August 4, 1961) is an American retired politician who served as the 44th president of the sections: 48 [(2, 'Early life and career', 2730), (3, 'Education', 2203), (4, 'College and research - Network accessline 198
sections: 48 [(2, 'Early life and career', 2730), (3, 'Education', 2203), (4, 'College and research jobs', 1040), (4, 'Community organizer and Harvard Law School', 1701), (4, 'University of Chicago Law School', 682)] ... last: [('External l - Network accessline 199
infobox: infobox vcard | 'Barack Obama' | 20 rows | image: https://thumb.wikimedia.org/wikipedia/commons/thumb/8/8d/President_Bar - Network accessline 213
Self-contained. Opens `/wiki/Main_Page` once so `fetch()` is same-origin, then calls only `/w/api.php` and `/api/rest_v1/`. - Network accessline 219
BASE = "https://en.wikipedia.org" - Network accessline 220
# Wikimedia asks API clients to identify themselves; from a browser, Api-User-Agent is the header for that. # The browser's own User-Agent is left untouched. HEADERS = {"Api-User-Agent": "browser-harness-wikipedia-skill/1.0 (https://github. - Network accessline 222
HEADERS = {"Api-User-Agent": "browser-harness-wikipedia-skill/1.0 (https://github.com/browser-use/browser-harness)"} - Network accessline 224
# Same-origin fetch() needs a tab on en.wikipedia.org; /wiki/Main_Page is allowed by robots.txt. - Network accessline 228
def _fetch(url): raw = js("""(async () => { const r = await fetch(%s, {headers: %s}); - Network accessline 229
raw = js("""(async () => { const r = await fetch(%s, {headers: %s});
agent-workspace/domain-skills/world-bank/scraping.md
- Network accessline 3
`https://api.worldbank.org/v2` — free REST API for global development indicators. No API key, no auth, no browser needed. All data via `http_get`. - Network accessline 13
raw = http_get("https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD?format=json") - Network accessline 29
raw = http_get("https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD?format=json") - Network accessline 51
raw = http_get( "https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD" - Network accessline 52
"https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD" - Network accessline 74
raw = http_get( "https://api.worldbank.org/v2/country/US;CN;GB/indicator/SP.POP.TOTL" - Network accessline 75
"https://api.worldbank.org/v2/country/US;CN;GB/indicator/SP.POP.TOTL" - Network accessline 97
raw = http_get( "https://api.worldbank.org/v2/country/all/indicator/NY.GDP.PCAP.CD" - Network accessline 98
"https://api.worldbank.org/v2/country/all/indicator/NY.GDP.PCAP.CD" - Network accessline 135
# Example: all US GDP data (66 years, 2 pages) rows = fetch_all_pages( "https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD" - Network accessline 136
rows = fetch_all_pages( "https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD" "?format=json&per_page=50" - Network accessline 137
"https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD" - Network accessline 151
raw = http_get("https://api.worldbank.org/v2/indicator?format=json&per_page=50") - Network accessline 169
# Topic 3 = Economy & Growth raw = http_get("https://api.worldbank.org/v2/topic/3/indicator?format=json&per_page=50") - Network accessline 170
raw = http_get("https://api.worldbank.org/v2/topic/3/indicator?format=json&per_page=50") - Network accessline 184
raw = http_get("https://api.worldbank.org/v2/country/US?format=json") - Network accessline 190
# Filter countries by income level raw = http_get("https://api.worldbank.org/v2/country?format=json&incomeLevel=LIC&per_page=300") - Network accessline 191
raw = http_get("https://api.worldbank.org/v2/country?format=json&incomeLevel=LIC&per_page=300") - Network accessline 202
raw = http_get("https://api.worldbank.org/v2/topics?format=json") - Network accessline 225
def fetch_indicator(ind_id): url = ( f"https://api.worldbank.org/v2/country/US/indicator/{ind_id}" - Network accessline 226
url = ( f"https://api.worldbank.org/v2/country/US/indicator/{ind_id}" f"?format=json&mrv=5" - Network accessline 227
f"https://api.worldbank.org/v2/country/US/indicator/{ind_id}" - Network accessline 247
https://api.worldbank.org/v2 - Network accessline 293
Find more: `https://api.worldbank.org/v2/indicator?format=json&per_page=50&page=N` - Network accessline 344
- **HTTP 302 redirects HTTP to HTTPS.** Always use `https://` directly to avoid an extra round trip.
agent-workspace/domain-skills/x/article-source-recovery.md
- Network accessline 16
Article cards commonly point to `https://x.com/i/article/<id>`. An anonymous visit to that route may redirect to `x.com/i/jf/onboarding/web?...mode=login`; do not interpret this as evidence that the status itself is private or deleted. - Network accessline 35
LinkedIn wraps external links as `https://www.linkedin.com/redir/redirect?url=<encoded-url>&...`. Decode the `url` query parameter, open that canonical URL directly, and validate the article title and content there.
agent-workspace/domain-skills/x/posting.md
- Network accessline 5
Navigate to `https://x.com/i/flow/login` (not `https://x.com/`) to get the full sign-in modal. The homepage may render a truncated version of the auth buttons. - Network accessline 15
Use the standard form on `https://x.com/i/flow/login`. Ask the user for credentials — do not guess or read them from screenshots. - Network accessline 19
Once logged in, the home feed is at `https://x.com/home`.
agent-workspace/domain-skills/xiaohongshu/scraping.md
- Network accessline 3
URL patterns: - Home / discovery: `https://www.xiaohongshu.com/explore` - Network accessline 4
- Home / discovery: `https://www.xiaohongshu.com/explore` - Network accessline 5
- Search results: `https://www.xiaohongshu.com/search_result?keyword=...` - Network accessline 9
- Prefer direct navigation to the desktop search results page over automating the home-page search box. - Reliable primary path: `https://www.xiaohongshu.com/search_result?keyword=<url-encoded keyword>&source=web_explore_feed` - Network accessline 10
- Reliable primary path: `https://www.xiaohongshu.com/search_result?keyword=<url-encoded keyword>&source=web_explore_feed` - Network accessline 65
- Do **not** assume a raw results link like `https://www.xiaohongshu.com/explore/<id>` is directly openable. - Network accessline 66
- Opening that raw `/explore/<id>` URL in a fresh tab can redirect to the web `404` / app-only gate even when the same post is openable from search results. - To open a post from search results, click the visible card image / card in-page f - Network accessline 67
[Credential-related source omitted] - Network accessline 68
[Credential-related source omitted] - Network accessline 69
- Once the tokenized URL is obtained from the click flow, it can be revisited in-session for extraction. - If the search results state is already loaded, you can reconstruct the tokenized note URL directly from a feed item without re-clicki - Network accessline 71
[Credential-related source omitted]
agent-workspace/domain-skills/yahoo-finance/scraping.md
- Network accessline 9
- **Quote summary**: open `https://finance.yahoo.com/quote/<T>/` in a browser and read the DOM. Price, change and change % are `[data-testid="qsp-price"]`, `qsp-price-change`, `qsp-price-change-percent`; after-hours/pre-market values are th - Network accessline 10
- **Historical OHLCV**: open `https://finance.yahoo.com/quote/<T>/history/?period1=<unix>&period2=<unix>[&frequency=1wk|1mo]`. This is the exact URL the page's own date picker and frequency menu write. The whole range renders as one `<table - Network accessline 87
def quote_summary(symbol): url = f"https://finance.yahoo.com/quote/{urllib.parse.quote(symbol, safe='')}/" # ^GSPC -> %5EGSPC - Network accessline 88
url = f"https://finance.yahoo.com/quote/{urllib.parse.quote(symbol, safe='')}/" # ^GSPC -> %5EGSPC - Network accessline 190
p1 = calendar.timegm(start.timetuple()) p2 = calendar.timegm((end + timedelta(days=1)).timetuple()) base = f"https://finance.yahoo.com/quote/{urllib.parse.quote(symbol, safe='')}/history/" # ^GSPC -> %5EGSPC - Network accessline 191
p2 = calendar.timegm((end + timedelta(days=1)).timetuple()) base = f"https://finance.yahoo.com/quote/{urllib.parse.quote(symbol, safe='')}/history/" # ^GSPC -> %5EGSPC url = f"{base}?period1={p1}&period2={p2}" - Network accessline 192
base = f"https://finance.yahoo.com/quote/{urllib.parse.quote(symbol, safe='')}/history/" # ^GSPC -> %5EGSPC - Network accessline 238
https://finance.yahoo.com/quote/AAPL/history/?period1=1704067200&period2=1711929600
agent-workspace/domain-skills/youtube/playback.md
- Network accessline 10
tab = new_tab("https://www.youtube.com/watch?v=<VIDEO_ID>")
agent-workspace/domain-skills/youtube/scraping.md
- Network accessline 10
`https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={VIDEO_ID}&format=json` - Network accessline 21
Returns title, author, thumbnail URL, and embed iframe HTML. """ url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={video_id}&format=json" - Network accessline 22
""" url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={video_id}&format=json" return json.loads(http_get(url)) - Network accessline 23
url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={video_id}&format=json" - Network accessline 28
# "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)", # "author_name": "Rick Astley", # "author_url": "https://www.youtube.com/@RickAstleyYT", - Network accessline 29
# "author_name": "Rick Astley", # "author_url": "https://www.youtube.com/@RickAstleyYT", # "type": "video", - Network accessline 30
# "author_url": "https://www.youtube.com/@RickAstleyYT", - Network accessline 31
# "type": "video", # "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg", # "thumbnail_width": 480, - Network accessline 32
# "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg", - Network accessline 37
# "version": "1.0", # "provider_name": "YouTube", # "html": '<iframe width="200" height="113" src="https://www.youtube.com/embed/dQw4w9WgXcQ?feature=oembed" ...>' - Network accessline 38
# "provider_name": "YouTube", # "html": '<iframe width="200" height="113" src="https://www.youtube.com/embed/dQw4w9WgXcQ?feature=oembed" ...>' # } - Network accessline 39
# "html": '<iframe width="200" height="113" src="https://www.youtube.com/embed/dQw4w9WgXcQ?feature=oembed" ...>' - Network accessline 52
def fetch_oembed(vid): url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={vid}&format=json" - Network accessline 53
url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={vid}&format=json" - Network accessline 79
def scrape_video(video_id): html = http_get(f"https://www.youtube.com/watch?v={video_id}") - Network accessline 80
html = http_get(f"https://www.youtube.com/watch?v={video_id}") - Network accessline 124
"embed_url": mf.get("embed", {}).get("iframeUrl"), # Thumbnails (all publicly accessible, no auth) "thumbnail_hq": f"https://i.ytimg.com/vi/{video_id}/hqdefault.jpg", # 480×360, always exists - Network accessline 125
# Thumbnails (all publicly accessible, no auth) "thumbnail_hq": f"https://i.ytimg.com/vi/{video_id}/hqdefault.jpg", # 480×360, always exists "thumbnail_max": f"https://i.ytimg.com/vi/{video_id}/maxresdefault.jpg", # 1280 - Network accessline 126
"thumbnail_hq": f"https://i.ytimg.com/vi/{video_id}/hqdefault.jpg", # 480×360, always exists - Network accessline 127
"thumbnail_max": f"https://i.ytimg.com/vi/{video_id}/maxresdefault.jpg", # 1280×720, may 404 - Network accessline 172
def youtube_search(query, max_results=20): """Search YouTube videos without a browser or API key.""" url = f"https://www.youtube.com/results?search_query={quote_plus(query)}" - Network accessline 173
"""Search YouTube videos without a browser or API key.""" url = f"https://www.youtube.com/results?search_query={quote_plus(query)}" html = http_get(url) - Network accessline 174
url = f"https://www.youtube.com/results?search_query={quote_plus(query)}" - Network accessline 200
results.append({ "video_id": vr["videoId"], "url": f"https://www.youtube.com/watch?v={vr['videoId']}", - Network accessline 201
"video_id": vr["videoId"], "url": f"https://www.youtube.com/watch?v={vr['videoId']}", "title": vr.get("title", {}).get("runs", [{}])[0].get("text"), - Network accessline 202
"url": f"https://www.youtube.com/watch?v={vr['videoId']}", - Network accessline 204
"channel": vr.get("ownerText", {}).get("runs", [{}])[0].get("text"), "channel_url": ( "https://www.youtube.com" - Network accessline 205
"channel_url": ( "https://www.youtube.com" + vr.get("ownerText", {}).get("runs", [{}])[0] - Network accessline 206
"https://www.youtube.com" - Network accessline 214
"published": vr.get("publishedTimeText", {}).get("simpleText"), # e.g. "7 years ago" "description_snippet": desc, "thumbnail": f"https://i.ytimg.com/vi/{vr['videoId']}/hqdefault.jpg", - Network accessline 215
"description_snippet": desc, "thumbnail": f"https://i.ytimg.com/vi/{vr['videoId']}/hqdefault.jpg", }) - Network accessline 216
"thumbnail": f"https://i.ytimg.com/vi/{vr['videoId']}/hqdefault.jpg", - Network accessline 250
""" if handle_or_id.startswith("UC"): url = f"https://www.youtube.com/channel/{handle_or_id}" - Network accessline 251
if handle_or_id.startswith("UC"): url = f"https://www.youtube.com/channel/{handle_or_id}" else: - Network accessline 252
url = f"https://www.youtube.com/channel/{handle_or_id}" - Network accessline 254
url = f"https://www.youtube.com/{handle_or_id}" - Network accessline 314
# "title": "Rick Astley", # "description": "2026 UK & Ireland Reflection Tour...", # "channel_url": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - Network accessline 315
# "description": "2026 UK & Ireland Reflection Tour...", # "channel_url": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", # "handle": "@RickAstleyYT", - Network accessline 316
# "channel_url": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - Network accessline 317
# "handle": "@RickAstleyYT", # "subscribers": "4.48m subscribers", # "avatar_url": "https://yt3.googleusercontent.com/...", - Network accessline 318
# "subscribers": "4.48m subscribers", # "avatar_url": "https://yt3.googleusercontent.com/...", # "banner_url": "https://yt3.googleusercontent.com/...", - Network accessline 319
# "avatar_url": "https://yt3.googleusercontent.com/...", - Network accessline 320
# "banner_url": "https://yt3.googleusercontent.com/...", - Network accessline 331
def thumbnail_urls(video_id): base = f"https://i.ytimg.com/vi/{video_id}" - Network accessline 332
base = f"https://i.ytimg.com/vi/{video_id}" - Network accessline 354
extract_video_id("https://www.youtube.com/watch?v=dQw4w9WgXcQ") # "dQw4w9WgXcQ" - Network accessline 355
extract_video_id("https://youtu.be/dQw4w9WgXcQ") # "dQw4w9WgXcQ" - Network accessline 356
extract_video_id("https://www.youtube.com/shorts/dQw4w9WgXcQ") # "dQw4w9WgXcQ" - Network accessline 357
extract_video_id("https://www.youtube.com/embed/dQw4w9WgXcQ") # "dQw4w9WgXcQ" - Network accessline 391
| Resource | URL pattern | |----------------|--------------------------------------------------------------------| | Video | `https://www.youtube.com/watch?v={VIDEO_ID}` - Network accessline 392
|----------------|--------------------------------------------------------------------| | Video | `https://www.youtube.com/watch?v={VIDEO_ID}` | | Short URL | `https://youtu.be/{VIDEO_ID}` - Network accessline 393
| Video | `https://www.youtube.com/watch?v={VIDEO_ID}` | - Network accessline 394
| Short URL | `https://youtu.be/{VIDEO_ID}` | - Network accessline 395
| Shorts | `https://www.youtube.com/shorts/{VIDEO_ID}` | - Network accessline 396
| Channel handle | `https://www.youtube.com/@{HANDLE}` | - Network accessline 397
| Channel ID | `https://www.youtube.com/channel/{CHANNEL_ID}` | - Network accessline 398
| Playlist | `https://www.youtube.com/playlist?list={PLAYLIST_ID}` | - Network accessline 399
| Search | `https://www.youtube.com/results?search_query={QUERY}` | - Network accessline 400
| oEmbed | `https://www.youtube.com/oembed?url={VIDEO_URL}&format=json` | - Network accessline 401
| Thumbnail (HQ) | `https://i.ytimg.com/vi/{VIDEO_ID}/hqdefault.jpg` | - Network accessline 413
- **Channel subscriber count is a rounded string** — `"4.48m subscribers"`, not an integer. Parse with regex if sorting: `re.search(r'([\d.]+)\s*([km]?)', text, re.I)`. - **`meta_parts` order is `[handle, subscribers, video_count]`** — the - Network accessline 414
- **`meta_parts` order is `[handle, subscribers, video_count]`** — the third element is not always present. Index defensively. - **Caption `baseUrl` is not fetchable** — `captionTracks[].baseUrl` contains `expire=` and `signature=` params b - Network accessline 415
- **Caption `baseUrl` is not fetchable** — `captionTracks[].baseUrl` contains `expire=` and `signature=` params but returns empty bytes in all tested conditions (plain `http_get`, XHR from within the page, and `fetch()` with cookies). Use t
agent-workspace/domain-skills/zillow/scraping.md
- Network accessline 39
html = http_get("https://www.zillow.com/homes/San-Francisco,-CA_rb/", headers=HEADERS) - Network accessline 58
| `latLong` | listing | `{'latitude': 37.78867, 'longitude': -122.45361}` | | `statusType` | listing | `"FOR_SALE"` / `"FOR_RENT"` / `"RECENTLY_SOLD"` | | `detailUrl` | listing | full `https://www.zillow.com/homedetails/...` URL | - Network accessline 59
| `statusType` | listing | `"FOR_SALE"` / `"FOR_RENT"` / `"RECENTLY_SOLD"` | | `detailUrl` | listing | full `https://www.zillow.com/homedetails/...` URL | | `zestimate` | listing | `4857200` (Zillow AI estimate, int) | - Network accessline 60
| `detailUrl` | listing | full `https://www.zillow.com/homedetails/...` URL | - Network accessline 112
# Each page returns exactly 41 listings. Add /<N>_p/ for subsequent pages: # Page 2: https://www.zillow.com/homes/San-Francisco,-CA_rb/2_p/ - Network accessline 113
# Page 2: https://www.zillow.com/homes/San-Francisco,-CA_rb/2_p/ - Network accessline 114
# Page 3: https://www.zillow.com/homes/San-Francisco,-CA_rb/3_p/ - Network accessline 132
"""city_slug: e.g. 'San-Francisco,-CA', 'Seattle,-WA', 'Austin,-TX'""" if page == 1: url = f"https://www.zillow.com/homes/{city_slug}_rb/" - Network accessline 133
if page == 1: url = f"https://www.zillow.com/homes/{city_slug}_rb/" else: - Network accessline 134
url = f"https://www.zillow.com/homes/{city_slug}_rb/" - Network accessline 135
else: url = f"https://www.zillow.com/homes/{city_slug}_rb/{page}_p/" html = http_get(url, headers=HEADERS) - Network accessline 136
url = f"https://www.zillow.com/homes/{city_slug}_rb/{page}_p/" - Network accessline 182
html = http_get("https://www.zillow.com/san-francisco-ca/rentals/", headers=HEADERS) - Network accessline 211
html = http_get("https://www.zillow.com/san-francisco-ca/sold/", headers=HEADERS) - Network accessline 271
html = http_get( "https://www.redfin.com/city/17151/CA/San-Francisco/filter/property-type=house", - Network accessline 272
"https://www.redfin.com/city/17151/CA/San-Francisco/filter/property-type=house", - Network accessline 296
print("Floor size:", prop['floorSize']) # {'@type': 'QuantitativeValue', 'value': 3350, 'unitCode': 'FTK'} print("URL:", prop['url']) # https://www.redfin.com/CA/San-Francisco/662-Hampshire-St-94110/home/1533754 - Network accessline 298
# https://www.redfin.com/CA/San-Francisco/662-Hampshire-St-94110/home/1533754 - Network accessline 315
""" url = ( f"https://www.redfin.com/stingray/api/gis" - Network accessline 316
url = ( f"https://www.redfin.com/stingray/api/gis" f"?al=1&num_homes={num_homes}&ord=redfin-recommended-asc" - Network accessline 317
f"https://www.redfin.com/stingray/api/gis" - Network accessline 322
raw = http_get(url, headers={ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Referer": "https://www.redfin.com/", - Network accessline 323
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Referer": "https://www.redfin.com/", "Accept": "*/*", - Network accessline 324
"Referer": "https://www.redfin.com/", - Network accessline 437
Field-tested 2026-07-31. Task: "download all listing photos" for one address when `/homedetails/` is PX-walled (curl AND `--headless=new` both get the captcha page). - Network accessline 438
`/homedetails/` is PX-walled (curl AND `--headless=new` both get the captcha page). - Network accessline 443
search for `"<address>" movoto` (their slug embeds an internal ID you can't guess). The listing page (`/for-sale/` variant for sold homes) embeds every gallery image as `https://pi.movoto.com/p/101/<MLS#>_0_<hash>.jpeg` — plain curl w - Network accessline 444
The listing page (`/for-sale/` variant for sold homes) embeds every gallery image as `https://pi.movoto.com/p/101/<MLS#>_0_<hash>.jpeg` — plain curl with a Chrome UA returns all of them (a 54-photo gallery came back complete). ~1150px - Network accessline 445
`https://pi.movoto.com/p/101/<MLS#>_0_<hash>.jpeg` — plain curl with a Chrome UA
agent-workspace/domain-skills/zoopla/scraping.md
- Network accessline 33
if not re.fullmatch(r"[a-z0-9-]+(/[a-z0-9-]+)*", area) or BAD_SEGMENTS & set(area.split("/")): raise ValueError(f"bad area slug {area!r}") base = f"https://www.zoopla.co.uk/for-sale/property/{area}/" - Network accessline 34
raise ValueError(f"bad area slug {area!r}") base = f"https://www.zoopla.co.uk/for-sale/property/{area}/" return base if page == 1 else f"{base}?pn={page}" # ?pn= is allowed; ?rpn= / ?qpn= / q= are not - Network accessline 35
base = f"https://www.zoopla.co.uk/for-sale/property/{area}/" - Network accessline 135
"under_offer": x.get("underOffer"), "summary": html.unescape(x.get("summaryDescription") or ""), "url": "https://www.zoopla.co.uk" + uri if uri else None, - Network accessline 136
"summary": html.unescape(x.get("summaryDescription") or ""), "url": "https://www.zoopla.co.uk" + uri if uri else None, } - Network accessline 137
"url": "https://www.zoopla.co.uk" + uri if uri else None, - Network accessline 179
bristol | total 3643 | pages 40 | stopped max_pages | rows 50 {"id": "71129298", "address": "\"The Gilder\" at Stillwell Road, Cribbs Causeway, Almondsbury, Bristol BS10", "price": 460000, "price_text": "£460,000", "beds": 4, "baths": null, - Network accessline 180
{"id": "71129298", "address": "\"The Gilder\" at Stillwell Road, Cribbs Causeway, Almondsbury, Bristol BS10", "price": 460000, "price_text": "£460,000", "beds": 4, "baths": null, "receptions": null, "sqft": null, "type": "semi_detached", "t - Network accessline 181
{"id": "73091249", "address": "\"The Jeweller\" at Stillwell Road, Cribbs Causeway, Almondsbury, Bristol BS10", "price": 675000, "price_text": "£675,000", "beds": 4, "baths": null, "receptions": null, "sqft": null, "type": "detached", "titl - Network accessline 182
bs8 | total 229 | pages 10 | stopped last_page | rows 229 {"id": "73753592", "address": "The Avenue, Clifton BS8", "price": 560000, "price_text": "£560,000", "beds": 3, "baths": 2, "receptions": 1, "sqft": 1094, "type": "flat", "title": "3 - Network accessline 183
{"id": "73753592", "address": "The Avenue, Clifton BS8", "price": 560000, "price_text": "£560,000", "beds": 3, "baths": 2, "receptions": 1, "sqft": 1094, "type": "flat", "title": "3 bed flat for sale", "agent": "Elephant Estate Agents, Bris - Network accessline 184
{"id": "73215714", "address": "Oakfield Road, Clifton, Bristol BS8", "price": 429000, "price_text": "Guide price £429,000", "beds": 2, "baths": 2, "receptions": 1, "sqft": null, "type": "flat", "title": "2 bed flat for sale", "agent": "Howa - Network accessline 255
def get_listing(listing_id): """Detail page -> dict, or None when Zoopla redirects away (removed listing).""" url = f"https://www.zoopla.co.uk/for-sale/details/{listing_id}/" - Network accessline 256
"""Detail page -> dict, or None when Zoopla redirects away (removed listing).""" url = f"https://www.zoopla.co.uk/for-sale/details/{listing_id}/" href, rows, lds = load_flight(url) - Network accessline 257
url = f"https://www.zoopla.co.uk/for-sale/details/{listing_id}/" - Network accessline 304
# 1) pick live /for-sale/details/ ids from a search page href, rows, _ = load_flight(f"https://www.zoopla.co.uk/for-sale/property/{SEARCH_AREA}/") - Network accessline 305
href, rows, _ = load_flight(f"https://www.zoopla.co.uk/for-sale/property/{SEARCH_AREA}/") - Network accessline 323
{"id": "73753592", "url": "https://www.zoopla.co.uk/for-sale/details/73753592/", "title": "3 bed flat for sale", "address": "The Avenue, Clifton BS8", "postcode": "BS8 3GE", "price": 560000, "price_text": "£560,000", "ld_price": 560000, "be - Network accessline 324
{"id": "73215714", "url": "https://www.zoopla.co.uk/for-sale/details/73215714/", "title": "2 bed flat for sale", "address": "Oakfield Road, Clifton, Bristol BS8", "postcode": "BS8 2BG", "price": 429000, "price_text": "Guide price £429,000", - Network accessline 325
1: redirected to https://www.zoopla.co.uk/overseas/, listing not available - Network accessline 366
Also in `ListingData`: `additionalNtsInfo` (water, heating, broadband, parking: mostly "Ask agent"), `epc.image`, `floorPlan.image`, `propertyImage[].filename` (photos at `https://lid.zoocdn.com/645/430/<filename>`), `adTargeting` (`priceMi
browser-harness
docs/MCP.md
- Network accessline 53
1. `browser_new_tab(url="https://example.com")`
docs/snap-linux-headless.md
- Network accessline 5
Ubuntu and several other distributions ship Chromium as a [Snap](https://snapcraft.io/) package. Snap runs apps in a confined environment. Chrome’s remote debugging endpoint must bind on the host network where the `browser-harness` daemon c - Network accessline 7
Symptoms: `browser-harness --doctor` shows Chrome running, but the daemon never attaches, or CDP handshake fails without an obvious cause. [Issue #191](https://github.com/browser-use/browser-harness/issues/191) discusses this class of setup - Network accessline 14
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - Dangerous shell operationline 15
sudo apt install ./google-chrome-stable_current_amd64.deb - Network accessline 18
ARM or other architectures: download the matching package from [Google Chrome for Linux](https://www.google.com/chrome/linux/).
interaction-skills/connection.md
interaction-skills/cookies.md
- Access to secretsline 3
[Credential-related source omitted]
interaction-skills/dialogs.md
- Network accessline 54
# Option A: dismiss after navigating (CDP-level, safe) goto_url("https://new-url.com") - Network accessline 55
goto_url("https://new-url.com") - Network accessline 61
# Option B: prevent before navigating (JS injection, detectable) js("window.onbeforeunload=null") goto_url("https://new-url.com") - Network accessline 63
goto_url("https://new-url.com")
interaction-skills/profile-sync.md
- Dangerous shell operationline 8
curl -fsSL https://browser-use.com/profile.sh | sh - Network accessline 8
curl -fsSL https://browser-use.com/profile.sh | sh - Access to secretsline 76
[Credential-related source omitted] - Network accessline 80
- UI: https://cloud.browser-use.com/settings?tab=profiles - Network accessline 81
- API: `GET /profiles`, `GET/PATCH/DELETE /profiles/{id}` (paths are relative to `BU_API = "https://api.browser-use.com/api/v3"` in `admin.py`). Fields: `id`, `name`, `userId`, `lastUsedAt`, `cookieDomains[]`. `list_cloud_profiles()` wraps
interaction-skills/tabs.md
- Network accessline 8
tabs = list_tabs() # includes chrome:// pages too real_tabs = list_tabs(include_chrome=False) tid = new_tab("https://example.com") # create + attach in the background - Network accessline 9
real_tabs = list_tabs(include_chrome=False) tid = new_tab("https://example.com") # create + attach in the background switch_tab(tid) # attach harness, move the horse marker - Network accessline 10
tid = new_tab("https://example.com") # create + attach in the background
pyproject.toml
- Network accessline 38
[project.urls] Homepage = "https://github.com/browser-use/browser-harness" - Network accessline 39
Homepage = "https://github.com/browser-use/browser-harness" - Network accessline 40
Repository = "https://github.com/browser-use/browser-harness" - Network accessline 41
Issues = "https://github.com/browser-use/browser-harness/issues"
skills/browser-harness/SKILL.md
- Network accessline 1
--- name: browser-harness description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." - Network accessline 2
name: browser-harness description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." --- - Network accessline 3
description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." - Network accessline 8
Direct browser control via CDP. For task-specific edits, use `agent-workspace/agent_helpers.py`. For setup, install, or connection problems, read https://github.com/browser-use/browser-harness/blob/main/install.md. - Access to secretsline 143
[Credential-related source omitted] - Network accessline 150
You can also direct the user to try the same agent behind Browser Harness, fully hosted, in Browser Use Cloud (it's called the v4 agent): https://cloud.browser-use.com?utm_source=skill&utm_medium=browser-use&utm_campaign=v4. - Access to secretsline 161
[Credential-related source omitted] - Network accessline 171
BU_NAME=r7k2 browser-harness <<'PY' new_tab("https://example.com") - Network accessline 172
new_tab("https://example.com") - Network accessline 183
Cloud profile cookie sync reference: https://github.com/browser-use/browser-harness/blob/main/interaction-skills/profile-sync.md. - Network accessline 223
Use it only if timestamps and pages match; otherwise say the work was not captured. Never reenact a completed task. For a video, follow [make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.m - Network accessline 224
captured. Never reenact a completed task. For a video, follow [make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.md). If sub-agents are available, they may handle post-production from the - Network accessline 225
[make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.md). - Network accessline 231
If you get stuck on a browser mechanic, check https://github.com/browser-use/browser-harness/tree/main/interaction-skills.
skills/browser-harness/references/install.md
- Network accessline 45
- **Way 1 (real browser):** open Chrome normally, then open `chrome://inspect/#remote-debugging` and tick "Allow remote debugging for this browser instance". On Chrome 144+, click Allow on the first-attach popup. Inherits your logins/extens - Network accessline 46
- **Way 2 (isolated profile, no popups):** launch Chrome with `--remote-debugging-port=9222 --user-data-dir=<non-default path>`, then set `BU_CDP_URL=http://127.0.0.1:9222`. Best for unattended automation.
src/browser_harness/SKILL.md
- Network accessline 1
--- name: browser-harness description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." - Network accessline 2
name: browser-harness description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." --- - Network accessline 3
description: "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those." - Network accessline 8
Direct browser control via CDP. For task-specific edits, use `agent-workspace/agent_helpers.py`. For setup, install, or connection problems, read https://github.com/browser-use/browser-harness/blob/main/install.md. - Access to secretsline 143
[Credential-related source omitted] - Network accessline 150
You can also direct the user to try the same agent behind Browser Harness, fully hosted, in Browser Use Cloud (it's called the v4 agent): https://cloud.browser-use.com?utm_source=skill&utm_medium=browser-use&utm_campaign=v4. - Access to secretsline 161
[Credential-related source omitted] - Network accessline 171
BU_NAME=r7k2 browser-harness <<'PY' new_tab("https://example.com") - Network accessline 172
new_tab("https://example.com") - Network accessline 183
Cloud profile cookie sync reference: https://github.com/browser-use/browser-harness/blob/main/interaction-skills/profile-sync.md. - Network accessline 223
Use it only if timestamps and pages match; otherwise say the work was not captured. Never reenact a completed task. For a video, follow [make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.m - Network accessline 224
captured. Never reenact a completed task. For a video, follow [make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.md). If sub-agents are available, they may handle post-production from the - Network accessline 225
[make-video.md](https://github.com/browser-use/browser-harness/blob/main/interaction-skills/make-video.md). - Network accessline 231
If you get stuck on a browser mechanic, check https://github.com/browser-use/browser-harness/tree/main/interaction-skills.
src/browser_harness/__init__.py
- Executable scriptline 1
Executable file
src/browser_harness/_ipc.py
- Executable scriptline 1
Executable file - Access to secretsline 18
[Credential-related source omitted] - Access to secretsline 19
[Credential-related source omitted] - Access to secretsline 20
[Credential-related source omitted] - Access to secretsline 21
[Credential-related source omitted] - Network accessline 88
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - Network accessline 90
[Credential-related source omitted] - Network accessline 91
if port is None: raise FileNotFoundError(str(port_path(name))) s = socket.create_connection(("127.0.0.1", port), timeout=timeout) s.settimeout(timeout); return s, token - Network accessline 92
s = socket.create_connection(("127.0.0.1", port), timeout=timeout)
src/browser_harness/admin.py
- Executable scriptline 1
Executable file - Access to secretsline 111
[Credential-related source omitted] - Access to secretsline 123
[Credential-related source omitted] - Network accessline 128
[Credential-related source omitted] - Access to secretsline 128
[Credential-related source omitted] - Network accessline 129
BU_API = "https://api.browser-use.com/api/v3" - Network accessline 130
PYPI_JSON = "https://pypi.org/pypi/browser-harness/json" - Access to secretsline 355
[Credential-related source omitted] - Access to secretsline 356
[Credential-related source omitted] - Access to secretsline 477
[Credential-related source omitted] - Network accessline 497
def _snap_linux_headless_doc_url(): return "https://github.com/browser-use/browser-harness/blob/main/docs/snap-linux-headless.md" - Network accessline 498
return "https://github.com/browser-use/browser-harness/blob/main/docs/snap-linux-headless.md" - Network accessline 508
print() print("1. Install Google Chrome from Google's .deb (not the Snap store):") print(" wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb") - Network accessline 509
print("1. Install Google Chrome from Google's .deb (not the Snap store):") print(" wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb") print(" sudo apt install ./google-chrome-stable_current_amd64.de - Network accessline 510
print(" wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb") - Dangerous shell operationline 511
print(" sudo apt install ./google-chrome-stable_current_amd64.deb") - Access to secretsline 562
[Credential-related source omitted] - Network accessline 886
def _browser_use(path, method, body=None): key = auth.get_browser_use_api_key() req = urllib.request.Request( - Network accessline 887
[Credential-related source omitted] - Access to secretsline 887
[Credential-related source omitted] - Network accessline 888
req = urllib.request.Request( - Network accessline 892
[Credential-related source omitted] - Network accessline 894
return json.loads(urllib.request.urlopen(req, timeout=60).read() or b"{}") - Network accessline 914
def _cdp_ws_from_url(cdp_url): return json.loads(urllib.request.urlopen(f"{cdp_url}/json/version", timeout=15).read())["webSocketDebuggerUrl"] - Network accessline 915
return json.loads(urllib.request.urlopen(f"{cdp_url}/json/version", timeout=15).read())["webSocketDebuggerUrl"] - Access to secretsline 925
[Credential-related source omitted] - Access to secretsline 946
[Credential-related source omitted] - Network accessline 1041
import json, shutil, subprocess if not shutil.which("profile-use"): raise RuntimeError("profile-use not installed -- curl -fsSL https://browser-use.com/profile.sh | sh") - Network accessline 1042
if not shutil.which("profile-use"): raise RuntimeError("profile-use not installed -- curl -fsSL https://browser-use.com/profile.sh | sh") return json.loads(subprocess.check_output(["profile-use", "list", "--json"], text=True, en - Dangerous shell operationline 1043
raise RuntimeError("profile-use not installed -- curl -fsSL https://browser-use.com/profile.sh | sh") - Network accessline 1043
raise RuntimeError("profile-use not installed -- curl -fsSL https://browser-use.com/profile.sh | sh") - Access to secretsline 1051
[Credential-related source omitted] - Network accessline 1066
import shutil, subprocess, sys if not shutil.which("profile-use"): raise RuntimeError("profile-use not installed -- curl -fsSL https://browser-use.com/profile.sh | sh") - Network accessline 1067
if not shutil.which("profile-use"): raise RuntimeError("profile-use not installed -- curl -fsSL https://browser-use.com/profile.sh | sh") key = auth.get_browser_use_api_key() - Dangerous shell operationline 1068
raise RuntimeError("profile-use not installed -- curl -fsSL https://browser-use.com/profile.sh | sh") - Network accessline 1068
raise RuntimeError("profile-use not installed -- curl -fsSL https://browser-use.com/profile.sh | sh") - Access to secretsline 1069
[Credential-related source omitted] - Access to secretsline 1079
[Credential-related source omitted] - Network accessline 1154
return cache["tag"] try: tag = json.loads(urllib.request.urlopen(PYPI_JSON, timeout=5).read()).get("info", {}).get("version") or "" - Network accessline 1155
try: tag = json.loads(urllib.request.urlopen(PYPI_JSON, timeout=5).read()).get("info", {}).get("version") or "" except Exception: - Network accessline 1156
tag = json.loads(urllib.request.urlopen(PYPI_JSON, timeout=5).read()).get("info", {}).get("version") or "" - Access to secretsline 1188
[Credential-related source omitted] - Access to secretsline 1291
[Credential-related source omitted]
src/browser_harness/auth.py
- Executable scriptline 1
Executable file - Network accessline 29
AUTH_BASE = "https://api.browser-use.com" - Access to secretsline 83
[Credential-related source omitted] - Access to secretsline 92
[Credential-related source omitted] - Access to secretsline 93
[Credential-related source omitted] - Access to secretsline 94
[Credential-related source omitted] - Access to secretsline 99
[Credential-related source omitted] - Access to secretsline 109
[Credential-related source omitted] - Access to secretsline 119
[Credential-related source omitted] - Access to secretsline 123
[Credential-related source omitted] - Access to secretsline 127
[Credential-related source omitted] - Access to secretsline 182
[Credential-related source omitted] - Access to secretsline 183
[Credential-related source omitted] - Access to secretsline 187
[Credential-related source omitted] - Access to secretsline 194
[Credential-related source omitted] - Access to secretsline 197
[Credential-related source omitted] - Network accessline 213
server = _callback_server(callback) host, port = server.server_address redirect_uri = f"http://{host}:{port}{CALLBACK_PATH}" - Network accessline 214
host, port = server.server_address redirect_uri = f"http://{host}:{port}{CALLBACK_PATH}" req = { - Network accessline 215
redirect_uri = f"http://{host}:{port}{CALLBACK_PATH}" - Access to secretsline 223
[Credential-related source omitted] - Access to secretsline 301
[Credential-related source omitted] - Access to secretsline 378
[Credential-related source omitted] - Network accessline 427
def _post_json(url: str, payload: dict) -> dict: req = urllib.request.Request( - Network accessline 428
req = urllib.request.Request( - Network accessline 433
) try: with urllib.request.urlopen(req, timeout=60) as resp: - Network accessline 434
try: with urllib.request.urlopen(req, timeout=60) as resp: return json.loads(resp.read() or b"{}") - Network accessline 435
with urllib.request.urlopen(req, timeout=60) as resp:
src/browser_harness/daemon.py
- Executable scriptline 1
Executable file - Access to secretsline 16
[Credential-related source omitted] - Access to secretsline 28
[Credential-related source omitted] - Access to secretsline 33
[Credential-related source omitted] - Access to secretsline 105
[Credential-related source omitted] - Network accessline 112
PROFILES = profile_dirs() INTERNAL = ("chrome://", "chrome-untrusted://", "devtools://", "chrome-extension://", "about:") BU_API = "https://api.browser-use.com/api/v3" - Network accessline 113
INTERNAL = ("chrome://", "chrome-untrusted://", "devtools://", "chrome-extension://", "about:") BU_API = "https://api.browser-use.com/api/v3" REMOTE_ID = os.environ.get("BU_BROWSER_ID") - Network accessline 114
BU_API = "https://api.browser-use.com/api/v3" - Access to secretsline 115
[Credential-related source omitted] - Access to secretsline 117
[Credential-related source omitted] - Access to secretsline 135
[Credential-related source omitted] - Network accessline 147
return False try: socket.create_connection(("127.0.0.1", port), timeout=0.5).close() - Network accessline 148
try: socket.create_connection(("127.0.0.1", port), timeout=0.5).close() return True - Network accessline 149
socket.create_connection(("127.0.0.1", port), timeout=0.5).close() - Access to secretsline 265
[Credential-related source omitted] - Access to secretsline 267
[Credential-related source omitted] - Network accessline 268
# HTTP DevTools endpoint (e.g. http://127.0.0.1:9333) — resolve to ws via /json/version. - Network accessline 274
while time.time() < deadline: try: return json.loads(urllib.request.urlopen(f"{base_url}/json/version", timeout=5).read())["webSocketDebuggerUrl"] - Network accessline 275
try: return json.loads(urllib.request.urlopen(f"{base_url}/json/version", timeout=5).read())["webSocketDebuggerUrl"] except urllib.error.HTTPError as e: - Network accessline 276
return json.loads(urllib.request.urlopen(f"{base_url}/json/version", timeout=5).read())["webSocketDebuggerUrl"] - Network accessline 307
try: return json.loads(urllib.request.urlopen(f"http://127.0.0.1:{port}/json/version", timeout=1).read())["webSocketDebuggerUrl"] - Network accessline 308
return json.loads(urllib.request.urlopen(f"http://127.0.0.1:{port}/json/version", timeout=1).read())["webSocketDebuggerUrl"] - Network accessline 331
for probe_port in (9222, 9223): try: with urllib.request.urlopen(f"http://127.0.0.1:{probe_port}/json/version", timeout=1) as r: - Network accessline 332
try: with urllib.request.urlopen(f"http://127.0.0.1:{probe_port}/json/version", timeout=1) as r: return json.loads(r.read())["webSocketDebuggerUrl"] - Network accessline 333
with urllib.request.urlopen(f"http://127.0.0.1:{probe_port}/json/version", timeout=1) as r: - Network accessline 353
try: key = auth.get_browser_use_api_key() req = urllib.request.Request( - Network accessline 354
[Credential-related source omitted] - Access to secretsline 354
[Credential-related source omitted] - Network accessline 355
req = urllib.request.Request( - Network accessline 359
[Credential-related source omitted] - Network accessline 360
) urllib.request.urlopen(req, timeout=15).read() _REMOTE_STOPPED = True - Network accessline 361
urllib.request.urlopen(req, timeout=15).read() - Access to secretsline 646
[Credential-related source omitted]
src/browser_harness/helpers.py
- Executable scriptline 1
Executable file - Access to secretsline 20
[Credential-related source omitted] - Access to secretsline 33
[Credential-related source omitted] - Access to secretsline 38
[Credential-related source omitted] - Access to secretsline 154
[Credential-related source omitted] - Access to secretsline 175
[Credential-related source omitted] - Possible obfuscationline 346
open(path, "wb").write(base64.b64decode(r["data"])) - Access to secretsline 390
[Credential-related source omitted] - Access to secretsline 631
[Credential-related source omitted] - Access to secretsline 633
[Credential-related source omitted] - Network accessline 640
h = {"User-Agent": "Mozilla/5.0", "Accept-Encoding": "gzip"} if headers: h.update(headers) with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=timeout) as r: - Network accessline 641
if headers: h.update(headers) with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=timeout) as r: data = r.read() - Network accessline 642
with urllib.request.urlopen(urllib.request.Request(url, headers=h), timeout=timeout) as r:
src/browser_harness/macos.py
- Executable scriptline 1
Executable file
src/browser_harness/mcp_cli.py
- Executable scriptline 1
Executable file
src/browser_harness/paths.py
- Executable scriptline 1
Executable file - Access to secretsline 10
[Credential-related source omitted] - Access to secretsline 13
[Credential-related source omitted] - Access to secretsline 28
[Credential-related source omitted] - Access to secretsline 38
[Credential-related source omitted] - Access to secretsline 43
[Credential-related source omitted] - Access to secretsline 48
[Credential-related source omitted]
src/browser_harness/recorder.py
- Executable scriptline 1
Executable file - Access to secretsline 45
[Credential-related source omitted] - Access to secretsline 46
[Credential-related source omitted] - Access to secretsline 87
[Credential-related source omitted] - Access to secretsline 94
[Credential-related source omitted] - Access to secretsline 206
[Credential-related source omitted] - Possible obfuscationline 288
data = base64.b64decode(shot["data"])
src/browser_harness/run.py
- Executable scriptline 1
Executable file - Network accessline 83
for port in (9222, 9223): try: with urllib.request.urlopen(f"http://127.0.0.1:{port}/json/version", timeout=0.3) as response: - Network accessline 84
try: with urllib.request.urlopen(f"http://127.0.0.1:{port}/json/version", timeout=0.3) as response: version = json.loads(response.read()) - Network accessline 85
with urllib.request.urlopen(f"http://127.0.0.1:{port}/json/version", timeout=0.3) as response: - Access to secretsline 100
[Credential-related source omitted] - Access to secretsline 105
[Credential-related source omitted] - Access to secretsline 375
[Credential-related source omitted] - Access to secretsline 384
[Credential-related source omitted] - Access to secretsline 390
[Credential-related source omitted] - Access to secretsline 400
[Credential-related source omitted] - Dangerous shell operationline 409
exec(code, globals())
src/browser_harness/telemetry.py
- Executable scriptline 1
Executable file - Network accessline 18
POSTHOG_KEY = "phc_rCPCLPtaXB3EuBdiH7JLKtU2Wj5iPnuwdsbw58CnjYXc" POSTHOG_HOST = "https://eu.i.posthog.com" - Network accessline 19
POSTHOG_HOST = "https://eu.i.posthog.com" - Access to secretsline 23
[Credential-related source omitted] - Access to secretsline 83
[Credential-related source omitted] - Access to secretsline 167
[Credential-related source omitted] - Network accessline 175
try: job = json.load(sys.stdin) request = urllib.request.Request( - Network accessline 176
job = json.load(sys.stdin) request = urllib.request.Request( job['url'], - Network accessline 177
request = urllib.request.Request( - Network accessline 181
headers={'Content-Type': 'application/json', 'User-Agent': 'browser-harness'}, ) urllib.request.urlopen(request, timeout=job['timeout']).close() - Network accessline 182
) urllib.request.urlopen(request, timeout=job['timeout']).close() except Exception: - Network accessline 183
urllib.request.urlopen(request, timeout=job['timeout']).close() - Access to secretsline 191
[Credential-related source omitted] - Access to secretsline 194
[Credential-related source omitted] - Access to secretsline 219
[Credential-related source omitted] - Access to secretsline 233
[Credential-related source omitted] - Access to secretsline 265
[Credential-related source omitted] - Access to secretsline 276
[Credential-related source omitted] - Access to secretsline 277
[Credential-related source omitted] - Access to secretsline 279
[Credential-related source omitted] - Access to secretsline 280
[Credential-related source omitted]
src/browser_harness/video.py
- Executable scriptline 1
#!/usr/bin/env python3
src/browser_harness/video_render.py
- Executable scriptline 1
#!/usr/bin/env python3 - Network accessline 93
thread.start() try: yield f"http://127.0.0.1:{server.server_port}/video.html" - Network accessline 94
try: yield f"http://127.0.0.1:{server.server_port}/video.html" finally: - Network accessline 95
yield f"http://127.0.0.1:{server.server_port}/video.html" - Access to secretsline 107
[Credential-related source omitted]
src/mcp_server.py
- Executable scriptline 1
Executable file
tests/__init__.py
- Executable scriptline 1
Executable file
tests/conftest.py
- Executable scriptline 1
Executable file
tests/integration/__init__.py
- Executable scriptline 1
Executable file
tests/integration/test_js.py
- Executable scriptline 1
Executable file
tests/unit/__init__.py
- Executable scriptline 1
Executable file
tests/unit/test_admin.py
- Executable scriptline 1
Executable file - Network accessline 205
"_browser_use", lambda path, method, body=None: ( {"id": "browser-1", "cdpUrl": "https://cdp.example.test"} - Network accessline 206
lambda path, method, body=None: ( {"id": "browser-1", "cdpUrl": "https://cdp.example.test"} if method == "POST" - Network accessline 207
{"id": "browser-1", "cdpUrl": "https://cdp.example.test"} - Network accessline 343
response = ( b'{"target_id":"target-1","session_id":"session-1",' b'"page":{"targetId":"target-1","title":"Cat - Wikipedia","url":"https://en.wikipedia.org/wiki/Cat"}}\n' - Network accessline 344
b'{"target_id":"target-1","session_id":"session-1",' b'"page":{"targetId":"target-1","title":"Cat - Wikipedia","url":"https://en.wikipedia.org/wiki/Cat"}}\n' ) - Network accessline 345
b'"page":{"targetId":"target-1","title":"Cat - Wikipedia","url":"https://en.wikipedia.org/wiki/Cat"}}\n' - Network accessline 350
{ "name": "default", "page": {"title": "Cat - Wikipedia", "url": "https://en.wikipedia.org/wiki/Cat"}, - Network accessline 351
"name": "default", "page": {"title": "Cat - Wikipedia", "url": "https://en.wikipedia.org/wiki/Cat"}, } - Network accessline 352
"page": {"title": "Cat - Wikipedia", "url": "https://en.wikipedia.org/wiki/Cat"}, - Access to secretsline 433
[Credential-related source omitted] - Access to secretsline 454
[Credential-related source omitted] - Network accessline 495
{ "name": "default", "page": {"title": "Example", "url": "https://example.test"}, - Network accessline 496
"name": "default", "page": {"title": "Example", "url": "https://example.test"}, }, - Network accessline 497
"page": {"title": "Example", "url": "https://example.test"}, - Network accessline 499
{ "name": "cats", "page": {"title": "Cat - Wikipedia", "url": "https://en.wikipedia.org/wiki/Cat"}, - Network accessline 500
"name": "cats", "page": {"title": "Cat - Wikipedia", "url": "https://en.wikipedia.org/wiki/Cat"}, }, - Network accessline 501
"page": {"title": "Cat - Wikipedia", "url": "https://en.wikipedia.org/wiki/Cat"}, - Access to secretsline 506
[Credential-related source omitted] - Network accessline 510
out = capsys.readouterr().out assert "[ok ] active browser connections — 2" in out assert " default — active page: Example — https://example.test" in out - Network accessline 511
assert "[ok ] active browser connections — 2" in out assert " default — active page: Example — https://example.test" in out assert " cats — active page: Cat - Wikipedia — https://en.wikipedia.org/wiki/Cat" in out - Network accessline 512
assert " default — active page: Example — https://example.test" in out - Network accessline 513
assert " cats — active page: Cat - Wikipedia — https://en.wikipedia.org/wiki/Cat" in out - Network accessline 523
{ "name": "default", "page": {"title": "A very long page title", "url": "https://example.test/very/long/path"}, - Network accessline 524
"name": "default", "page": {"title": "A very long page title", "url": "https://example.test/very/long/path"}, } - Network accessline 525
"page": {"title": "A very long page title", "url": "https://example.test/very/long/path"}, - Access to secretsline 530
[Credential-related source omitted] - Network accessline 534
out = capsys.readouterr().out assert "A very long page ..." in out assert "https://example.t..." in out - Network accessline 536
assert "https://example.t..." in out - Network accessline 539
def test_start_remote_daemon_stops_created_browser_when_daemon_start_fails(monkeypatch): calls = [] browser = {"id": "browser-123", "cdpUrl": "http://127.0.0.1:9333", "liveUrl": "https://live.example"} - Network accessline 541
browser = {"id": "browser-123", "cdpUrl": "http://127.0.0.1:9333", "liveUrl": "https://live.example"} - Network accessline 566
def test_start_remote_daemon_stops_created_browser_when_daemon_start_is_interrupted(monkeypatch, exc_type): calls = [] browser = {"id": "browser-123", "cdpUrl": "http://127.0.0.1:9333", "liveUrl": "https://live.example"} - Network accessline 568
browser = {"id": "browser-123", "cdpUrl": "http://127.0.0.1:9333", "liveUrl": "https://live.example"} - Network accessline 598
def test_start_remote_daemon_does_not_stop_created_browser_on_success(monkeypatch): calls = [] browser = {"id": "browser-123", "cdpUrl": "http://127.0.0.1:9333", "liveUrl": "https://live.example"} - Network accessline 600
browser = {"id": "browser-123", "cdpUrl": "http://127.0.0.1:9333", "liveUrl": "https://live.example"}
tests/unit/test_auth.py
tests/unit/test_brave_origin.py
tests/unit/test_daemon.py
- Executable scriptline 1
Executable file - Access to secretsline 47
[Credential-related source omitted] - Network accessline 383
return {"targetInfo": { "targetId": params["targetId"], "url": "https://example.com/", - Network accessline 384
"targetId": params["targetId"], "url": "https://example.com/", "title": "Example Domain", - Network accessline 385
"url": "https://example.com/", - Network accessline 397
assert result == { "targetId": "page-target-abc", "url": "https://example.com/", - Network accessline 398
"targetId": "page-target-abc", "url": "https://example.com/", "title": "Example Domain", - Network accessline 399
"url": "https://example.com/", - Network accessline 453
monkeypatch.setattr(daemon, "REMOTE_ID", None) monkeypatch.setattr(daemon, "BROWSER_KIND", "cdp") existing = [{"targetId": "someone-elses-tab", "url": "https://example.com/", "type": "page"}] - Network accessline 454
monkeypatch.setattr(daemon, "BROWSER_KIND", "cdp") existing = [{"targetId": "someone-elses-tab", "url": "https://example.com/", "type": "page"}] d = daemon.Daemon() - Network accessline 455
existing = [{"targetId": "someone-elses-tab", "url": "https://example.com/", "type": "page"}] - Network accessline 475
monkeypatch.setattr(daemon, "NAME", "default") monkeypatch.setattr(daemon, "REMOTE_ID", None) existing = [{"targetId": "user-tab", "url": "https://example.com/", "type": "page"}] - Network accessline 476
monkeypatch.setattr(daemon, "REMOTE_ID", None) existing = [{"targetId": "user-tab", "url": "https://example.com/", "type": "page"}] d = daemon.Daemon() - Network accessline 477
existing = [{"targetId": "user-tab", "url": "https://example.com/", "type": "page"}] - Network accessline 544
asyncio.run(d.attach_first_page()) d.cdp.targets.append({"targetId": "selected-tab", "url": "https://example.com", "type": "page"}) - Network accessline 545
d.cdp.targets.append({"targetId": "selected-tab", "url": "https://example.com", "type": "page"}) - Network accessline 704
if method == "Target.getTargets": return {"targetInfos": [ {"targetId": "same-tab", "url": "https://example.com", "type": "page"} - Network accessline 705
return {"targetInfos": [ {"targetId": "same-tab", "url": "https://example.com", "type": "page"} ]} - Network accessline 706
{"targetId": "same-tab", "url": "https://example.com", "type": "page"} - Network accessline 770
await self.release_discovery.wait() return {"targetInfos": [ {"targetId": "old-tab", "url": "https://example.com", "type": "page"} - Network accessline 771
return {"targetInfos": [ {"targetId": "old-tab", "url": "https://example.com", "type": "page"} ]} - Network accessline 772
{"targetId": "old-tab", "url": "https://example.com", "type": "page"}
tests/unit/test_helpers.py
- Executable scriptline 1
Executable file - Network accessline 85
_seed_skill(tmp_path) with patch("browser_harness.helpers.cdp", return_value={"frameId": "f"}): result = helpers.goto_url("https://www.example.com/") - Network accessline 86
with patch("browser_harness.helpers.cdp", return_value={"frameId": "f"}): result = helpers.goto_url("https://www.example.com/") assert result == {"frameId": "f"} - Network accessline 87
result = helpers.goto_url("https://www.example.com/") - Network accessline 94
_seed_skill(tmp_path) with patch("browser_harness.helpers.cdp", return_value={"frameId": "f"}): result = helpers.goto_url("https://www.example.com/") - Network accessline 95
with patch("browser_harness.helpers.cdp", return_value={"frameId": "f"}): result = helpers.goto_url("https://www.example.com/") assert result == {"frameId": "f", "domain_skills": ["scraping.md"]} - Network accessline 96
result = helpers.goto_url("https://www.example.com/") - Network accessline 510
assert helpers.new_tab("https://example.com") == "target-placeholder" - Network accessline 511
assert calls == [("goto_url", "https://example.com")]
tests/unit/test_ipc.py
- Executable scriptline 1
Executable file
tests/unit/test_macos.py
- Executable scriptline 1
Executable file
tests/unit/test_mcp_cli.py
- Executable scriptline 1
Executable file
tests/unit/test_mcp_server.py
- Executable scriptline 1
Executable file - Network accessline 31
def test_helper_success_remains_a_normal_tool_result(monkeypatch): monkeypatch.setattr(mcp_server, "ensure_daemon", lambda: None) monkeypatch.setattr(mcp_server, "page_info", lambda: {"url": "https://example.com"}) - Network accessline 33
monkeypatch.setattr(mcp_server, "page_info", lambda: {"url": "https://example.com"}) - Network accessline 37
assert result.is_error is False assert result.content[0].text == '{"url": "https://example.com"}' - Network accessline 38
assert result.content[0].text == '{"url": "https://example.com"}'
tests/unit/test_recorder.py
- Executable scriptline 1
Executable file
tests/unit/test_run.py
- Executable scriptline 1
Executable file - Access to secretsline 75
[Credential-related source omitted] - Network accessline 93
monkeypatch.setenv("BU_CDP_URL", "http://127.0.0.1:9333") - Access to secretsline 94
[Credential-related source omitted] - Access to secretsline 112
[Credential-related source omitted] - Access to secretsline 130
[Credential-related source omitted] - Access to secretsline 145
[Credential-related source omitted] - Access to secretsline 149
[Credential-related source omitted] - Network accessline 162
monkeypatch.setenv("BU_CDP_URL", "http://127.0.0.1:9333") - Access to secretsline 164
[Credential-related source omitted] - Network accessline 181
monkeypatch.setenv("BU_CDP_URL", "http://127.0.0.1:9333") - Access to secretsline 182
[Credential-related source omitted] - Network accessline 200
monkeypatch.setenv("BU_CDP_URL", "http://127.0.0.1:9333") - Access to secretsline 201
[Credential-related source omitted] - Network accessline 217
for name, value in [ ("BU_CDP_URL", "http://127.0.0.1:9333"), - Network accessline 218
("BU_CDP_URL", "http://127.0.0.1:9333"), - Network accessline 219
("BU_CDP_WS", "ws://example.test/devtools/browser/abc"), ("BU_CDP_URL", "http://[::1]:9333"), # IPv6 host ("BU_CDP_WS", "wss://cloud.example.com/devtools/browser/x"), # secure WS - Network accessline 220
("BU_CDP_URL", "http://[::1]:9333"), # IPv6 host - Network accessline 245
with patch("browser_harness.run.urllib.request.urlopen", side_effect=OSError): - Network accessline 248
response = MagicMock() response.__enter__.return_value.read.return_value = payload with patch("browser_harness.run.urllib.request.urlopen", return_value=response) as mock_open: - Network accessline 249
response.__enter__.return_value.read.return_value = payload with patch("browser_harness.run.urllib.request.urlopen", return_value=response) as mock_open: assert run._local_chrome_listening() is False - Network accessline 250
with patch("browser_harness.run.urllib.request.urlopen", return_value=response) as mock_open: - Network accessline 256
response = MagicMock() response.__enter__.return_value.read.return_value = b'{"webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/browser/x"}' with patch("browser_harness.run.urllib.request.urlopen", return_value=response) as mock - Network accessline 257
response.__enter__.return_value.read.return_value = b'{"webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/browser/x"}' with patch("browser_harness.run.urllib.request.urlopen", return_value=response) as mock_open: assert run._ - Network accessline 258
with patch("browser_harness.run.urllib.request.urlopen", return_value=response) as mock_open:
tests/unit/test_skill.py
- Executable scriptline 1
Executable file - Network accessline 32
assert metadata == { "name": "browser-harness", "description": "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public conte - Network accessline 33
"name": "browser-harness", "description": "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those.", - Network accessline 34
"description": "Control a real browser via CDP: clicking, typing, navigation, logged-in sessions, JS-rendered or bot-protected pages. Not for plain HTTP fetches of public content - use curl for those.",
How the signals fit together
Facts from a static read of the files at the pinned commit. They describe what the code does, not why.
Some files could not be read; the facts below still hold.
Signal confidence: 500 facts
- Access to secrets in prose of documentationAGENTS.md:51Low confidence
- Network access in prose of documentationREADME.md:1Low confidence
- Network access in prose of documentationREADME.md:7Low confidence
- Network access in prose of documentationREADME.md:25Low confidence
- Network access in code of documentationREADME.md:32Low confidence
- Network access in prose of documentationREADME.md:58Low confidence
- Network access in prose of documentationREADME.md:78Low confidence
- Network access in prose of documentationREADME.md:91Low confidence
- Network access in prose of documentationREADME.md:102Low confidence
- Network access in prose of documentationREADME.md:103Low confidence
- Network access in prose of documentationREADME.md:123Low confidence
- Network access in the frontmatter of the SKILL.mdSKILL.md:1Low confidence
- Network access in the frontmatter of the SKILL.mdSKILL.md:2Low confidence
- Network access in the frontmatter of the SKILL.mdSKILL.md:3Low confidence
- Network access in prose of the SKILL.mdSKILL.md:8Low confidence
- Access to secrets in prose of the SKILL.mdSKILL.md:143Low confidence
- Network access in prose of the SKILL.mdSKILL.md:150Low confidence
- Access to secrets in code of the SKILL.md: a variable, placeholder or call, not a stored valueSKILL.md:161Low confidence
- Network access in code of the SKILL.mdSKILL.md:171High confidence
- Network access in code of the SKILL.mdSKILL.md:172High confidence
- Network access in prose of the SKILL.mdSKILL.md:183Low confidence
- Network access in prose of the SKILL.mdSKILL.md:223Low confidence
- Network access in prose of the SKILL.mdSKILL.md:224Low confidence
- Network access in prose of the SKILL.mdSKILL.md:225Low confidence
- Network access in prose of the SKILL.mdSKILL.md:231Low confidence
- Executable script in prose of a file that runsagent-workspace/agent_helpers.py:1Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:191Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:192Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:193Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:226Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:227Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:228Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:242Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:243Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:244Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:289Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:290Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/chat.md:291Low confidence
- Network access in prose of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:13Low confidence
- Access to secrets in prose of documentation: a variable, placeholder or call, not a stored valueagent-workspace/domain-skills/BOSS-zhipin/job-search.md:13Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:24Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:28Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:29Low confidence
- Network access in code of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:30Low confidence
- Network access in prose of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:45Low confidence
- Network access in prose of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:46Low confidence
- Network access in prose of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:47Low confidence
- Network access in prose of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:48Low confidence
- Network access in prose of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:49Low confidence
- Network access in prose of documentationagent-workspace/domain-skills/BOSS-zhipin/job-search.md:50Low confidence
and 450 more
Only the first 500 facts are listed.
Works with
| Agent | Status | Evidence | Install to |
|---|---|---|---|
| Claude Code | Native | Manifest .claude-plugin/marketplace.json | .claude/skills/<skill-name>/ |
| Codex | Native | Manifest AGENTS.md | .agents/skills/<skill-name>/ |
| Cursor | Compatible | Standard SKILL.md SKILL.md | .cursor/skills/<skill-name>/ |
| Gemini CLI | Compatible | Standard SKILL.md SKILL.md | .gemini/skills/<skill-name>/ |
| GitHub Copilot | Compatible | Standard SKILL.md SKILL.md | .github/skills/<skill-name>/ |
| OpenCode | Compatible | Standard SKILL.md SKILL.md | .opencode/skills/<skill-name>/ |
- Native The repository ships a manifest, folder or frontmatter field for this agent.
- Compatible A standard SKILL.md that this agent can read.
- Unknown No evidence either way.
Derived automatically from paths, manifests and frontmatter. Not tested on each agent.
Add this badge to your README
It updates every night and links to this page.
[](https://hotskills.dev/skill/browser-use-browser-harness/)