@pencil-agent/nano-pencil 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/README.md +267 -267
  2. package/dist/build-meta.json +3 -3
  3. package/dist/core/export-html/AGENT.md +11 -11
  4. package/dist/core/export-html/template.css +971 -971
  5. package/dist/core/export-html/template.html +54 -54
  6. package/dist/core/mcp/mcp-client.d.ts +3 -1
  7. package/dist/core/mcp/mcp-client.js +6 -6
  8. package/dist/core/mcp/mcp-config.d.ts +3 -3
  9. package/dist/core/mcp/mcp-config.js +1 -1
  10. package/dist/core/mcp/mcp-manager.d.ts +5 -1
  11. package/dist/core/mcp/mcp-manager.js +1 -1
  12. package/dist/core/platform/config/resource-loader.d.ts +2 -0
  13. package/dist/core/platform/config/resource-loader.js +2 -2
  14. package/dist/core/runtime/agent-session.d.ts +12 -0
  15. package/dist/core/runtime/agent-session.js +8 -8
  16. package/dist/core/runtime/sdk.d.ts +8 -0
  17. package/dist/core/runtime/sdk.js +1 -1
  18. package/dist/extensions/builtin/AGENT.md +115 -115
  19. package/dist/extensions/builtin/browser/AGENT.md +17 -17
  20. package/dist/extensions/builtin/browser/agent-workspace/agent_helpers.py +12 -12
  21. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/amazon/product-search.md +198 -198
  22. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/archive-org/scraping.md +341 -341
  23. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv/scraping.md +311 -311
  24. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv-bulk/scraping.md +333 -333
  25. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/atlas/overview.md +70 -70
  26. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/booking-com/scraping.md +578 -578
  27. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/capterra/scraping.md +440 -440
  28. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/centilebrain/generate-estimates.md +110 -110
  29. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coingecko/scraping.md +325 -325
  30. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coinmarketcap/scraping.md +463 -463
  31. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coursera/scraping.md +360 -360
  32. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/craigslist/scraping.md +390 -390
  33. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/crossref/scraping.md +568 -568
  34. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/dev-to/scraping.md +323 -323
  35. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/duckduckgo/scraping.md +349 -349
  36. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/ebay/scraping.md +435 -435
  37. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/etsy/scraping.md +506 -506
  38. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/eventbrite/scraping.md +363 -363
  39. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/expedia/automation.md +168 -168
  40. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/groups.md +236 -236
  41. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/pages.md +295 -295
  42. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/framer/editor.md +108 -108
  43. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/fred/scraping.md +493 -493
  44. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/g2/scraping.md +580 -580
  45. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/genius/scraping.md +511 -511
  46. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/repo-actions.md +65 -65
  47. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/scraping.md +184 -184
  48. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/glassdoor/scraping.md +543 -543
  49. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gmail/compose.md +122 -122
  50. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/goodreads/scraping.md +461 -461
  51. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gutenberg/scraping.md +383 -383
  52. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/hackernews/scraping.md +243 -243
  53. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/howlongtobeat/scraping.md +473 -473
  54. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/imdb/scraping.md +271 -271
  55. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/itch-io/scraping.md +436 -436
  56. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/job-boards/indeed-glassdoor.md +1021 -1021
  57. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/letterboxd/scraping.md +349 -349
  58. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/linkedin/invitation-manager.md +109 -109
  59. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/loom/folder-enumeration.md +170 -170
  60. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/macrotrends/scraping.md +537 -537
  61. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/article-hydration.md +120 -120
  62. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/scraping.md +414 -414
  63. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/metacritic/scraping.md +477 -477
  64. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/musicbrainz/scraping.md +478 -478
  65. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/nasa/scraping.md +339 -339
  66. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/news-aggregation/multi-source.md +205 -205
  67. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/open-library/scraping.md +472 -472
  68. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openalex/scraping.md +470 -470
  69. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openstreetmap/scraping.md +490 -490
  70. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/package-registries/npm-pypi.md +478 -478
  71. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/polymarket/scraping.md +234 -234
  72. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/producthunt/scraping.md +307 -307
  73. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/pubmed/scraping.md +421 -421
  74. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/quora/scraping.md +364 -364
  75. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rawg/scraping.md +352 -352
  76. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/reddit/scraping.md +124 -124
  77. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rest-countries/scraping.md +233 -233
  78. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/sec-edgar/scraping.md +361 -361
  79. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/README.md +36 -36
  80. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/embedded-apps.md +72 -72
  81. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/knowledge-base.md +109 -109
  82. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/polaris-inputs.md +137 -137
  83. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/soundcloud/scraping.md +362 -362
  84. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/spotify/scraping.md +339 -339
  85. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/stackoverflow/scraping.md +435 -435
  86. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/steam/scraping.md +575 -575
  87. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/substack/scraping.md +338 -338
  88. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/thetechgeeks/pricing.md +52 -52
  89. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tiktok/upload.md +107 -107
  90. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tradingview/scraping.md +309 -309
  91. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trello/boards-and-lists.md +88 -88
  92. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trustpilot/scraping.md +375 -375
  93. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/walmart/scraping.md +444 -444
  94. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wayback-machine/scraping.md +306 -306
  95. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/weather/scraping.md +398 -398
  96. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wellfound/scraping.md +596 -596
  97. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/world-bank/scraping.md +356 -356
  98. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/xiaohongshu/scraping.md +84 -84
  99. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/youtube/scraping.md +418 -418
  100. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/zillow/scraping.md +433 -433
  101. package/dist/extensions/builtin/browser/browser.md +73 -73
  102. package/dist/extensions/builtin/browser/install.md +142 -142
  103. package/dist/extensions/builtin/browser/interaction-skills/connection.md +48 -48
  104. package/dist/extensions/builtin/browser/interaction-skills/cookies.md +3 -3
  105. package/dist/extensions/builtin/browser/interaction-skills/cross-origin-iframes.md +3 -3
  106. package/dist/extensions/builtin/browser/interaction-skills/dialogs.md +64 -64
  107. package/dist/extensions/builtin/browser/interaction-skills/downloads.md +3 -3
  108. package/dist/extensions/builtin/browser/interaction-skills/drag-and-drop.md +3 -3
  109. package/dist/extensions/builtin/browser/interaction-skills/dropdowns.md +3 -3
  110. package/dist/extensions/builtin/browser/interaction-skills/iframes.md +3 -3
  111. package/dist/extensions/builtin/browser/interaction-skills/network-requests.md +3 -3
  112. package/dist/extensions/builtin/browser/interaction-skills/print-as-pdf.md +3 -3
  113. package/dist/extensions/builtin/browser/interaction-skills/profile-sync.md +90 -90
  114. package/dist/extensions/builtin/browser/interaction-skills/screenshots.md +17 -17
  115. package/dist/extensions/builtin/browser/interaction-skills/scrolling.md +3 -3
  116. package/dist/extensions/builtin/browser/interaction-skills/shadow-dom.md +3 -3
  117. package/dist/extensions/builtin/browser/interaction-skills/tabs.md +69 -69
  118. package/dist/extensions/builtin/browser/interaction-skills/uploads.md +1 -1
  119. package/dist/extensions/builtin/browser/interaction-skills/viewport.md +3 -3
  120. package/dist/extensions/builtin/browser/src/browser_harness/AGENT.md +15 -15
  121. package/dist/extensions/builtin/browser/src/browser_harness/__init__.py +8 -8
  122. package/dist/extensions/builtin/browser/src/browser_harness/_ipc.py +90 -90
  123. package/dist/extensions/builtin/browser/src/browser_harness/admin.py +722 -722
  124. package/dist/extensions/builtin/browser/src/browser_harness/daemon.py +328 -328
  125. package/dist/extensions/builtin/browser/src/browser_harness/helpers.py +396 -396
  126. package/dist/extensions/builtin/browser/src/browser_harness/run.py +103 -103
  127. package/dist/extensions/builtin/discipline/skills/brainstorming/SKILL.md +33 -33
  128. package/dist/extensions/builtin/discipline/skills/executing-plans/SKILL.md +25 -25
  129. package/dist/extensions/builtin/discipline/skills/finishing-development-branch/SKILL.md +25 -25
  130. package/dist/extensions/builtin/discipline/skills/receiving-code-review/SKILL.md +22 -22
  131. package/dist/extensions/builtin/discipline/skills/requesting-code-review/SKILL.md +31 -31
  132. package/dist/extensions/builtin/discipline/skills/systematic-debugging/SKILL.md +28 -28
  133. package/dist/extensions/builtin/discipline/skills/test-driven-development/SKILL.md +32 -32
  134. package/dist/extensions/builtin/discipline/skills/using-git-worktrees/SKILL.md +25 -25
  135. package/dist/extensions/builtin/discipline/skills/verification-before-completion/SKILL.md +27 -27
  136. package/dist/extensions/builtin/discipline/skills/writing-plans/SKILL.md +26 -26
  137. package/dist/extensions/builtin/goal/README.md +67 -67
  138. package/dist/extensions/builtin/grub/README.md +112 -112
  139. package/dist/extensions/builtin/link-world/agent-workspace/README.md +16 -16
  140. package/dist/extensions/builtin/link-world/internet-search/internet-search.md +65 -65
  141. package/dist/extensions/builtin/link-world/link-world-agent.md +82 -82
  142. package/dist/extensions/builtin/link-world/linkworld.md +313 -313
  143. package/dist/extensions/builtin/link-world/network-routing/network-routing.md +67 -67
  144. package/dist/extensions/builtin/loop/README.md +92 -92
  145. package/dist/extensions/builtin/mcp/figma-design.md +68 -68
  146. package/dist/extensions/builtin/mcp/mcp-management.md +85 -85
  147. package/dist/extensions/builtin/recap/AGENT.md +15 -15
  148. package/dist/extensions/builtin/sal/README.md +72 -72
  149. package/dist/extensions/builtin/security-audit/README.md +289 -289
  150. package/dist/extensions/builtin/team/AGENT.md +112 -112
  151. package/dist/extensions/builtin/team/TESTING.md +299 -299
  152. package/dist/extensions/builtin/token-save/README.md +56 -56
  153. package/dist/extensions/optional/AGENT.md +10 -10
  154. package/dist/modes/interactive/interactive-mode.js +36 -36
  155. package/dist/modes/interactive/theme/dark.json +85 -85
  156. package/dist/modes/interactive/theme/light.json +84 -84
  157. package/dist/modes/interactive/theme/theme-schema.json +335 -335
  158. package/dist/modes/interactive/theme/warm.json +81 -81
  159. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop.js +3 -2
  160. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-agent-loop.js +2 -1
  161. package/dist/node_modules/@pencil-agent/ai/dist/cli.js +0 -0
  162. package/docs/cc-agent-design.md +1297 -0
  163. package/docs/cc-tui-design.md +1333 -0
  164. package/docs/codex-goal-command-impl.md +1055 -1055
  165. package/docs/codex-goal-vs-grub.md +500 -500
  166. package/docs/custom-provider.md +27 -27
  167. package/docs/extensions.md +27 -27
  168. package/docs/keybindings.md +27 -27
  169. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/200/273/347/273/223.md" +250 -250
  170. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/212/245/345/221/212.md" +122 -122
  171. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210.md" +1222 -1222
  172. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210/345/256/236/347/216/260/346/212/245/345/221/212.md" +158 -158
  173. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210/345/257/271/346/257/224/345/210/206/346/236/220.md" +128 -128
  174. package/docs/loop /351/207/215/346/236/204/350/256/241/345/210/222.md" +320 -320
  175. package/docs/loop-usage-examples.md +214 -214
  176. package/docs/models.md +27 -27
  177. package/docs/nanoPencil-/345/255/246/344/271/240/350/256/241/345/210/222.md +170 -0
  178. package/docs/packages.md +27 -27
  179. package/docs/pi-design-philosophy.md +457 -457
  180. package/docs/planmode.md +1987 -1987
  181. package/docs/prompt-templates.md +27 -27
  182. package/docs/providers.md +27 -27
  183. package/docs/scan-report.md +3820 -0
  184. package/docs/sdk.md +27 -27
  185. package/docs/skills.md +27 -27
  186. package/docs/themes.md +27 -27
  187. package/docs/tui.md +27 -27
  188. package/docs//345/257/271/346/240/207Claude-Code.md +1775 -0
  189. package/docs//351/230/277/351/207/214/345/267/264/345/267/264/350/264/242/346/212/245/345/210/206/346/236/220/344/271/246.md +261 -0
  190. package/package.json +190 -190
  191. package/docs/ACP/345/215/217/350/256/256/351/233/206/346/210/220/345/274/200/345/217/221/346/226/207/346/241/243.md +0 -851
  192. package/docs/SDK-TESTING.md +0 -364
  193. package/docs/mem-core/346/212/200/346/234/257/346/226/207/346/241/243.md +0 -593
  194. package/docs/startup-performance-optimization.md +0 -301
  195. package/docs//350/256/244/347/237/245/345/234/260/345/233/276.md +0 -47
