scrapebadger-cli 0.2.1__tar.gz → 0.4.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 (31) hide show
  1. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/PKG-INFO +8 -1
  2. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/README.md +7 -0
  3. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/pyproject.toml +1 -1
  4. scrapebadger_cli-0.4.0/src/scrapebadger_cli/commands/depop.py +106 -0
  5. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/google.py +7 -0
  6. scrapebadger_cli-0.4.0/src/scrapebadger_cli/commands/linkedin.py +171 -0
  7. scrapebadger_cli-0.4.0/src/scrapebadger_cli/commands/redfin.py +121 -0
  8. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/main.py +6 -0
  9. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/.gitignore +0 -0
  10. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/__init__.py +0 -0
  11. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/client.py +0 -0
  12. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/__init__.py +0 -0
  13. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/amazon.py +0 -0
  14. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/auth.py +0 -0
  15. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/ebay.py +0 -0
  16. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/idealista.py +0 -0
  17. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/immobiliare.py +0 -0
  18. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/leboncoin.py +0 -0
  19. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/loopnet.py +0 -0
  20. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/realtor.py +0 -0
  21. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/reddit.py +0 -0
  22. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/stream.py +0 -0
  23. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/tiktok.py +0 -0
  24. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/twitter.py +0 -0
  25. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/vinted.py +0 -0
  26. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/web.py +0 -0
  27. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/youtube.py +0 -0
  28. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/commands/zillow.py +0 -0
  29. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/config.py +0 -0
  30. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/src/scrapebadger_cli/output.py +0 -0
  31. {scrapebadger_cli-0.2.1 → scrapebadger_cli-0.4.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scrapebadger-cli
3
- Version: 0.2.1
3
+ Version: 0.4.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
@@ -28,6 +28,13 @@ Command-line interface for ScrapeBadger — Twitter, Vinted, and Web Scraping.
28
28
 
29
29
  ```bash
30
30
  pip install scrapebadger-cli
31
+ # or: uv tool install scrapebadger-cli
32
+ ```
33
+
34
+ The installed command is `scrapebadger`. To run without installing:
35
+
36
+ ```bash
37
+ uvx --from scrapebadger-cli scrapebadger --help
31
38
  ```
32
39
 
33
40
  ## Quick Start
@@ -6,6 +6,13 @@ Command-line interface for ScrapeBadger — Twitter, Vinted, and Web Scraping.
6
6
 
7
7
  ```bash
8
8
  pip install scrapebadger-cli
9
+ # or: uv tool install scrapebadger-cli
10
+ ```
11
+
12
+ The installed command is `scrapebadger`. To run without installing:
13
+
14
+ ```bash
15
+ uvx --from scrapebadger-cli scrapebadger --help
9
16
  ```
10
17
 
11
18
  ## Quick Start
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "scrapebadger-cli"
3
- version = "0.2.1"
3
+ version = "0.4.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"}
@@ -0,0 +1,106 @@
1
+ """Depop marketplace commands."""
2
+
3
+ import typer
4
+
5
+ from scrapebadger_cli.client import api_get
6
+ from scrapebadger_cli.output import render
7
+
8
+ app = typer.Typer(no_args_is_help=True)
9
+
10
+ FMT = typer.Option("json", "--output", "-o", help="Output format: json, csv, table, markdown")
11
+ FIELDS = typer.Option(None, "--fields", "-f", help="Comma-separated fields to include")
12
+ MARKET = typer.Option("us", "--market", "-m", help="us, gb (uk), au, ie, it, fr, de, es, nl, nz")
13
+
14
+
15
+ @app.command()
16
+ def search(
17
+ query: str = typer.Argument(..., help='Search text (e.g. "nike vintage")'),
18
+ market: str = MARKET,
19
+ per_page: int = typer.Option(24, "--per-page", "-p", help="1-24 (default 24)"),
20
+ page: int = typer.Option(1, "--page", help="Page number (default 1)"),
21
+ price_min: float | None = typer.Option(None, "--price-min"),
22
+ price_max: float | None = typer.Option(None, "--price-max"),
23
+ brands: str | None = typer.Option(None, "--brands", help="CSV of numeric brand IDs"),
24
+ sizes: str | None = typer.Option(
25
+ None, "--sizes", help='CSV of size labels (e.g. "US-M,UK-12")'
26
+ ),
27
+ colours: str | None = typer.Option(None, "--colours", help="CSV of colour slugs"),
28
+ conditions: str | None = typer.Option(
29
+ None, "--conditions", help="CSV: brand_new, used_like_new, used_good, used_fair"
30
+ ),
31
+ gender: str | None = typer.Option(None, "--gender", help="male or female"),
32
+ sort: str | None = typer.Option(
33
+ None,
34
+ "--sort",
35
+ help="relevance, newest, priceAscending, priceDescending, popularity",
36
+ ),
37
+ fmt: str = FMT,
38
+ fields: str | None = FIELDS,
39
+ ) -> None:
40
+ """Search Depop for second-hand fashion products."""
41
+ data = api_get(
42
+ "/v1/depop/search",
43
+ {
44
+ "query": query,
45
+ "market": market,
46
+ "per_page": per_page,
47
+ "page": page,
48
+ "price_min": price_min,
49
+ "price_max": price_max,
50
+ "brands": brands,
51
+ "sizes": sizes,
52
+ "colours": colours,
53
+ "conditions": conditions,
54
+ "gender": gender,
55
+ "sort": sort,
56
+ },
57
+ )
58
+ render(data, fmt, fields)
59
+
60
+
61
+ @app.command()
62
+ def product(
63
+ slug: str = typer.Argument(..., help="Depop product slug"),
64
+ market: str = MARKET,
65
+ fmt: str = FMT,
66
+ fields: str | None = FIELDS,
67
+ ) -> None:
68
+ """Get a Depop product's full detail by slug."""
69
+ data = api_get(f"/v1/depop/products/{slug}", {"market": market})
70
+ render(data, fmt, fields)
71
+
72
+
73
+ @app.command()
74
+ def user(
75
+ username: str = typer.Argument(..., help="Depop username"),
76
+ market: str = MARKET,
77
+ fmt: str = FMT,
78
+ fields: str | None = FIELDS,
79
+ ) -> None:
80
+ """Get a Depop shop/user profile by username."""
81
+ data = api_get(f"/v1/depop/users/{username}", {"market": market})
82
+ render(data, fmt, fields)
83
+
84
+
85
+ @app.command("user-products")
86
+ def user_products(
87
+ username: str = typer.Argument(..., help="Depop username"),
88
+ market: str = MARKET,
89
+ per_page: int = typer.Option(24, "--per-page", "-p", help="1-24 (default 24)"),
90
+ page: int = typer.Option(1, "--page", help="Page number (default 1)"),
91
+ fmt: str = FMT,
92
+ fields: str | None = FIELDS,
93
+ ) -> None:
94
+ """Get a Depop seller's listings by username."""
95
+ data = api_get(
96
+ f"/v1/depop/users/{username}/products",
97
+ {"market": market, "per_page": per_page, "page": page},
98
+ )
99
+ render(data, fmt, fields)
100
+
101
+
102
+ @app.command("markets")
103
+ def list_markets(fmt: str = FMT, fields: str | None = FIELDS) -> None:
104
+ """List Depop coverage markets (us, gb, au, ie, it, fr, de, es, nl, nz)."""
105
+ data = api_get("/v1/depop/markets", {})
106
+ render(data, fmt, fields)
@@ -1092,6 +1092,12 @@ def flights_search(
1092
1092
  hl: str | None = typer.Option(None, "--hl", help="Language code"),
1093
1093
  stops: str | None = typer.Option(None, "--stops", help="any | nonstop | one_stop | two_stops"),
1094
1094
  max_price: int | None = typer.Option(None, "--max-price", help="Upper price filter"),
1095
+ sort_by: str | None = typer.Option(
1096
+ None,
1097
+ "--sort-by",
1098
+ help="top (default, fast best picks) | price (FULL price-sorted inventory "
1099
+ "+ Google's price floor/typical range/history; slower)",
1100
+ ),
1095
1101
  fmt: str = FMT,
1096
1102
  fields: str | None = FIELDS,
1097
1103
  ) -> None:
