scrapebadger-cli 0.24.2__tar.gz → 0.25.0__tar.gz

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 (66) hide show
  1. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/PKG-INFO +1 -1
  2. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/pyproject.toml +1 -1
  3. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/facebook.py +31 -0
  4. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/perplexity.py +33 -11
  5. scrapebadger_cli-0.25.0/tests/test_perplexity_strict_country.py +36 -0
  6. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/uv.lock +1 -1
  7. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/.gitignore +0 -0
  8. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/README.md +0 -0
  9. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/__init__.py +0 -0
  10. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/client.py +0 -0
  11. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/__init__.py +0 -0
  12. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/agent.py +0 -0
  13. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/airbnb.py +0 -0
  14. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/aliexpress.py +0 -0
  15. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/amazon.py +0 -0
  16. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/apartments.py +0 -0
  17. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/app_store.py +0 -0
  18. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/asos.py +0 -0
  19. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/auth.py +0 -0
  20. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/baidu.py +0 -0
  21. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/bestbuy.py +0 -0
  22. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/bing.py +0 -0
  23. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/booking.py +0 -0
  24. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/chatgpt.py +0 -0
  25. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/depop.py +0 -0
  26. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/duckduckgo.py +0 -0
  27. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/ebay.py +0 -0
  28. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/etsy.py +0 -0
  29. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/gemini.py +0 -0
  30. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/google.py +0 -0
  31. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/google_play.py +0 -0
  32. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/gumtree.py +0 -0
  33. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/idealista.py +0 -0
  34. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/immobiliare.py +0 -0
  35. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/init.py +0 -0
  36. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/instagram.py +0 -0
  37. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/leboncoin.py +0 -0
  38. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/linkedin.py +0 -0
  39. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/loopnet.py +0 -0
  40. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/naver.py +0 -0
  41. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/onboarding.py +0 -0
  42. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/realtor.py +0 -0
  43. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/reddit.py +0 -0
  44. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/redfin.py +0 -0
  45. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/stream.py +0 -0
  46. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/target.py +0 -0
  47. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/tiktok.py +0 -0
  48. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/twitter.py +0 -0
  49. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/vinted.py +0 -0
  50. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/wallapop.py +0 -0
  51. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/walmart.py +0 -0
  52. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/web.py +0 -0
  53. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/yahoo.py +0 -0
  54. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/yandex.py +0 -0
  55. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/youtube.py +0 -0
  56. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/commands/zillow.py +0 -0
  57. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/config.py +0 -0
  58. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/main.py +0 -0
  59. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/output.py +0 -0
  60. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/results.py +0 -0
  61. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/src/scrapebadger_cli/views.py +0 -0
  62. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/tests/test_agent_features.py +0 -0
  63. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/tests/test_google_light_search.py +0 -0
  64. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/tests/test_naver.py +0 -0
  65. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/tests/test_tiktok_pagination.py +0 -0
  66. {scrapebadger_cli-0.24.2 → scrapebadger_cli-0.25.0}/tests/test_vinted_image_search.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: scrapebadger-cli
3
- Version: 0.24.2
3
+ Version: 0.25.0
4
4
  Summary: ScrapeBadger CLI — Twitter, Vinted, Google, and Web Scraping from the command line
5
5
  Author: ScrapeBadger Team
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "scrapebadger-cli"
3
- version = "0.24.2"
3
+ version = "0.25.0"
4
4
  description = "ScrapeBadger CLI — Twitter, Vinted, Google, and Web Scraping from the command line"
5
5
  requires-python = ">=3.10"
6
6
  license = {text = "MIT"}