@@ -1,233 +1,233 @@
1
- # REST Countries — Scraping & Data Extraction
2
-
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.
4
-
5
- ## Do this first
6
-
7
- **Fetch all 250 countries in one call with a field filter — almost always the fastest approach.**
8
-
9
- ```python
10
- import json
11
- from helpers import http_get
12
-
13
- data = http_get("https://restcountries.com/v3.1/all?fields=name,cca2,capital,population,area,region")
14
- countries = json.loads(data)
15
- # countries is a list of 250 dicts — confirmed 2026-04-18
16
-
17
- for c in countries:
18
- name = c["name"]["common"] # "Germany"
19
- official = c["name"]["official"] # "Federal Republic of Germany"
20
- code = c["cca2"] # "DE"
21
- capital = c["capital"][0] if c.get("capital") else None # list — may be empty
22
- population = c["population"] # 83491249
23
- area = c["area"] # 357114.0 (km²)
24
- region = c["region"] # "Europe"
25
- print(code, name, population)
26
- # Confirmed output (first result varies — API returns unsorted):
27
- # CI Ivory Coast 31719275
28
- ```
29
-
30
- Use the `?fields=` query param to limit response size — essential when fetching all 250.
31
-
32
- ## Common workflows
33
-
34
- ### Lookup a single country by code (ISO 3166-1 alpha-2 or alpha-3)
35
-
36
- ```python
37
- import json
38
- from helpers import http_get
39
-
40
- # Single code — returns a list (one element)
41
- data = http_get("https://restcountries.com/v3.1/alpha/DE")
42
- country = json.loads(data)[0]
43
-
44
- # But: /alpha/CODE?fields=... returns a plain dict, not a list — watch for this
45
- data2 = http_get("https://restcountries.com/v3.1/alpha/DE?fields=name,cca2,currencies,languages,flags")
46
- country2 = json.loads(data2) # dict, NOT list
47
-
48
- name = country2["name"]["common"] # "Germany"
49
- currencies = country2["currencies"] # {"EUR": {"name": "euro", "symbol": "€"}}
50
- currency_codes = list(currencies.keys()) # ["EUR"]
51
- currency_name = currencies["EUR"]["name"] # "euro"
52
- languages = country2["languages"] # {"deu": "German"}
53
- lang_names = list(languages.values()) # ["German"]
54
- flag_png = country2["flags"]["png"] # "https://flagcdn.com/w320/de.png"
55
- flag_svg = country2["flags"]["svg"] # "https://flagcdn.com/de.svg"
56
- flag_alt = country2["flags"]["alt"] # description text
57
-
58
- print(name, currency_codes, lang_names)
59
- # Confirmed: Germany ['EUR'] ['German']
60
- ```
61
-
62
- ### Batch lookup — multiple codes in one call
63
-
64
- Use `/alpha?codes=` for fetching a known list of countries — always returns a list.
65
-
66
- ```python
67
- import json
68
- from helpers import http_get
69
-
70
- codes = ["US", "GB", "FR", "DE", "JP", "CN", "IN", "BR", "AU", "CA"]
71
- data = http_get(f"https://restcountries.com/v3.1/alpha?codes={','.join(codes)}&fields=name,cca2,population")
72
- countries = json.loads(data)
73
- # Returns list, order NOT guaranteed to match input order
74
- for c in countries:
75
- print(c["cca2"], c["name"]["common"], c["population"])
76
- # Confirmed: 10 results, returned in arbitrary order
77
- ```
78
-
79
- ### Search by name
80
-
81
- ```python
82
- import json
83
- from helpers import http_get
84
-
85
- # Partial match (default) — may return multiple results
86
- data = http_get("https://restcountries.com/v3.1/name/united")
87
- results = json.loads(data)
88
- # Returns 7 countries: United States, UK, UAE, Tanzania, Mexico, ...
89
-
90
- # Exact match — use fullText=true with the full common or official name
91
- data2 = http_get("https://restcountries.com/v3.1/name/united%20kingdom?fullText=true")
92
- results2 = json.loads(data2)
93
- # Returns exactly 1 result: United Kingdom
94
- print(results2[0]["name"]["common"]) # United Kingdom
95
- ```
96
-
97
- ### Filter by region
98
-
99
- ```python
100
- import json
101
- from helpers import http_get
102
-
103
- data = http_get("https://restcountries.com/v3.1/region/europe?fields=name,cca2,population")
104
- countries = json.loads(data)
105
- # 53 European countries — confirmed
106
-
107
- # Sort by population
108
- ranked = sorted(countries, key=lambda x: x["population"], reverse=True)
109
- for c in ranked[:5]:
110
- print(c["cca2"], c["name"]["common"], f"{c['population']:,}")
111
- # Confirmed top 5: RU Russia, DE Germany, FR France, GB United Kingdom, IT Italy
112
- ```
113
-
114
- Valid region values: `africa`, `americas`, `asia`, `europe`, `oceania`, `antarctic`
115
-
116
- ### Filter by subregion
117
-
118
- ```python
119
- import json
120
- from helpers import http_get
121
-
122
- data = http_get("https://restcountries.com/v3.1/subregion/Western%20Europe?fields=name,cca2")
123
- countries = json.loads(data)
124
- print([c["cca2"] for c in countries])
125
- # Confirmed: ['FR', 'NL', 'MC', 'DE', 'BE', 'LI', 'CH', 'LU']
126
- ```
127
-
128
- ### Filter by language
129
-
130
- ```python
131
- import json
132
- from helpers import http_get
133
-
134
- data = http_get("https://restcountries.com/v3.1/lang/arabic")
135
- countries = json.loads(data)
136
- print(f"Arabic-speaking countries: {len(countries)}")
137
- # Confirmed: 25 countries
138
-
139
- # Language param is the language name (English), not the ISO 639-3 code
140
- # Works: arabic, french, spanish, english, portuguese, german, russian, chinese
141
- ```
142
-
143
- ### Filter by currency
144
-
145
- ```python
146
- import json
147
- from helpers import http_get
148
-
149
- data = http_get("https://restcountries.com/v3.1/currency/EUR")
150
- countries = json.loads(data)
151
- print(f"EUR countries: {len(countries)}") # Confirmed: 36
152
- names = [c["name"]["common"] for c in countries]
153
- print(names[:5])
154
-
155
- # Use ISO 4217 currency code (uppercase)
156
- ```
157
-
158
- ### Filter by capital city
159
-
160
- ```python
161
- import json
162
- from helpers import http_get
163
-
164
- data = http_get("https://restcountries.com/v3.1/capital/berlin?fields=name,cca2,capital")
165
- result = json.loads(data)
166
- print(result[0]["name"]["common"], result[0]["capital"])
167
- # Confirmed: Germany ['Berlin']
168
- # Capital param is case-insensitive
169
- ```
170
-
171
- ### Full country detail — all fields
172
-
173
- ```python
174
- import json
175
- from helpers import http_get
176
-
177
- data = http_get("https://restcountries.com/v3.1/alpha/US")
178
- c = json.loads(data)[0]
179
-
180
- # Available top-level keys (confirmed for US/DE):
181
- # name, tld, cca2, ccn3, cca3, cioc, independent, status, unMember,
182
- # currencies, idd, capital, altSpellings, region, subregion, languages,
183
- # translations, latlng, landlocked, borders, area, demonyms, flag (emoji),
184
- # maps, population, gini, fifa, car, timezones, continents, flags,
185
- # coatOfArms, startOfWeek, capitalInfo, postalCode
186
-
187
- print(c["idd"]) # {"root": "+1", "suffixes": ["201", "202", ...]}
188
- print(c["car"]["side"]) # "right" or "left"
189
- print(c["gini"]) # {"2018": 41.4} — year keyed, may be absent
190
- print(c["timezones"]) # list of UTC offset strings
191
- print(c["borders"]) # list of cca3 codes for bordering countries
192
- print(c["latlng"]) # [lat, lng] of geographic center
193
- ```
194
-
195
- ## URL reference
196
-
197
- | Endpoint | Pattern | Notes |
198
- |---|---|---|
199
- | All countries | `/v3.1/all` | Always add `?fields=` |
200
- | By code | `/v3.1/alpha/{code}` | cca2 or cca3; single code → list (no fields) or dict (with fields) |
201
- | By codes | `/v3.1/alpha?codes=DE,FR,JP` | Always returns list |
202
- | By name | `/v3.1/name/{name}` | Partial; add `?fullText=true` for exact match |
203
- | By region | `/v3.1/region/{region}` | africa, americas, asia, europe, oceania, antarctic |
204
- | By subregion | `/v3.1/subregion/{subregion}` | URL-encode spaces as `%20` |
205
- | By language | `/v3.1/lang/{language}` | English language name |
206
- | By currency | `/v3.1/currency/{code}` | ISO 4217 (EUR, USD, GBP) |
207
- | By capital | `/v3.1/capital/{city}` | Case-insensitive |
208
-
209
- All endpoints accept `?fields=field1,field2,...` to limit response payload.
210
-
211
- ## Gotchas
212
-
213
- - **`name` is a nested object, not a string.** Use `c["name"]["common"]` for the familiar English name, `c["name"]["official"]` for the full official name. `nativeName` is a dict keyed by ISO 639-3 language code.
214
-
215
- - **`/alpha/CODE` return type depends on whether `?fields=` is present.** Without `?fields=`, returns a list (one element). With `?fields=...`, returns a plain dict. Use `json.loads(data)[0]` for the no-fields case, `json.loads(data)` for the fields case. Using `/alpha?codes=CODE` always returns a list regardless.
216
-
217
- - **`currencies` is a dict keyed by ISO 4217 code, not a list.** `c["currencies"]["EUR"]["name"]` → `"euro"`, `c["currencies"]["EUR"]["symbol"]` → `"€"`. A country can have multiple currencies — iterate `currencies.items()`.
218
-
219
- - **`languages` is a dict keyed by ISO 639-3 code.** `c["languages"]["deu"]` → `"German"`. Use `list(c["languages"].values())` for a simple list of language names.
220
-
221
- - **`capital` is a list and may be empty.** Some territories (Antarctica, Bouvet Island, Macau, Heard Island) have no capital — `c.get("capital")` returns `[]`, not `None`. Guard with `c["capital"][0] if c.get("capital") else None`. South Africa has 3 capitals.
222
-
223
- - **`gini` is a dict keyed by year string, may be absent entirely.** `c["gini"]` → `{"2016": 31.9}`. Many small countries or territories have no gini data — always check `c.get("gini")`.
224
-
225
- - **`borders` uses cca3 codes, not cca2.** `c["borders"]` → `["AUT", "BEL", ...]`. Cross-reference with another `/alpha?codes=` call to resolve to names.
226
-
227
- - **`translations` covers ~45 languages.** Each entry: `c["translations"]["deu"]` → `{"official": "Bundesrepublik Deutschland", "common": "Deutschland"}`. Useful for multilingual apps.
228
-
229
- - **No rate limit headers, no documented rate limit.** In practice the API handles rapid sequential calls fine. For bulk crawling hundreds of per-country requests, add a short sleep (`time.sleep(0.5)`) between calls to be polite.
230
-
231
- - **404 returns JSON, not HTML.** `{"message": "Not Found", "status": 404}`. Wrap calls in try/except and check for this pattern when handling user-supplied country names or codes.
232
-
233
- - **`?fields=` is the key performance lever.** The full all-countries payload without field filtering is ~1.5 MB. With `?fields=name,cca2,population` it drops to ~50 KB. Always filter when you don't need all fields.
1
+ # REST Countries — Scraping & Data Extraction
2
+
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.
4
+
5
+ ## Do this first
6
+
7
+ **Fetch all 250 countries in one call with a field filter — almost always the fastest approach.**
8
+
9
+ ```python
10
+ import json
11
+ from helpers import http_get
12
+
13
+ data = http_get("https://restcountries.com/v3.1/all?fields=name,cca2,capital,population,area,region")
14
+ countries = json.loads(data)
15
+ # countries is a list of 250 dicts — confirmed 2026-04-18
16
+
17
+ for c in countries:
18
+ name = c["name"]["common"] # "Germany"
19
+ official = c["name"]["official"] # "Federal Republic of Germany"
20
+ code = c["cca2"] # "DE"
21
+ capital = c["capital"][0] if c.get("capital") else None # list — may be empty
22
+ population = c["population"] # 83491249
23
+ area = c["area"] # 357114.0 (km²)
24
+ region = c["region"] # "Europe"
25
+ print(code, name, population)
26
+ # Confirmed output (first result varies — API returns unsorted):
27
+ # CI Ivory Coast 31719275
28
+ ```
29
+
30
+ Use the `?fields=` query param to limit response size — essential when fetching all 250.
31
+
32
+ ## Common workflows
33
+
34
+ ### Lookup a single country by code (ISO 3166-1 alpha-2 or alpha-3)
35
+
36
+ ```python
37
+ import json
38
+ from helpers import http_get
39
+
40
+ # Single code — returns a list (one element)
41
+ data = http_get("https://restcountries.com/v3.1/alpha/DE")
42
+ country = json.loads(data)[0]
43
+
44
+ # But: /alpha/CODE?fields=... returns a plain dict, not a list — watch for this
45
+ data2 = http_get("https://restcountries.com/v3.1/alpha/DE?fields=name,cca2,currencies,languages,flags")
46
+ country2 = json.loads(data2) # dict, NOT list
47
+
48
+ name = country2["name"]["common"] # "Germany"
49
+ currencies = country2["currencies"] # {"EUR": {"name": "euro", "symbol": "€"}}
50
+ currency_codes = list(currencies.keys()) # ["EUR"]
51
+ currency_name = currencies["EUR"]["name"] # "euro"
52
+ languages = country2["languages"] # {"deu": "German"}
53
+ lang_names = list(languages.values()) # ["German"]
54
+ flag_png = country2["flags"]["png"] # "https://flagcdn.com/w320/de.png"
55
+ flag_svg = country2["flags"]["svg"] # "https://flagcdn.com/de.svg"
56
+ flag_alt = country2["flags"]["alt"] # description text
57
+
58
+ print(name, currency_codes, lang_names)
59
+ # Confirmed: Germany ['EUR'] ['German']
60
+ ```
61
+
62
+ ### Batch lookup — multiple codes in one call
63
+
64
+ Use `/alpha?codes=` for fetching a known list of countries — always returns a list.
65
+
66
+ ```python
67
+ import json
68
+ from helpers import http_get
69
+
70
+ codes = ["US", "GB", "FR", "DE", "JP", "CN", "IN", "BR", "AU", "CA"]
71
+ data = http_get(f"https://restcountries.com/v3.1/alpha?codes={','.join(codes)}&fields=name,cca2,population")
72
+ countries = json.loads(data)
73
+ # Returns list, order NOT guaranteed to match input order
74
+ for c in countries:
75
+ print(c["cca2"], c["name"]["common"], c["population"])
76
+ # Confirmed: 10 results, returned in arbitrary order
77
+ ```
78
+
79
+ ### Search by name
80
+
81
+ ```python
82
+ import json
83
+ from helpers import http_get
84
+
85
+ # Partial match (default) — may return multiple results
86
+ data = http_get("https://restcountries.com/v3.1/name/united")
87
+ results = json.loads(data)
88
+ # Returns 7 countries: United States, UK, UAE, Tanzania, Mexico, ...
89
+
90
+ # Exact match — use fullText=true with the full common or official name
91
+ data2 = http_get("https://restcountries.com/v3.1/name/united%20kingdom?fullText=true")
92
+ results2 = json.loads(data2)
93
+ # Returns exactly 1 result: United Kingdom
94
+ print(results2[0]["name"]["common"]) # United Kingdom
95
+ ```
96
+
97
+ ### Filter by region
98
+
99
+ ```python
100
+ import json
101
+ from helpers import http_get
102
+
103
+ data = http_get("https://restcountries.com/v3.1/region/europe?fields=name,cca2,population")
104
+ countries = json.loads(data)
105
+ # 53 European countries — confirmed
106
+
107
+ # Sort by population
108
+ ranked = sorted(countries, key=lambda x: x["population"], reverse=True)
109
+ for c in ranked[:5]:
110
+ print(c["cca2"], c["name"]["common"], f"{c['population']:,}")
111
+ # Confirmed top 5: RU Russia, DE Germany, FR France, GB United Kingdom, IT Italy
112
+ ```
113
+
114
+ Valid region values: `africa`, `americas`, `asia`, `europe`, `oceania`, `antarctic`
115
+
116
+ ### Filter by subregion
117
+
118
+ ```python
119
+ import json
120
+ from helpers import http_get
121
+
122
+ data = http_get("https://restcountries.com/v3.1/subregion/Western%20Europe?fields=name,cca2")
123
+ countries = json.loads(data)
124
+ print([c["cca2"] for c in countries])
125
+ # Confirmed: ['FR', 'NL', 'MC', 'DE', 'BE', 'LI', 'CH', 'LU']
126
+ ```
127
+
128
+ ### Filter by language
129
+
130
+ ```python
131
+ import json
132
+ from helpers import http_get
133
+
134
+ data = http_get("https://restcountries.com/v3.1/lang/arabic")
135
+ countries = json.loads(data)
136
+ print(f"Arabic-speaking countries: {len(countries)}")
137
+ # Confirmed: 25 countries
138
+
139
+ # Language param is the language name (English), not the ISO 639-3 code
140
+ # Works: arabic, french, spanish, english, portuguese, german, russian, chinese
141
+ ```
142
+
143
+ ### Filter by currency
144
+
145
+ ```python
146
+ import json
147
+ from helpers import http_get
148
+
149
+ data = http_get("https://restcountries.com/v3.1/currency/EUR")
150
+ countries = json.loads(data)
151
+ print(f"EUR countries: {len(countries)}") # Confirmed: 36
152
+ names = [c["name"]["common"] for c in countries]
153
+ print(names[:5])
154
+
155
+ # Use ISO 4217 currency code (uppercase)
156
+ ```
157
+
158
+ ### Filter by capital city
159
+
160
+ ```python
161
+ import json
162
+ from helpers import http_get
163
+
164
+ data = http_get("https://restcountries.com/v3.1/capital/berlin?fields=name,cca2,capital")
165
+ result = json.loads(data)
166
+ print(result[0]["name"]["common"], result[0]["capital"])
167
+ # Confirmed: Germany ['Berlin']
168
+ # Capital param is case-insensitive
169
+ ```
170
+
171
+ ### Full country detail — all fields
172
+
173
+ ```python
174
+ import json
175
+ from helpers import http_get
176
+
177
+ data = http_get("https://restcountries.com/v3.1/alpha/US")
178
+ c = json.loads(data)[0]
179
+
180
+ # Available top-level keys (confirmed for US/DE):
181
+ # name, tld, cca2, ccn3, cca3, cioc, independent, status, unMember,
182
+ # currencies, idd, capital, altSpellings, region, subregion, languages,
183
+ # translations, latlng, landlocked, borders, area, demonyms, flag (emoji),
184
+ # maps, population, gini, fifa, car, timezones, continents, flags,
185
+ # coatOfArms, startOfWeek, capitalInfo, postalCode
186
+
187
+ print(c["idd"]) # {"root": "+1", "suffixes": ["201", "202", ...]}
188
+ print(c["car"]["side"]) # "right" or "left"
189
+ print(c["gini"]) # {"2018": 41.4} — year keyed, may be absent
190
+ print(c["timezones"]) # list of UTC offset strings
191
+ print(c["borders"]) # list of cca3 codes for bordering countries
192
+ print(c["latlng"]) # [lat, lng] of geographic center
193
+ ```
194
+
195
+ ## URL reference
196
+
197
+ | Endpoint | Pattern | Notes |
198
+ |---|---|---|
199
+ | All countries | `/v3.1/all` | Always add `?fields=` |
200
+ | By code | `/v3.1/alpha/{code}` | cca2 or cca3; single code → list (no fields) or dict (with fields) |
201
+ | By codes | `/v3.1/alpha?codes=DE,FR,JP` | Always returns list |
202
+ | By name | `/v3.1/name/{name}` | Partial; add `?fullText=true` for exact match |
203
+ | By region | `/v3.1/region/{region}` | africa, americas, asia, europe, oceania, antarctic |
204
+ | By subregion | `/v3.1/subregion/{subregion}` | URL-encode spaces as `%20` |
205
+ | By language | `/v3.1/lang/{language}` | English language name |
206
+ | By currency | `/v3.1/currency/{code}` | ISO 4217 (EUR, USD, GBP) |
207
+ | By capital | `/v3.1/capital/{city}` | Case-insensitive |
208
+
209
+ All endpoints accept `?fields=field1,field2,...` to limit response payload.
210
+
211
+ ## Gotchas
212
+
213
+ - **`name` is a nested object, not a string.** Use `c["name"]["common"]` for the familiar English name, `c["name"]["official"]` for the full official name. `nativeName` is a dict keyed by ISO 639-3 language code.
214
+
215
+ - **`/alpha/CODE` return type depends on whether `?fields=` is present.** Without `?fields=`, returns a list (one element). With `?fields=...`, returns a plain dict. Use `json.loads(data)[0]` for the no-fields case, `json.loads(data)` for the fields case. Using `/alpha?codes=CODE` always returns a list regardless.
216
+
217
+ - **`currencies` is a dict keyed by ISO 4217 code, not a list.** `c["currencies"]["EUR"]["name"]` → `"euro"`, `c["currencies"]["EUR"]["symbol"]` → `"€"`. A country can have multiple currencies — iterate `currencies.items()`.
218
+
219
+ - **`languages` is a dict keyed by ISO 639-3 code.** `c["languages"]["deu"]` → `"German"`. Use `list(c["languages"].values())` for a simple list of language names.
220
+
221
+ - **`capital` is a list and may be empty.** Some territories (Antarctica, Bouvet Island, Macau, Heard Island) have no capital — `c.get("capital")` returns `[]`, not `None`. Guard with `c["capital"][0] if c.get("capital") else None`. South Africa has 3 capitals.
222
+
223
+ - **`gini` is a dict keyed by year string, may be absent entirely.** `c["gini"]` → `{"2016": 31.9}`. Many small countries or territories have no gini data — always check `c.get("gini")`.
224
+
225
+ - **`borders` uses cca3 codes, not cca2.** `c["borders"]` → `["AUT", "BEL", ...]`. Cross-reference with another `/alpha?codes=` call to resolve to names.
226
+
227
+ - **`translations` covers ~45 languages.** Each entry: `c["translations"]["deu"]` → `{"official": "Bundesrepublik Deutschland", "common": "Deutschland"}`. Useful for multilingual apps.
228
+
229
+ - **No rate limit headers, no documented rate limit.** In practice the API handles rapid sequential calls fine. For bulk crawling hundreds of per-country requests, add a short sleep (`time.sleep(0.5)`) between calls to be polite.
230
+
231
+ - **404 returns JSON, not HTML.** `{"message": "Not Found", "status": 404}`. Wrap calls in try/except and check for this pattern when handling user-supplied country names or codes.
232
+
233
+ - **`?fields=` is the key performance lever.** The full all-countries payload without field filtering is ~1.5 MB. With `?fields=name,cca2,population` it drops to ~50 KB. Always filter when you don't need all fields.