ytscrape 0.1.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.
@@ -0,0 +1,32 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ .eggs/
11
+ wheels/
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ env/
17
+
18
+ # uv
19
+ .uv/
20
+
21
+ # Caches / tooling
22
+ .pytest_cache/
23
+ .mypy_cache/
24
+ .ruff_cache/
25
+ .cache/
26
+
27
+ # IDE
28
+ .idea/
29
+ *.iml
30
+
31
+ # OS
32
+ .DS_Store
ytscrape-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hural
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.4
2
+ Name: ytscrape
3
+ Version: 0.1.0
4
+ Summary: YouTube scraper for Python — search videos, channels and playlists and fetch video metadata via the InnerTube API, no API key required.
5
+ Project-URL: Homepage, https://github.com/hural/ytscraper
6
+ Project-URL: Repository, https://github.com/hural/ytscraper
7
+ Project-URL: Issues, https://github.com/hural/ytscraper/issues
8
+ Author: hural
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 hural
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: crawler,free,innertube,no-api-key,scraper,scraping,search,video,youtube,youtube-api,youtube-data,youtube-scraper
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Operating System :: OS Independent
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3 :: Only
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Programming Language :: Python :: 3.13
42
+ Classifier: Programming Language :: Python :: 3.14
43
+ Classifier: Topic :: Internet :: WWW/HTTP
44
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
45
+ Classifier: Typing :: Typed
46
+ Requires-Python: >=3.10
47
+ Requires-Dist: build>=1.5.0
48
+ Requires-Dist: pycountry>=22.3.5
49
+ Requires-Dist: requests>=2.28
50
+ Requires-Dist: twine>=7.0.0
51
+ Description-Content-Type: text/markdown
52
+
53
+ # ytscraper — Free YouTube Scraper for Python
54
+
55
+ [![PyPI version](https://img.shields.io/pypi/v/ytscraper.svg)](https://pypi.org/project/ytscraper/)
56
+ [![Python versions](https://img.shields.io/pypi/pyversions/ytscraper.svg)](https://pypi.org/project/ytscraper/)
57
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
58
+
59
+ > **Free, open-source YouTube scraper library for Python.** Scrape YouTube
60
+ > search results — videos, channels, playlists and Shorts — plus detailed video
61
+ > metadata, **without an official YouTube Data API key** and **without any quota
62
+ > limits**.
63
+
64
+ `ytscraper` is a **free YouTube scraper and crawler** for Python built on top of
65
+ the internal YouTube *InnerTube* API. Use it to **search YouTube**, **extract
66
+ video, channel and playlist data**, and **fetch video metadata** — all with
67
+ **transparent pagination** and no API key required.
68
+
69
+ Whether you need to **scrape YouTube videos**, **collect channel data**, **mine
70
+ YouTube search results**, or build a **YouTube data extractor** or **dataset**,
71
+ `ytscraper` gives you a simple, Pythonic interface and a clean, extensible
72
+ architecture that is easy to grow with new endpoints and data sources.
73
+
74
+ **Keywords:** free youtube scraper, youtube scraper python, youtube data
75
+ extractor, youtube api without key, scrape youtube videos, youtube channel
76
+ scraper, youtube search scraper, youtube crawler, youtube metadata, python
77
+ youtube scraping library, open source youtube scraper.
78
+
79
+ > ⚠️ This library talks to YouTube's private endpoints. Use it responsibly and
80
+ > at your own risk; the endpoints and `params` values may change over time.
81
+
82
+ ## Why ytscraper?
83
+
84
+ - ✅ **Free & open source** (MIT) — no paid plans, no sign-up, no rate-limit
85
+ tiers.
86
+ - 🔑 **No YouTube Data API key required** and **no quota** to worry about.
87
+ - 🐍 **Pure Python** with full type hints and a tiny, dependency-light install.
88
+ - ⚡ Simple, Pythonic API — start scraping YouTube in just a few lines.
89
+
90
+ ## Features
91
+
92
+ - 🔎 Search videos, channels and playlists with a clean `SearchFilter` enum
93
+ (no magic `EgIQAQ==` strings in your code).
94
+ - 📄 **Transparent pagination** — just iterate; continuation tokens are handled
95
+ for you.
96
+ - 🎬 Fetch detailed video metadata from an id or any YouTube URL.
97
+ - 🌍 **Language & country support** — localise results with the `Language`
98
+ and `Country` value objects (thin wrappers around raw ISO codes, no
99
+ hard-coded lists) bundled in a small `Locale` object; codes are validated
100
+ with `pycountry`, so typos fail fast.
101
+ - 🧱 Extensible OOP design (facade + factory methods + strategy) and full type
102
+ hints — easy to build on.
103
+ - 🖥️ A tiny CLI: `python -m ytscraper ...`.
104
+
105
+ ## Installation
106
+
107
+ ```bash
108
+ pip install ytscraper
109
+ ```
110
+
111
+ From source:
112
+
113
+ ```bash
114
+ pip install .
115
+ ```
116
+
117
+ ## Quick start
118
+
119
+ ```python
120
+ from ytscraper import YouTube, SearchFilter
121
+
122
+ with YouTube() as yt:
123
+ # Search videos and iterate over as many pages as needed.
124
+ for video in yt.search("python", filter=SearchFilter.VIDEOS, max_results=20):
125
+ print(video.title, "-", video.url)
126
+
127
+ # Search channels.
128
+ for channel in yt.search("python", filter=SearchFilter.CHANNELS, max_results=5):
129
+ print(channel.title, channel.url)
130
+
131
+ # Fetch details for a single video (id or URL both work).
132
+ details = yt.video("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
133
+ print(details.title, details.channel, details.views)
134
+ ```
135
+
136
+ ### Search filters
137
+
138
+ | Filter | Description |
139
+ | -------------------------- | ------------------- |
140
+ | `SearchFilter.ALL` | Everything (default)|
141
+ | `SearchFilter.VIDEOS` | Videos only |
142
+ | `SearchFilter.CHANNELS` | Channels only |
143
+ | `SearchFilter.PLAYLISTS` | Playlists only |
144
+ | `SearchFilter.SHORTS` | Shorts only |
145
+ | `SearchFilter.MOVIES` | Movies only |
146
+
147
+ You can also pass the string form: `yt.search("python", filter="videos")`.
148
+
149
+ ### Language & country
150
+
151
+ YouTube localises results by *interface language* (`hl`) and *content region*
152
+ (`gl`). Configure both when creating `YouTube`, passing plain ISO codes (or the
153
+ `Language` / `Country` value objects, which wrap the same codes):
154
+
155
+ ```python
156
+ from ytscraper import YouTube, Language, Country, Locale
157
+
158
+ # Just pass raw ISO codes — they are validated and normalised for you.
159
+ with YouTube(language="uk", region="UA") as yt:
160
+ for video in yt.search("музика", max_results=10):
161
+ print(video.title, video.url)
162
+
163
+ # The Language / Country value objects are equivalent (and reusable).
164
+ yt = YouTube(language=Language("de"), region=Country("DE"))
165
+
166
+ # Invalid codes are rejected early (validated with pycountry).
167
+ YouTube(region="XX") # ValueError: Unknown country code 'XX'. ...
168
+
169
+ # Or pass a ready-made Locale.
170
+ yt = YouTube(locale=Locale(language="fr", country="FR"))
171
+ print(yt.locale.language.code, yt.locale.country.code) # fr FR
172
+ ```
173
+
174
+ `Language` and `Country` are thin, self-validating value objects around a raw
175
+ ISO 639-1 / ISO 3166-1 alpha-2 code — there is no hard-coded list of languages
176
+ or countries, so any valid code works. Codes are validated with
177
+ [`pycountry`](https://pypi.org/project/pycountry/): an unknown language or
178
+ country code raises a `ValueError` instead of silently producing a broken
179
+ request. The chosen locale is sent both in the request context (`hl` / `gl`)
180
+ and as the `Accept-Language` HTTP header.
181
+
182
+ ### Pagination
183
+
184
+ Pagination is transparent — iterating over the result object automatically
185
+ loads the next page:
186
+
187
+ ```python
188
+ results = yt.search("python")
189
+
190
+ for item in results: # loads pages on demand
191
+ print(item.title)
192
+ ```
193
+
194
+ You can also page manually:
195
+
196
+ ```python
197
+ results = yt.search("python")
198
+ print(len(results.fetch_next_page())) # explicitly load one more page
199
+ print(results.has_more) # is there another page?
200
+ ```
201
+
202
+ Use `max_results` to cap how many items you consume.
203
+
204
+ ## Use cases
205
+
206
+ `ytscraper` is a great fit when you want to:
207
+
208
+ - **Scrape YouTube search results** for a keyword or topic.
209
+ - **Extract YouTube video data** (title, channel, views, duration, thumbnails).
210
+ - **Collect YouTube channel and playlist listings** at scale.
211
+ - **Build a YouTube dataset** for research, analytics or machine learning.
212
+ - **Monitor YouTube** content for a niche without hitting API quotas.
213
+
214
+ ## Command line
215
+
216
+ ```bash
217
+ # Search
218
+ python -m ytscraper search "python tutorial" --filter videos --max 10
219
+
220
+ # Localised search (Ukrainian interface, Ukrainian region)
221
+ python -m ytscraper --language uk --region UA search "музика" --max 10
222
+
223
+ # Video details
224
+ python -m ytscraper video https://www.youtube.com/watch?v=dQw4w9WgXcQ
225
+ ```
226
+
227
+ After installing, a `ytscraper` console script is also available:
228
+
229
+ ```bash
230
+ ytscraper search "python" --filter channels --max 5
231
+ ```
232
+
233
+ ## License
234
+
235
+ [MIT](LICENSE)
@@ -0,0 +1,183 @@
1
+ # ytscraper — Free YouTube Scraper for Python
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/ytscraper.svg)](https://pypi.org/project/ytscraper/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/ytscraper.svg)](https://pypi.org/project/ytscraper/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
6
+
7
+ > **Free, open-source YouTube scraper library for Python.** Scrape YouTube
8
+ > search results — videos, channels, playlists and Shorts — plus detailed video
9
+ > metadata, **without an official YouTube Data API key** and **without any quota
10
+ > limits**.
11
+
12
+ `ytscraper` is a **free YouTube scraper and crawler** for Python built on top of
13
+ the internal YouTube *InnerTube* API. Use it to **search YouTube**, **extract
14
+ video, channel and playlist data**, and **fetch video metadata** — all with
15
+ **transparent pagination** and no API key required.
16
+
17
+ Whether you need to **scrape YouTube videos**, **collect channel data**, **mine
18
+ YouTube search results**, or build a **YouTube data extractor** or **dataset**,
19
+ `ytscraper` gives you a simple, Pythonic interface and a clean, extensible
20
+ architecture that is easy to grow with new endpoints and data sources.
21
+
22
+ **Keywords:** free youtube scraper, youtube scraper python, youtube data
23
+ extractor, youtube api without key, scrape youtube videos, youtube channel
24
+ scraper, youtube search scraper, youtube crawler, youtube metadata, python
25
+ youtube scraping library, open source youtube scraper.
26
+
27
+ > ⚠️ This library talks to YouTube's private endpoints. Use it responsibly and
28
+ > at your own risk; the endpoints and `params` values may change over time.
29
+
30
+ ## Why ytscraper?
31
+
32
+ - ✅ **Free & open source** (MIT) — no paid plans, no sign-up, no rate-limit
33
+ tiers.
34
+ - 🔑 **No YouTube Data API key required** and **no quota** to worry about.
35
+ - 🐍 **Pure Python** with full type hints and a tiny, dependency-light install.
36
+ - ⚡ Simple, Pythonic API — start scraping YouTube in just a few lines.
37
+
38
+ ## Features
39
+
40
+ - 🔎 Search videos, channels and playlists with a clean `SearchFilter` enum
41
+ (no magic `EgIQAQ==` strings in your code).
42
+ - 📄 **Transparent pagination** — just iterate; continuation tokens are handled
43
+ for you.
44
+ - 🎬 Fetch detailed video metadata from an id or any YouTube URL.
45
+ - 🌍 **Language & country support** — localise results with the `Language`
46
+ and `Country` value objects (thin wrappers around raw ISO codes, no
47
+ hard-coded lists) bundled in a small `Locale` object; codes are validated
48
+ with `pycountry`, so typos fail fast.
49
+ - 🧱 Extensible OOP design (facade + factory methods + strategy) and full type
50
+ hints — easy to build on.
51
+ - 🖥️ A tiny CLI: `python -m ytscraper ...`.
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ pip install ytscraper
57
+ ```
58
+
59
+ From source:
60
+
61
+ ```bash
62
+ pip install .
63
+ ```
64
+
65
+ ## Quick start
66
+
67
+ ```python
68
+ from ytscraper import YouTube, SearchFilter
69
+
70
+ with YouTube() as yt:
71
+ # Search videos and iterate over as many pages as needed.
72
+ for video in yt.search("python", filter=SearchFilter.VIDEOS, max_results=20):
73
+ print(video.title, "-", video.url)
74
+
75
+ # Search channels.
76
+ for channel in yt.search("python", filter=SearchFilter.CHANNELS, max_results=5):
77
+ print(channel.title, channel.url)
78
+
79
+ # Fetch details for a single video (id or URL both work).
80
+ details = yt.video("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
81
+ print(details.title, details.channel, details.views)
82
+ ```
83
+
84
+ ### Search filters
85
+
86
+ | Filter | Description |
87
+ | -------------------------- | ------------------- |
88
+ | `SearchFilter.ALL` | Everything (default)|
89
+ | `SearchFilter.VIDEOS` | Videos only |
90
+ | `SearchFilter.CHANNELS` | Channels only |
91
+ | `SearchFilter.PLAYLISTS` | Playlists only |
92
+ | `SearchFilter.SHORTS` | Shorts only |
93
+ | `SearchFilter.MOVIES` | Movies only |
94
+
95
+ You can also pass the string form: `yt.search("python", filter="videos")`.
96
+
97
+ ### Language & country
98
+
99
+ YouTube localises results by *interface language* (`hl`) and *content region*
100
+ (`gl`). Configure both when creating `YouTube`, passing plain ISO codes (or the
101
+ `Language` / `Country` value objects, which wrap the same codes):
102
+
103
+ ```python
104
+ from ytscraper import YouTube, Language, Country, Locale
105
+
106
+ # Just pass raw ISO codes — they are validated and normalised for you.
107
+ with YouTube(language="uk", region="UA") as yt:
108
+ for video in yt.search("музика", max_results=10):
109
+ print(video.title, video.url)
110
+
111
+ # The Language / Country value objects are equivalent (and reusable).
112
+ yt = YouTube(language=Language("de"), region=Country("DE"))
113
+
114
+ # Invalid codes are rejected early (validated with pycountry).
115
+ YouTube(region="XX") # ValueError: Unknown country code 'XX'. ...
116
+
117
+ # Or pass a ready-made Locale.
118
+ yt = YouTube(locale=Locale(language="fr", country="FR"))
119
+ print(yt.locale.language.code, yt.locale.country.code) # fr FR
120
+ ```
121
+
122
+ `Language` and `Country` are thin, self-validating value objects around a raw
123
+ ISO 639-1 / ISO 3166-1 alpha-2 code — there is no hard-coded list of languages
124
+ or countries, so any valid code works. Codes are validated with
125
+ [`pycountry`](https://pypi.org/project/pycountry/): an unknown language or
126
+ country code raises a `ValueError` instead of silently producing a broken
127
+ request. The chosen locale is sent both in the request context (`hl` / `gl`)
128
+ and as the `Accept-Language` HTTP header.
129
+
130
+ ### Pagination
131
+
132
+ Pagination is transparent — iterating over the result object automatically
133
+ loads the next page:
134
+
135
+ ```python
136
+ results = yt.search("python")
137
+
138
+ for item in results: # loads pages on demand
139
+ print(item.title)
140
+ ```
141
+
142
+ You can also page manually:
143
+
144
+ ```python
145
+ results = yt.search("python")
146
+ print(len(results.fetch_next_page())) # explicitly load one more page
147
+ print(results.has_more) # is there another page?
148
+ ```
149
+
150
+ Use `max_results` to cap how many items you consume.
151
+
152
+ ## Use cases
153
+
154
+ `ytscraper` is a great fit when you want to:
155
+
156
+ - **Scrape YouTube search results** for a keyword or topic.
157
+ - **Extract YouTube video data** (title, channel, views, duration, thumbnails).
158
+ - **Collect YouTube channel and playlist listings** at scale.
159
+ - **Build a YouTube dataset** for research, analytics or machine learning.
160
+ - **Monitor YouTube** content for a niche without hitting API quotas.
161
+
162
+ ## Command line
163
+
164
+ ```bash
165
+ # Search
166
+ python -m ytscraper search "python tutorial" --filter videos --max 10
167
+
168
+ # Localised search (Ukrainian interface, Ukrainian region)
169
+ python -m ytscraper --language uk --region UA search "музика" --max 10
170
+
171
+ # Video details
172
+ python -m ytscraper video https://www.youtube.com/watch?v=dQw4w9WgXcQ
173
+ ```
174
+
175
+ After installing, a `ytscraper` console script is also available:
176
+
177
+ ```bash
178
+ ytscraper search "python" --filter channels --max 5
179
+ ```
180
+
181
+ ## License
182
+
183
+ [MIT](LICENSE)
@@ -0,0 +1,66 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "ytscrape"
7
+ version = "0.1.0"
8
+ description = "YouTube scraper for Python — search videos, channels and playlists and fetch video metadata via the InnerTube API, no API key required."
9
+ readme = "README.md"
10
+ license = { file = "LICENSE" }
11
+ requires-python = ">=3.10"
12
+ keywords = [
13
+ "youtube",
14
+ "youtube-scraper",
15
+ "scraper",
16
+ "crawler",
17
+ "innertube",
18
+ "youtube-api",
19
+ "youtube-data",
20
+ "video",
21
+ "scraping",
22
+ "search",
23
+ "free",
24
+ "no-api-key",
25
+ ]
26
+ authors = [{ name = "hural" }]
27
+ classifiers = [
28
+ "Development Status :: 4 - Beta",
29
+ "Intended Audience :: Developers",
30
+ "License :: OSI Approved :: MIT License",
31
+ "Operating System :: OS Independent",
32
+ "Programming Language :: Python :: 3",
33
+ "Programming Language :: Python :: 3 :: Only",
34
+ "Programming Language :: Python :: 3.10",
35
+ "Programming Language :: Python :: 3.11",
36
+ "Programming Language :: Python :: 3.12",
37
+ "Programming Language :: Python :: 3.13",
38
+ "Programming Language :: Python :: 3.14",
39
+ "Topic :: Internet :: WWW/HTTP",
40
+ "Topic :: Software Development :: Libraries :: Python Modules",
41
+ "Typing :: Typed",
42
+ ]
43
+ dependencies = [
44
+ "requests>=2.28",
45
+ "pycountry>=22.3.5",
46
+ "build>=1.5.0",
47
+ "twine>=7.0.0",
48
+ ]
49
+
50
+ [project.urls]
51
+ Homepage = "https://github.com/hural/ytscraper"
52
+ Repository = "https://github.com/hural/ytscraper"
53
+ Issues = "https://github.com/hural/ytscraper/issues"
54
+
55
+ [project.scripts]
56
+ ytscraper = "ytscraper.__main__:main"
57
+
58
+ [tool.hatch.build.targets.wheel]
59
+ packages = ["src/ytscraper"]
60
+
61
+ [tool.hatch.build.targets.sdist]
62
+ include = [
63
+ "src/ytscraper",
64
+ "README.md",
65
+ "LICENSE",
66
+ ]
@@ -0,0 +1,54 @@
1
+ """ytscraper -- a small, object-oriented YouTube scraper.
2
+
3
+ The package exposes a single high level facade, :class:`YouTube`, together with
4
+ the data models and the :class:`SearchFilter` enum::
5
+
6
+ from ytscraper import YouTube, SearchFilter
7
+
8
+ with YouTube() as yt:
9
+ for video in yt.search("python", filter=SearchFilter.VIDEOS,
10
+ max_results=20):
11
+ print(video.title, video.url)
12
+
13
+ details = yt.video("dQw4w9WgXcQ")
14
+ print(details.title, details.views)
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from .client import InnerTubeClient
20
+ from .context import ContextExtractor, InnerTubeContext
21
+ from .exceptions import (
22
+ ContextExtractionError,
23
+ ParseError,
24
+ RequestError,
25
+ YtScraperError,
26
+ )
27
+ from .filters import SearchFilter
28
+ from .locale import Country, Language, Locale
29
+ from .models import Channel, Playlist, Video, VideoDetails
30
+ from .results import SearchResults
31
+ from .youtube import YouTube
32
+
33
+ __version__ = "0.1.0"
34
+
35
+ __all__ = [
36
+ "YouTube",
37
+ "SearchFilter",
38
+ "Language",
39
+ "Country",
40
+ "Locale",
41
+ "SearchResults",
42
+ "Video",
43
+ "Channel",
44
+ "Playlist",
45
+ "VideoDetails",
46
+ "InnerTubeClient",
47
+ "InnerTubeContext",
48
+ "ContextExtractor",
49
+ "YtScraperError",
50
+ "ContextExtractionError",
51
+ "RequestError",
52
+ "ParseError",
53
+ "__version__",
54
+ ]
@@ -0,0 +1,92 @@
1
+ """Minimal command line interface: ``python -m ytscraper``.
2
+
3
+ Examples:
4
+ python -m ytscraper search "python tutorial" --filter videos --max 10
5
+ python -m ytscraper video https://www.youtube.com/watch?v=dQw4w9WgXcQ
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import sys
12
+
13
+ from . import YouTube, __version__
14
+ from .exceptions import YtScraperError
15
+ from .filters import SearchFilter
16
+
17
+
18
+ def _build_parser() -> argparse.ArgumentParser:
19
+ parser = argparse.ArgumentParser(
20
+ prog="ytscraper",
21
+ description="Scrape YouTube search results and video metadata.",
22
+ )
23
+ parser.add_argument(
24
+ "--version", action="version", version=f"ytscraper {__version__}"
25
+ )
26
+ parser.add_argument(
27
+ "--language",
28
+ default="en",
29
+ metavar="HL",
30
+ help="Interface language (hl), e.g. en, uk, de.",
31
+ )
32
+ parser.add_argument(
33
+ "--region",
34
+ default="US",
35
+ metavar="GL",
36
+ help="Content region / country (gl), e.g. US, UA, DE.",
37
+ )
38
+ sub = parser.add_subparsers(dest="command", required=True)
39
+
40
+ search = sub.add_parser("search", help="Search YouTube.")
41
+ search.add_argument("query", help="Search query.")
42
+ search.add_argument(
43
+ "--filter",
44
+ choices=[f.value for f in SearchFilter],
45
+ default=SearchFilter.ALL.value,
46
+ help="Type of results to return.",
47
+ )
48
+ search.add_argument(
49
+ "--max",
50
+ type=int,
51
+ default=10,
52
+ dest="max_results",
53
+ help="Maximum number of results to print.",
54
+ )
55
+
56
+ video = sub.add_parser("video", help="Fetch details for a single video.")
57
+ video.add_argument("video", help="Video id or URL.")
58
+
59
+ return parser
60
+
61
+
62
+ def main(argv: list[str] | None = None) -> int:
63
+ """Entry point for the console script and ``python -m ytscraper``."""
64
+ args = _build_parser().parse_args(argv)
65
+
66
+ try:
67
+ with YouTube(language=args.language, region=args.region) as yt:
68
+ if args.command == "search":
69
+ results = yt.search(
70
+ args.query,
71
+ filter=args.filter,
72
+ max_results=args.max_results,
73
+ )
74
+ for item in results:
75
+ title = getattr(item, "title", None)
76
+ print(f"{title}\t{item.url}")
77
+ elif args.command == "video":
78
+ details = yt.video(args.video)
79
+ print(f"Title: {details.title}")
80
+ print(f"Channel: {details.channel}")
81
+ print(f"Views: {details.views}")
82
+ print(f"Length: {details.length_seconds}s")
83
+ print(f"URL: {details.url}")
84
+ except YtScraperError as exc:
85
+ print(f"error: {exc}", file=sys.stderr)
86
+ return 1
87
+
88
+ return 0
89
+
90
+
91
+ if __name__ == "__main__":
92
+ raise SystemExit(main())