@@ -112,6 +112,37 @@ def locations(
112
112
  render(data, fmt, fields)
113
113
 
114
114
 
115
+ @app.command(name="resolve-location")
116
+ def resolve_location(
117
+ query: str | None = typer.Argument(
118
+ None, help="Town, city, postcode or address (e.g. 'Durham', 'DH1 3LE')"
119
+ ),
120
+ latitude: float | None = typer.Option(None, "--lat", help="Resolve this point instead"),
121
+ longitude: float | None = typer.Option(None, "--lng"),
122
+ country: str | None = typer.Option(
123
+ None, "--country", help="ISO country hint for an ambiguous name (e.g. gb)"
124
+ ),
125
+ fmt: str = FMT,
126
+ fields: str | None = FIELDS,
127
+ ) -> None:
128
+ """Resolve a town/postcode/coordinates to a Marketplace location id (free).
129
+
130
+ Pass the returned place_id as --location on marketplace-search/category.
131
+ """
132
+ params = {
133
+ k: v
134
+ for k, v in {
135
+ "query": query,
136
+ "latitude": latitude,
137
+ "longitude": longitude,
138
+ "country": country,
139
+ }.items()
140
+ if v is not None
141
+ }
142
+ data = api_get("/v1/facebook/marketplace/locations/resolve", params)
143
+ render(data, fmt, fields)
144
+
145
+
115
146
  @app.command()
116
147
  def categories(
117
148
  fmt: str = FMT,
@@ -10,20 +10,38 @@ app = typer.Typer(no_args_is_help=True)
10
10
  FMT = typer.Option("json", "--output", "-o", help="Output format: json, csv, table, markdown")
11
11
  FIELDS = typer.Option(None, "--fields", "-f", help="Comma-separated fields to include")
12
12
  COUNTRY = typer.Option("US", "--country", "-c", help="ISO-3166 alpha-2 egress country")
13
+ ASK_COUNTRY = typer.Option(
14
+ "US",
15
+ "--country",
16
+ "-c",
17
+ help="ISO-3166 alpha-2 market. Best-effort: another market may answer "
18
+ "(the response `country` says which) unless --strict-country is set",
19
+ )
20
+ STRICT = typer.Option(
21
+ False,
22
+ "--strict-country",
23
+ help="Answer only from an exit in --country; fails with 503 country_unavailable "
24
+ "(not billed) when none answers in time",
25
+ )
26
+
27
+
28
+ def _strict(params: dict, strict_country: bool) -> dict:
29
+ return {**params, "strict_country": True} if strict_country else params
13
30
 
14
31
 
15
32
  @app.command()
16
33
  def ask(
17
34
  prompt: str = typer.Argument(..., help="Prompt to send to perplexity.ai (max 4096 chars)"),
18
- country: str = COUNTRY,
35
+ country: str = ASK_COUNTRY,
19
36
  focus: str = typer.Option("web", "--focus", help="Retrieval focus: web, scholar or social"),
37
+ strict_country: bool = STRICT,
20
38
  fmt: str = FMT,
21
39
  fields: str | None = FIELDS,
22
40
  ) -> None:
23
41
  """Ask the real perplexity.ai and get the grounded answer with its cited sources."""
24
42
  data = api_get(
25
43
  "/v1/perplexity/ask",
26
- {"prompt": prompt, "country": country, "focus": focus},
44
+ _strict({"prompt": prompt, "country": country, "focus": focus}, strict_country),
27
45
  )
28
46
  render(data, fmt, fields)
29
47
 
@@ -39,21 +57,25 @@ def brand_visibility(
39
57
  competitors: str | None = typer.Option(
40
58
  None, "--competitors", help="Comma-separated competitor names"
41
59
  ),
42
- country: str = COUNTRY,
60
+ country: str = ASK_COUNTRY,
61
+ strict_country: bool = STRICT,
43
62
  fmt: str = FMT,
44
63
  fields: str | None = FIELDS,
45
64
  ) -> None:
46
65
  """Score how a brand appears in a real Perplexity answer (AEO/GEO)."""
47
66
  data = api_get(
48
67
  "/v1/perplexity/brand-visibility",
49
- {
50
- "prompt": prompt,
51
- "brand": brand,
52
- "domain": domain,
53
- "aliases": aliases,
54
- "competitors": competitors,
55
- "country": country,
56
- },
68
+ _strict(
69
+ {
70
+ "prompt": prompt,
71
+ "brand": brand,
72
+ "domain": domain,
73
+ "aliases": aliases,
74
+ "competitors": competitors,
75
+ "country": country,
76
+ },
77
+ strict_country,
78
+ ),
57
79
  )
58
80
  render(data, fmt, fields)
59
81
 
@@ -0,0 +1,36 @@
1
+ from unittest.mock import Mock
2
+
3
+ import pytest
4
+
5
+ CliRunner = pytest.importorskip("typer.testing").CliRunner
6
+ perplexity = pytest.importorskip(
7
+ "scrapebadger_cli.commands.perplexity", reason="CLI is tested with its own installed package"
8
+ )
9
+
10
+
11
+ def _invoke(monkeypatch, args):
12
+ call = Mock(return_value={})
13
+ monkeypatch.setattr(perplexity, "api_get", call)
14
+ monkeypatch.setattr(perplexity, "render", Mock())
15
+ result = CliRunner().invoke(perplexity.app, args)
16
+ assert result.exit_code == 0, result.output
17
+ return call.call_args.args
18
+
19
+
20
+ def test_ask_omits_strict_country_by_default(monkeypatch):
21
+ path, params = _invoke(monkeypatch, ["ask", "q", "--country", "DE"])
22
+ assert path == "/v1/perplexity/ask"
23
+ assert params["country"] == "DE" and "strict_country" not in params
24
+
25
+
26
+ def test_ask_strict_country(monkeypatch):
27
+ _, params = _invoke(monkeypatch, ["ask", "q", "--country", "DE", "--strict-country"])
28
+ assert params["strict_country"] is True
29
+
30
+
31
+ def test_brand_strict_country(monkeypatch):
32
+ path, params = _invoke(
33
+ monkeypatch, ["brand", "q", "--brand", "Nike", "-c", "JP", "--strict-country"]
34
+ )
35
+ assert path == "/v1/perplexity/brand-visibility"
36
+ assert params["strict_country"] is True and params["country"] == "JP"
@@ -228,7 +228,7 @@ wheels = [
228
228
 
229
229
  [[package]]
230
230
  name = "scrapebadger-cli"
231
- version = "0.24.2"
231
+ version = "0.25.0"
232
232
  source = { editable = "." }
233
233
  dependencies = [
234
234
  { name = "httpx" },