@@ -1112,6 +1118,7 @@ def flights_search(
1112
1118
  "hl": hl,
1113
1119
  "stops": stops,
1114
1120
  "max_price": max_price,
1121
+ "sort_by": sort_by,
1115
1122
  },
1116
1123
  )
1117
1124
  render(data, fmt, fields)
@@ -0,0 +1,171 @@
1
+ """LinkedIn public-data commands."""
2
+
3
+ import typer
4
+
5
+ from scrapebadger_cli.client import api_get
6
+ from scrapebadger_cli.output import render
7
+
8
+ app = typer.Typer(no_args_is_help=True)
9
+
10
+ FMT = typer.Option("json", "--output", "-o", help="Output format: json, csv, table, markdown")
11
+ FIELDS = typer.Option(None, "--fields", "-f", help="Comma-separated fields to include")
12
+ COUNTRY = typer.Option("us", "--country", "-c", help="Country code (default us)")
13
+
14
+
15
+ @app.command("jobs-search")
16
+ def jobs_search(
17
+ keywords: str | None = typer.Option(None, "--keywords", "-k", help="Search text"),
18
+ location: str | None = typer.Option(None, "--location", "-l", help="Location name"),
19
+ geo_id: str | None = typer.Option(None, "--geo-id", help="LinkedIn numeric geo id"),
20
+ company_id: str | None = typer.Option(None, "--company-id", help="LinkedIn numeric company id"),
21
+ date_posted: str | None = typer.Option(
22
+ None, "--date-posted", help="past_24h, past_week, past_month, any"
23
+ ),
24
+ experience: str | None = typer.Option(
25
+ None,
26
+ "--experience",
27
+ help="CSV: internship, entry, associate, mid_senior, director, executive",
28
+ ),
29
+ job_type: str | None = typer.Option(
30
+ None,
31
+ "--job-type",
32
+ help="CSV: full_time, part_time, contract, temporary, internship, volunteer, other",
33
+ ),
34
+ workplace: str | None = typer.Option(None, "--workplace", help="CSV: onsite, remote, hybrid"),
35
+ sort: str | None = typer.Option(None, "--sort", help="relevant or recent"),
36
+ start: int = typer.Option(0, "--start", help="Pagination offset (default 0)"),
37
+ country: str = COUNTRY,
38
+ fmt: str = FMT,
39
+ fields: str | None = FIELDS,
40
+ ) -> None:
41
+ """Search LinkedIn public job postings."""
42
+ data = api_get(
43
+ "/v1/linkedin/jobs/search",
44
+ {
45
+ "keywords": keywords,
46
+ "location": location,
47
+ "geo_id": geo_id,
48
+ "company_id": company_id,
49
+ "date_posted": date_posted,
50
+ "experience": experience,
51
+ "job_type": job_type,
52
+ "workplace": workplace,
53
+ "sort": sort,
54
+ "start": start,
55
+ "country": country,
56
+ },
57
+ )
58
+ render(data, fmt, fields)
59
+
60
+
61
+ @app.command()
62
+ def job(
63
+ job_id: str = typer.Argument(..., help="Numeric LinkedIn job id"),
64
+ country: str = COUNTRY,
65
+ fmt: str = FMT,
66
+ fields: str | None = FIELDS,
67
+ ) -> None:
68
+ """Get a LinkedIn job posting's full detail by numeric id."""
69
+ data = api_get(f"/v1/linkedin/jobs/{job_id}", {"country": country})
70
+ render(data, fmt, fields)
71
+
72
+
73
+ @app.command("company-jobs")
74
+ def company_jobs(
75
+ company_id: str = typer.Argument(..., help="Numeric LinkedIn company id"),
76
+ start: int = typer.Option(0, "--start", help="Pagination offset (default 0)"),
77
+ country: str = COUNTRY,
78
+ fmt: str = FMT,
79
+ fields: str | None = FIELDS,
80
+ ) -> None:
81
+ """Get a LinkedIn company's job postings by numeric company id."""
82
+ data = api_get(
83
+ f"/v1/linkedin/companies/{company_id}/jobs",
84
+ {"start": start, "country": country},
85
+ )
86
+ render(data, fmt, fields)
87
+
88
+
89
+ @app.command()
90
+ def company(
91
+ universal_name: str = typer.Argument(..., help="Company vanity slug (e.g. microsoft)"),
92
+ country: str = COUNTRY,
93
+ fmt: str = FMT,
94
+ fields: str | None = FIELDS,
95
+ ) -> None:
96
+ """Get a LinkedIn company profile by universal name."""
97
+ data = api_get(f"/v1/linkedin/companies/{universal_name}", {"country": country})
98
+ render(data, fmt, fields)
99
+
100
+
101
+ @app.command()
102
+ def school(
103
+ universal_name: str = typer.Argument(..., help="School vanity slug (e.g. stanford-university)"),
104
+ country: str = COUNTRY,
105
+ fmt: str = FMT,
106
+ fields: str | None = FIELDS,
107
+ ) -> None:
108
+ """Get a LinkedIn school profile by universal name."""
109
+ data = api_get(f"/v1/linkedin/schools/{universal_name}", {"country": country})
110
+ render(data, fmt, fields)
111
+
112
+
113
+ @app.command()
114
+ def profile(
115
+ public_id: str = typer.Argument(..., help="Profile public id (e.g. williamhgates)"),
116
+ country: str = COUNTRY,
117
+ fmt: str = FMT,
118
+ fields: str | None = FIELDS,
119
+ ) -> None:
120
+ """Get a LinkedIn member profile by public id."""
121
+ data = api_get(f"/v1/linkedin/profiles/{public_id}", {"country": country})
122
+ render(data, fmt, fields)
123
+
124
+
125
+ @app.command()
126
+ def post(
127
+ post_slug: str = typer.Argument(..., help="LinkedIn post slug"),
128
+ country: str = COUNTRY,
129
+ fmt: str = FMT,
130
+ fields: str | None = FIELDS,
131
+ ) -> None:
132
+ """Get a LinkedIn social post by its slug."""
133
+ data = api_get(f"/v1/linkedin/posts/{post_slug}", {"country": country})
134
+ render(data, fmt, fields)
135
+
136
+
137
+ @app.command()
138
+ def article(
139
+ article_slug: str = typer.Argument(..., help="LinkedIn article slug"),
140
+ country: str = COUNTRY,
141
+ fmt: str = FMT,
142
+ fields: str | None = FIELDS,
143
+ ) -> None:
144
+ """Get a LinkedIn article by its slug."""
145
+ data = api_get(f"/v1/linkedin/articles/{article_slug}", {"country": country})
146
+ render(data, fmt, fields)
147
+
148
+
149
+ @app.command()
150
+ def course(
151
+ course_slug: str = typer.Argument(..., help="LinkedIn Learning course slug"),
152
+ country: str = COUNTRY,
153
+ fmt: str = FMT,
154
+ fields: str | None = FIELDS,
155
+ ) -> None:
156
+ """Get a LinkedIn Learning course by its slug."""
157
+ data = api_get(f"/v1/linkedin/learning/{course_slug}", {"country": country})
158
+ render(data, fmt, fields)
159
+
160
+
161
+ @app.command("geo-suggest")
162
+ def geo_suggest(
163
+ query: str = typer.Argument(..., help="Location or company name to resolve"),
164
+ type: str = typer.Option("geo", "--type", "-t", help="geo or company"),
165
+ country: str = COUNTRY,
166
+ fmt: str = FMT,
167
+ fields: str | None = FIELDS,
168
+ ) -> None:
169
+ """Resolve a location or company name to LinkedIn ids for job-search filters."""
170
+ data = api_get("/v1/linkedin/geo/suggest", {"query": query, "type": type, "country": country})
171
+ render(data, fmt, fields)
@@ -0,0 +1,121 @@
1
+ """Redfin real-estate commands."""
2
+
3
+ import typer
4
+
5
+ from scrapebadger_cli.client import api_get
6
+ from scrapebadger_cli.output import render
7
+
8
+ app = typer.Typer(no_args_is_help=True)
9
+
10
+ FMT = typer.Option("json", "--output", "-o", help="Output format: json, csv, table, markdown")
11
+ FIELDS = typer.Option(None, "--fields", "-f", help="Comma-separated fields to include")
12
+
13
+
14
+ @app.command()
15
+ def search(
16
+ location: str = typer.Argument(..., help="City/state, ZIP, address or neighborhood"),
17
+ page: int = typer.Option(1, "--page", "-p", help="1-20"),
18
+ sort: str | None = typer.Option(
19
+ None, "--sort", help="relevant, newest, price_low_to_high, etc."
20
+ ),
21
+ price_min: int | None = typer.Option(None, "--price-min"),
22
+ price_max: int | None = typer.Option(None, "--price-max"),
23
+ beds_min: int | None = typer.Option(None, "--beds-min"),
24
+ baths_min: float | None = typer.Option(None, "--baths-min"),
25
+ home_type: str | None = typer.Option(
26
+ None,
27
+ "--home-type",
28
+ help="house, condo, townhouse, multi_family, land, other, mobile, coop",
29
+ ),
30
+ sqft_min: int | None = typer.Option(None, "--sqft-min"),
31
+ sqft_max: int | None = typer.Option(None, "--sqft-max"),
32
+ lot_min: int | None = typer.Option(None, "--lot-min"),
33
+ lot_max: int | None = typer.Option(None, "--lot-max"),
34
+ year_built_min: int | None = typer.Option(None, "--year-built-min"),
35
+ year_built_max: int | None = typer.Option(None, "--year-built-max"),
36
+ max_days_on_market: int | None = typer.Option(None, "--max-days-on-market"),
37
+ north: float | None = typer.Option(None, "--north", help="Map bounds for tiling past the cap"),
38
+ south: float | None = typer.Option(None, "--south"),
39
+ east: float | None = typer.Option(None, "--east"),
40
+ west: float | None = typer.Option(None, "--west"),
41
+ fmt: str = FMT,
42
+ fields: str | None = FIELDS,
43
+ ) -> None:
44
+ """Search Redfin for for-sale properties."""
45
+ data = api_get(
46
+ "/v1/redfin/search",
47
+ {
48
+ "location": location,
49
+ "page": page,
50
+ "sort": sort,
51
+ "price_min": price_min,
52
+ "price_max": price_max,
53
+ "beds_min": beds_min,
54
+ "baths_min": baths_min,
55
+ "home_type": home_type,
56
+ "sqft_min": sqft_min,
57
+ "sqft_max": sqft_max,
58
+ "lot_min": lot_min,
59
+ "lot_max": lot_max,
60
+ "year_built_min": year_built_min,
61
+ "year_built_max": year_built_max,
62
+ "max_days_on_market": max_days_on_market,
63
+ "north": north,
64
+ "south": south,
65
+ "east": east,
66
+ "west": west,
67
+ },
68
+ )
69
+ render(data, fmt, fields)
70
+
71
+
72
+ @app.command()
73
+ def property(
74
+ property_id: str = typer.Argument(..., help="Redfin numeric property id"),
75
+ fmt: str = FMT,
76
+ fields: str | None = FIELDS,
77
+ ) -> None:
78
+ """Get a Redfin property's full detail by propertyId."""
79
+ data = api_get(f"/v1/redfin/property/{property_id}", {})
80
+ render(data, fmt, fields)
81
+
82
+
83
+ @app.command("property-url")
84
+ def property_url(
85
+ url: str = typer.Argument(..., help="Full Redfin property URL (/CA/City/.../home/12345678)"),
86
+ fmt: str = FMT,
87
+ fields: str | None = FIELDS,
88
+ ) -> None:
89
+ """Get a Redfin property's full detail by home URL."""
90
+ data = api_get("/v1/redfin/property", {"url": url})
91
+ render(data, fmt, fields)
92
+
93
+
94
+ @app.command()
95
+ def agent(
96
+ agent_id: str | None = typer.Argument(None, help="Redfin agent id"),
97
+ url: str | None = typer.Option(None, "--url", help="Full Redfin /realestateagents/... URL"),
98
+ fmt: str = FMT,
99
+ fields: str | None = FIELDS,
100
+ ) -> None:
101
+ """Get a Redfin agent's profile and their active listings."""
102
+ data = api_get("/v1/redfin/agent", {"agent_id": agent_id, "url": url})
103
+ render(data, fmt, fields)
104
+
105
+
106
+ @app.command()
107
+ def autocomplete(
108
+ query: str = typer.Argument(..., help="Partial location — city, ZIP, address, neighborhood"),
109
+ fmt: str = FMT,
110
+ fields: str | None = FIELDS,
111
+ ) -> None:
112
+ """Resolve a search term to Redfin regions/addresses."""
113
+ data = api_get("/v1/redfin/autocomplete", {"query": query})
114
+ render(data, fmt, fields)
115
+
116
+
117
+ @app.command("markets")
118
+ def list_markets(fmt: str = FMT, fields: str | None = FIELDS) -> None:
119
+ """List Redfin coverage regions (US)."""
120
+ data = api_get("/v1/redfin/markets", {})
121
+ render(data, fmt, fields)
@@ -5,14 +5,17 @@ import typer
5
5
  from scrapebadger_cli.commands import (
6
6
  amazon,
7
7
  auth,
8
+ depop,
8
9
  ebay,
9
10
  google,
10
11
  idealista,
11
12
  immobiliare,
12
13
  leboncoin,
14
+ linkedin,
13
15
  loopnet,
14
16
  realtor,
15
17
  reddit,
18
+ redfin,
16
19
  stream,
17
20
  tiktok,
18
21
  twitter,
@@ -44,6 +47,9 @@ app.add_typer(web.app, name="web", help="Web scraping commands")
44
47
  app.add_typer(google.app, name="google", help="Google scraper commands")
45
48
  app.add_typer(realtor.app, name="realtor", help="Realtor real-estate commands")
46
49
  app.add_typer(loopnet.app, name="loopnet", help="LoopNet commercial real estate commands")
50
+ app.add_typer(depop.app, name="depop", help="Depop marketplace commands")
51
+ app.add_typer(redfin.app, name="redfin", help="Redfin real-estate commands")
52
+ app.add_typer(linkedin.app, name="linkedin", help="LinkedIn public data commands")
47
53
  app.command()(auth.auth)
48
54
  app.command(name="credits")(auth.credits)
49
55
  app.command(name="logout")(auth.logout)