Nếu bạn từng thử requests.get("https://www.youtube.com/...") rồi dùng BeautifulSoup để parse kết quả và tìm tiêu đề video, chắc bạn đã biết ngay cái “plot twist”: thứ bạn nhận về chỉ là một đống thẻ <div> trống rỗng, gần như không có dữ liệu hữu ích nào.
Đây là kiểu hụt hẫng rất quen thuộc mà tôi thấy ở nhiều developer khi mới bắt đầu crawl YouTube. YouTube là một ứng dụng single-page — gần như mọi thứ đều được render ở phía client bằng JavaScript. HTML mà script Python nhận về chỉ là lớp vỏ bên ngoài. Còn tiêu đề video, lượt xem và metadata thật sự lại nằm trong một khối JSON khổng lồ tên là ytInitialData, được JS chèn vào sau khi trang load xong.
Vì vậy, việc soup.find("div", class_="ytd-video-renderer") trả về None là hoàn toàn dễ hiểu, vì phần tử đó đơn giản là không hề tồn tại trong phản hồi HTTP thô. Khi tôi hiểu ra chuyện này, toàn bộ bài toán bỗng sáng tỏ — và 4 phương pháp dưới đây là kết quả của rất nhiều lần test, sửa lỗi, và đọc không biết bao nhiêu issue trên GitHub. Tôi sẽ đi qua từng cách, chỉ rõ khi nào nên dùng cách nào, và cuối bài còn có thêm một lối tắt no-code cho ai chỉ cần dữ liệu mà không muốn dựng cả dự án.
Vì sao nên crawl YouTube bằng Python ngay từ đầu?
YouTube không chỉ là một nền tảng video — mà còn là một mỏ dữ liệu khổng lồ với . Với và , có vô số thông tin công khai mà doanh nghiệp, nhà nghiên cứu và creator đều muốn phân tích bằng code.
Vấn đề là phần analytics có sẵn của YouTube chỉ hiển thị dữ liệu cho kênh của chính bạn. Nếu bạn muốn biết đối thủ đang đăng bài với tần suất ra sao, theo dõi chủ đề nào đang lên trong ngách của mình, hay phân tích cảm xúc từ bình luận trên video của người khác, thì bạn buộc phải crawl dữ liệu.
Dưới đây là những trường hợp thực tế phổ biến nhất mà tôi thường thấy:
| Trường hợp sử dụng | Ai cần | Dữ liệu liên quan |
|---|---|---|
| Phân tích đối thủ | Đội marketing, strategist nội dung | Lượt xem, tần suất đăng, tỷ lệ tương tác |
| Tìm kiếm khách hàng tiềm năng | Đội sales, outreach B2B | Thông tin liên hệ của kênh, email doanh nghiệp trong phần mô tả |
| Nghiên cứu thị trường | Product manager, nhà phân tích | Chủ đề đang trend, cảm xúc người xem qua bình luận |
| Chiến lược nội dung | YouTuber, agency | Format hiệu quả, pattern tiêu đề/tag tối ưu |
| SEO / nghiên cứu từ khóa | Chuyên gia SEO | Tiêu đề video, tags, mô tả, tín hiệu xếp hạng |
| Giám sát thương hiệu | Đội PR, brand manager | Lượt nhắc đến trong tiêu đề video, bình luận, mô tả |
| Nghiên cứu học thuật | Nhà nghiên cứu, data scientist | Bộ dữ liệu bình luận cho phân tích cảm xúc (một nghiên cứu năm 2025 đạt độ chính xác 93,1% khi fine-tune BERT trên 45.000 bình luận YouTube) |
Ví dụ, một phân tích cạnh tranh giữa DJI, GoPro và Insta360 cho thấy — một kiểu insight mà bạn sẽ không thấy nếu chỉ nhìn YouTube Studio.
Vì sao chỉ dùng requests + BeautifulSoup lại không crawl được YouTube?
Trước khi đi vào những cách thật sự chạy được, bạn cần hiểu vì sao cách tiếp cận “nghe có vẻ hợp lý” lại thất bại. Đây không phải chuyện học thuật — mà là thứ có thể giúp bạn tiết kiệm cả đống giờ debug.
Cách làm “tưởng là đúng” thường trông như thế này:
1import requests
2from bs4 import BeautifulSoup
3response = requests.get("https://www.youtube.com/@somechannel/videos")
4soup = BeautifulSoup(response.text, "html.parser")
5videos = soup.find_all("a", id="video-title-link")
6print(len(videos)) # 0 — lúc nào cũng vậy
Kết quả luôn là số 0. Như đã chỉ ra: “Trang đã được load động, điều mà requests lib không hỗ trợ.” nói thẳng hơn: “Chỉ dùng requests và BeautifulSoup thì bạn không thể chạy JavaScript.”
giải thích cơ chế rất rõ: YouTube được xây dựng như một Single Page Application (SPA). Khi bạn gửi HTTP request cơ bản, bạn chỉ nhận được phần HTML khung ban đầu — nội dung thật sự chưa được render. Dữ liệu video bị giấu trong các object JavaScript mà trình duyệt sẽ chạy rồi chèn vào DOM.
Tin tốt là: YouTube có nhúng toàn bộ dữ liệu bạn cần ngay trong HTML thô. Chỉ là nó không nằm trong các phần tử DOM — mà nằm trong hai khối JSON trong thẻ <script>:
ytInitialData— cấu trúc trang, danh sách video, số liệu tương tác, token phân trang bình luậnytInitialPlayerResponse— metadata cốt lõi của video (tiêu đề, mô tả, thời lượng, định dạng, phụ đề)
Cả hai đều có thể lấy được chỉ với một lần requests.get() — không cần trình duyệt — nếu bạn biết cách trích và parse. Đó chính là Method 1 bên dưới.
4 cách crawl YouTube bằng Python: so sánh trực diện
Trước khi đi sâu vào từng phương pháp, đây là bảng quyết định. Tôi đã test cả 4 cách và so sánh theo những tiêu chí thực sự quan trọng khi chọn công cụ cho một dự án thật.
| Tiêu chí | requests + BS4 (ytInitialData) | Selenium / Playwright | yt-dlp | YouTube Data API | No-code (Thunderbit) |
|---|---|---|---|---|---|
| Độ phức tạp khi cài đặt | Thấp | Trung bình | Thấp | Trung bình (cần API key) | Không cần |
| Xử lý render JS | Một phần (parse JSON) | Có | Có | N/A (API có cấu trúc sẵn) | Có |
| Tốc độ | Nhanh | Chậm | Nhanh | Nhanh | Nhanh (cloud) |
| Rủi ro anti-bot | Trung bình | Cao | Thấp | Không có | Được xử lý |
| Hạn mức / rate limit | Không có (nhưng dễ bị chặn IP) | Không có (nhưng dễ bị phát hiện) | Không có | 10.000 unit/ngày | Theo credit |
| Lấy bình luận | Khó | Có nhưng phức tạp | Có sẵn | Có sẵn | Tùy trang |
| Transcript | Không | Phức tạp | Có | Không | Không |
| Phù hợp nhất | Metadata nhanh | Search results, trang động | Metadata + bình luận số lượng lớn | Dữ liệu có cấu trúc ở quy mô lớn | Người không biết code, xuất dữ liệu nhanh |
Tóm tắt nhanh:

YouTube có thể trích xuất dữ liệu gì, và bằng cách nào?
Đây là bảng tham chiếu mà tôi ước mình đã có khi mới bắt đầu. Không có một phương pháp nào bao phủ được mọi trường dữ liệu — và đó chính là lý do bài viết này giới thiệu tới 4 cách.
| Trường dữ liệu | BS4 (ytInitialData) | Selenium/Playwright | yt-dlp | YouTube API | Thunderbit |
|---|---|---|---|---|---|
| Tiêu đề video | ✅ | ✅ | ✅ | ✅ | ✅ |
| Lượt xem | ✅ | ✅ | ✅ | ✅ | ✅ |
| Số lượt thích | ⚠️ Không ổn định | ✅ | ✅ | ✅ | ✅ |
| Bình luận (text) | ❌ | ⚠️ Phức tạp | ✅ | ✅ | ⚠️ |
| Transcript/phụ đề | ❌ | ⚠️ | ✅ | ❌ | ❌ |
| Tags | ✅ | ✅ | ✅ | ✅ | ⚠️ |
| URL thumbnail | ✅ | ✅ | ✅ | ✅ | ✅ |
| Số subscriber của kênh | ⚠️ | ✅ | ✅ | ✅ | ✅ |
| Ngày đăng | ✅ | ✅ | ✅ | ✅ | ✅ |
| Thời lượng video | ✅ | ✅ | ✅ | ✅ | ✅ |
| Dữ liệu riêng cho Shorts | ❌ | ⚠️ | ✅ | ⚠️ | ⚠️ |
Hãy chọn phương pháp theo những dòng dữ liệu quan trọng nhất với dự án của bạn. Nếu bạn cần bình luận và transcript, yt-dlp là lựa chọn rõ ràng nhất. Nếu bạn cần dữ liệu có cấu trúc ở quy mô vừa, API là phương án tốt nhất. Còn nếu bạn cần dữ liệu trong 2 phút, hãy đọc tiếp phần Thunderbit.

Method 1: Crawl YouTube bằng Python với requests + BeautifulSoup (parse ytInitialData)
Phương pháp này tận dụng việc YouTube nhúng toàn bộ dữ liệu trang dưới dạng JSON ngay trong HTML thô. Bạn không cần trình duyệt — chỉ cần biết chỗ tìm.
- Độ khó: Người mới
- Thời gian cần: ~15 phút
- Bạn cần: Python 3.10+,
requests,beautifulsoup4
Bước 1: Gửi GET request tới trang YouTube
Hãy gửi request với User-Agent trông giống trình duyệt thật. Header mặc định python-requests/2.x gần như bị chặn ngay lập tức — xác nhận đây là lỗi phổ biến nhất của người mới.
1import requests
2HEADERS = {
3 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
4 "AppleWebKit/537.36 (KHTML, like Gecko) "
5 "Chrome/114.0.0.0 Safari/537.36",
6 "Accept-Language": "en-US,en;q=0.9",
7 "Cookie": "CONSENT=YES+cb", # vượt qua màn hình đồng ý ở EU
8}
9url = "https://www.youtube.com/@mkbhd/videos"
10response = requests.get(url, headers=HEADERS)
11print(response.status_code) # Nên là 200
Cookie CONSENT rất quan trọng — nếu không có nó, request từ khu vực EU sẽ bị chuyển hướng sang consent.youtube.com, nơi chỉ trả về HTML không có ytInitialData.
Bước 2: Parse HTML và tìm script ytInitialData
Dùng BeautifulSoup hoặc regex để tìm thẻ <script> chứa var ytInitialData =:
1import re
2import json
3# Trích JSON ytInitialData
4match = re.search(
5 r"var ytInitialData\s*=\s*({.*?});</script>",
6 response.text,
7 re.DOTALL
8)
9if match:
10 data = json.loads(match.group(1))
11 print("Đã trích xuất ytInitialData thành công")
12else:
13 print("Không tìm thấy ytInitialData — hãy kiểm tra header/cookie")
Một lỗi rất thường gặp: dùng .*? không tham lam nhưng chỉ đặt dấu kết thúc là };. Vì JSON lồng nhau có rất nhiều dấu đóng object, đoạn bắt dữ liệu sẽ bị cắt cụt sớm. Hãy dùng };</script> làm điểm kết thúc như — vì đó là phép gán cuối cùng trong chính block script đó.
Bước 3: Điều hướng cấu trúc JSON để lấy dữ liệu video
JSON này lồng nhau rất sâu. Thay vì hard-code đường dẫn dễ gãy mỗi khi YouTube đổi cấu trúc (điều này xảy ra khá thường xuyên — ghi nhận nhiều lần thay đổi định dạng từ 2023), hãy dùng hàm tìm key theo kiểu đệ quy:
1def search_dict(partial, search_key):
2 stack = [partial]
3 while stack:
4 cur = stack.pop()
5 if isinstance(cur, dict):
6 for k, v in cur.items():
7 if k == search_key:
8 yield v
9 else:
10 stack.append(v)
11 elif isinstance(cur, list):
12 stack.extend(cur)
13# Trích thông tin video từ trang kênh
14videos = []
15for vr in search_dict(data, "videoRenderer"):
16 videos.append({
17 "video_id": vr.get("videoId"),
18 "title": vr["title"]["runs"][0]["text"],
19 "views": vr.get("viewCountText", {}).get("simpleText", "N/A"),
20 "published": vr.get("publishedTimeText", {}).get("simpleText", "N/A"),
21 })
22print(f"Tìm thấy {len(videos)} video")
23for v in videos[:5]:
24 print(f" {v['title']} — {v['views']}")
Cách đệ quy này cũng chính là hướng tiếp cận mà , yt-dlp và Scrapfly đều chọn — vì nó chịu được việc YouTube tái cấu trúc JSON liên tục.
Bước 4: Xuất dữ liệu sang CSV hoặc Excel
1import csv
2with open("youtube_videos.csv", "w", newline="", encoding="utf-8") as f:
3 writer = csv.DictWriter(f, fieldnames=["video_id", "title", "views", "published"])
4 writer.writeheader()
5 writer.writerows(videos)
6print("Đã xuất dữ liệu ra youtube_videos.csv")
Khi nào nên dùng cách này, và khi nào không?
Phù hợp nhất cho: Lấy nhanh metadata từ vài trang kênh hoặc video. Công cụ SEO nhẹ. Phân tích một lần, cần title, lượt xem và ngày đăng.
Hạn chế: Cấu trúc JSON thay đổi — các lần vỡ thường gặp gồm refactor nút like (2023: toggleButtonRenderer → segmentedLikeDislikeButtonViewModel), refactor phần mô tả (2023: description.runs[] → attributedDescription.content), và thiết kế lại tab Videos của kênh (2022–2023: gridRenderer → richGridRenderer). IP từ datacenter thường bị soft-block sau khoảng 50–200 request. Không có bình luận, không có transcript.
Method 2: Crawl YouTube bằng Python với Selenium hoặc Playwright
Khi bạn cần tương tác với trang — cuộn search results, bấm tab, mở rộng mô tả — thì tự động hóa trình duyệt là cách hợp lý nhất.
- Độ khó: Trung bình
- Thời gian cần: ~30 phút
- Bạn cần: Python 3.10+, Playwright (
pip install playwright && playwright install) hoặc Selenium + ChromeDriver
Tôi khuyên dùng Playwright thay vì Selenium cho dự án mới. cho thấy Playwright nhanh hơn khoảng so với Selenium. Playwright dùng WebSocket bền qua Chrome DevTools Protocol, còn Selenium dùng WebDriver qua HTTP, nên mỗi lệnh đều phải đi qua một lớp chuyển đổi.
Bước 1: Cài đặt Playwright
1pip install playwright
2playwright install chromium
1from playwright.sync_api import sync_playwright
2pw = sync_playwright().start()
3browser = pw.chromium.launch(headless=False) # mở cửa sổ thật giúp né một số phát hiện
4context = browser.new_context()
5# Thêm cookie consent sẵn để vượt qua màn hình EU
6context.add_cookies([{
7 "name": "SOCS",
8 "value": "CAISNQgDEitib3FfaWRlbnRpdHlmcm9udGVuZHVpc2VydmVyXzIwMjMwODI5LjA3X3AxGgJlbiACGgYIgJnPpwY",
9 "domain": ".youtube.com",
10 "path": "/",
11}])
12page = context.new_page()
Bước 2: Điều hướng tới trang YouTube và chờ nội dung tải
1page.goto("https://www.youtube.com/@mkbhd/videos")
2page.wait_for_selector("a#video-title-link", timeout=15000)
3print("Trang đã tải — đã thấy phần tử video")
Nếu bạn đang crawl search results, hãy chuyển sang https://www.youtube.com/results?search_query=your+query.
Bước 3: Xử lý cuộn vô hạn để load thêm video
YouTube dùng infinite scroll ở trang kênh và trang tìm kiếm. Đây là vòng lặp scrollHeight kinh điển, được điều chỉnh từ :
1prev_height = -1
2max_scrolls = 20 # giới hạn lại — kênh 10K video thì cuộn mãi không hết
3scroll_count = 0
4while scroll_count < max_scrolls:
5 page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
6 page.wait_for_timeout(1500) # chờ nội dung mới load
7 new_height = page.evaluate("document.body.scrollHeight")
8 if new_height == prev_height:
9 break # không còn nội dung mới
10 prev_height = new_height
11 scroll_count += 1
12print(f"Đã cuộn \{scroll_count\} lần")
Bước 4: Trích dữ liệu video từ trang đã render
1video_elements = page.query_selector_all("a#video-title-link")
2videos = []
3for el in video_elements:
4 title = el.inner_text()
5 href = el.get_attribute("href")
6 video_id = href.split("v=")[-1] if href else None
7 videos.append({"title": title, "video_id": video_id, "url": f"https://www.youtube.com\{href\}"})
8print(f"Đã trích {len(videos)} video")
Để lấy lượt xem và ngày đăng, bạn sẽ cần thêm các phần tử anh em (sibling). lưu ý rằng id="video-title-link" không phải lúc nào cũng có mặt — YouTube có nhiều biến thể trang khác nhau. Fallback đáng tin hơn là a[href*="watch"].
Bước 5: Xuất ra CSV hoặc Google Sheets
1import csv
2with open("youtube_playwright.csv", "w", newline="", encoding="utf-8") as f:
3 writer = csv.DictWriter(f, fieldnames=["title", "video_id", "url"])
4 writer.writeheader()
5 writer.writerows(videos)
6browser.close()
7pw.stop()
Khi nào nên dùng cách này, và khi nào không?
Phù hợp nhất cho: Crawl search results, tương tác với phần tử động (bấm tab, mở mô tả), mọi thứ đòi hỏi DOM đã render đầy đủ.
Hạn chế: Chậm (~1,5–3 giây mỗi video trong flow cuộn và trích xuất). Rủi ro bị anti-bot cao — Selenium mặc định sẽ đặt navigator.webdriver === true, và . Tốn tài nguyên nặng (mỗi browser instance dùng khoảng 200–500 MB RAM). Với 100 video, bạn có thể mất 3–8 phút thay vì chỉ vài giây như yt-dlp.
Method 3: Crawl YouTube bằng Python với yt-dlp
yt-dlp là “dao đa năng” cho việc crawl YouTube. Đây là bản fork cộng đồng của youtube-dl với , phát hành nightly liên tục, và hỗ trợ sẵn metadata, bình luận, transcript, và crawl hàng loạt — tất cả mà không cần trình duyệt hay API key.
- Độ khó: Từ Người mới đến Trung bình
- Thời gian cần: ~10 phút
- Bạn cần: Python 3.10+,
pip install yt-dlp
Bước 1: Cài yt-dlp
1pip install yt-dlp
Không cần browser driver, không cần API key, không cần file cấu hình.
Bước 2: Trích metadata video mà không tải video
1import yt_dlp
2opts = {
3 "quiet": True,
4 "skip_download": True, # không tải byte video — chỉ lấy metadata
5 "no_warnings": True,
6}
7with yt_dlp.YoutubeDL(opts) as ydl:
8 info = ydl.extract_info(
9 "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
10 download=False
11 )
12print(f"Tiêu đề: {info['title']}")
13print(f"Lượt xem: {info['view_count']:,}")
14print(f"Lượt thích: {info.get('like_count', 'N/A')}")
15print(f"Thời lượng: {info['duration']}s")
16print(f"Ngày đăng: {info['upload_date']}")
17print(f"Kênh: {info['channel']} ({info.get('channel_follower_count', 'N/A')} subs)")
18print(f"Tags: {info.get('tags', [])[:5]}")
Một lần gọi extract_info thường trả về khoảng 80–120 trường tùy trạng thái video: id, title, channel, channel_id, channel_follower_count, view_count, like_count, comment_count, upload_date, duration, tags, categories, description, thumbnails, is_live, availability, automatic_captions, subtitles, chapters, heatmap, và nhiều hơn nữa.
Bước 3: Trích bình luận từ một video YouTube
1opts = {
2 "quiet": True,
3 "skip_download": True,
4 "getcomments": True,
5 "extractor_args": {
6 "youtube": {
7 "max_comments": ["200", "50", "50", "10"], # tổng, cha, reply mỗi comment, tổng reply
8 "comment_sort": ["top"],
9 }
10 },
11}
12with yt_dlp.YoutubeDL(opts) as ydl:
13 info = ydl.extract_info(
14 "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
15 download=False
16 )
17comments = info.get("comments", [])
18print(f"Đã lấy {len(comments)} bình luận")
19for c in comments[:3]:
20 print(f" [{c.get('like_count', 0)} lượt thích] {c['author']}: {c['text'][:80]}...")
Việc lấy bình luận khá chậm. ghi nhận tốc độ lấy comment khoảng 30 KB/s — một video có 100.000 bình luận có thể mất hàng giờ. cũng ghi nhận có video mà URL định dạng hết hạn (~6 giờ) trước khi phân trang bình luận hoàn tất. Hãy đặt max_comments thật chặt cho video lớn.
Bước 4: Trích transcript và phụ đề
Không phải YouTube Data API hay parse BS4 nào cũng cho bạn transcript đầy đủ. Đây là lợi thế riêng của yt-dlp.
1opts = {
2 "quiet": True,
3 "skip_download": True,
4 "writesubtitles": True,
5 "writeautomaticsub": True,
6 "subtitleslangs": ["en", "en-orig"],
7 "subtitlesformat": "json3", # dễ parse bằng máy: start/dur tính bằng ms + text
8 "outtmpl": "%(id)s.%(ext)s",
9}
10with yt_dlp.YoutubeDL(opts) as ydl:
11 info = ydl.extract_info(
12 "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
13 download=False
14 )
15# Truy cập dữ liệu subtitle trực tiếp từ dict info
16auto_captions = info.get("automatic_captions", {})
17manually_subs = info.get("subtitles", {})
18print(f"Ngôn ngữ auto-caption: {list(auto_captions.keys())[:10]}")
19print(f"Ngôn ngữ subtitle thủ công: {list(manually_subs.keys())}")
Định dạng json3 rất hợp để parse máy — mỗi segment có start/dur tính bằng mili-giây cùng các text runs. Mã ngôn ngữ dùng chuẩn BCP-47 (en, en-US, zh-Hans, ja, es).
Bước 5: Crawl hàng loạt video hoặc cả kênh
1opts = {
2 "quiet": True,
3 "skip_download": True,
4 "extract_flat": "in_playlist", # nhanh — chỉ lấy video ID và title
5 "sleep_interval": 2,
6 "max_sleep_interval": 6,
7}
8with yt_dlp.YoutubeDL(opts) as ydl:
9 info = ydl.extract_info(
10 "https://www.youtube.com/@mkbhd/videos",
11 download=False
12 )
13entries = info.get("entries", [])
14print(f"Tìm thấy {len(entries)} video trên kênh")
15for e in entries[:5]:
16 print(f" {e.get('title', 'N/A')} — {e.get('id')}")
Chỉ cần đưa vào URL kênh, URL playlist, hoặc thậm chí query tìm kiếm (ytsearch10:python scraping), yt-dlp sẽ tự lo phần pagination bên trong.
Khi nào nên dùng cách này, và khi nào không?
Phù hợp nhất cho: Trích metadata số lượng lớn, bình luận, transcript, tải video, crawl toàn kênh khi bạn cần đầy đủ field.
Hạn chế: Không lý tưởng để crawl trang kết quả tìm kiếm (Selenium/Playwright phù hợp hơn). Cuộc đua anti-bot giai đoạn 2024–2026 cũng khiến yt-dlp phức tạp hơn khi chạy quy mô lớn — YouTube hiện áp dụng trên một số client. Khi chạy production, hãy cài plugin và dùng --cookies-from-browser chrome (với một tài khoản bỏ đi — đội yt-dlp cảnh báo rằng cookie từ tài khoản Google thật có thể khiến tài khoản đó bị khóa).
Method 4: Crawl YouTube bằng Python với YouTube Data API
YouTube Data API v3 chính thức là cách đáng tin cậy và có cấu trúc nhất để lấy dữ liệu YouTube. Response là JSON sạch, field được tài liệu hóa rõ ràng, và không có màn đấu trí anti-bot. Nhưng có một điểm mà hầu hết tutorial bỏ qua: hệ thống quota.
- Độ khó: Trung bình
- Thời gian cần: ~20 phút (bao gồm setup API key)
- Bạn cần: Python 3.10+, một Google Cloud project,
pip install google-api-python-client
Bước 1: Lấy API key cho YouTube Data API
- Vào
- Tạo project mới (hoặc chọn project có sẵn)
- Vào APIs & Services → Library → tìm "YouTube Data API v3" → Enable
- Vào APIs & Services → Credentials → Create Credentials → API Key
- Copy key — bạn sẽ dùng nó ở code phía dưới
Bước 2: Gọi API lần đầu tiên
1from googleapiclient.discovery import build
2API_KEY = "YOUR_API_KEY_HERE"
3youtube = build("youtube", "v3", developerKey=API_KEY)
4# Lấy chi tiết của một video cụ thể
5response = youtube.videos().list(
6 part="snippet,statistics,contentDetails",
7 id="dQw4w9WgXcQ"
8).execute()
9video = response["items"][0]
10print(f"Tiêu đề: {video['snippet']['title']}")
11print(f"Lượt xem: {video['statistics']['viewCount']}")
12print(f"Lượt thích: {video['statistics'].get('likeCount', 'ẩn')}")
13print(f"Bình luận: {video['statistics'].get('commentCount', 'đã tắt')}")
14print(f"Thời lượng: {video['contentDetails']['duration']}")
15print(f"Tags: {video['snippet'].get('tags', [])[:5]}")
Response gọn, có kiểu dữ liệu, và có tài liệu đi kèm. Không cần đào bới JSON.
Bước 3: Trích chi tiết video, thông tin kênh và bình luận
1# Tìm video
2search_response = youtube.search().list(
3 part="snippet",
4 q="python web scraping tutorial",
5 type="video",
6 maxResults=10,
7 order="viewCount"
8).execute()
9for item in search_response["items"]:
10 print(f" {item['snippet']['title']} — {item['id']['videoId']}")
11# Lấy bình luận
12comments_response = youtube.commentThreads().list(
13 part="snippet",
14 videoId="dQw4w9WgXcQ",
15 maxResults=20,
16 order="relevance"
17).execute()
18for item in comments_response["items"]:
19 comment = item["snippet"]["topLevelComment"]["snippet"]
20 print(f" [{comment['likeCount']} lượt thích] {comment['authorDisplayName']}: {comment['textDisplay'][:80]}")
Thực tế về quota của YouTube API (điều mà ít ai nói rõ)
Đây là phần phân biệt một bài hướng dẫn hữu ích với một bài chỉ để copy-paste. Mức mặc định là , reset lúc nửa đêm theo giờ Pacific Time. Đây là chi phí của từng call:
| API Endpoint | Chi phí quota mỗi lần gọi | Số kết quả tối đa mỗi lần gọi |
|---|---|---|
search.list | 100 units | 50 kết quả |
videos.list | 1 unit | 50 video ID (theo lô) |
channels.list | 1 unit | 50 channel ID |
commentThreads.list | 1 unit | 100 bình luận |
captions.list | 50 units | N/A |
Bây giờ hãy tính thử. Giả sử bạn muốn crawl 1.000 kết quả tìm kiếm:
- Số lần search: 1.000 kết quả ÷ 50 mỗi trang = 20 call × 100 units = 2.000 units (20% ngân sách ngày — bay sạch)
- Chi tiết video cho 1.000 video đó: 1.000 ID ÷ 50 mỗi lô = 20 call × 1 unit = 20 units (rất rẻ —
videos.listtheo lô là điểm cứu cánh) - Bình luận cho 1.000 video (giả sử mỗi video 1 trang): 1.000 call × 1 unit = 1.000 units
Tổng cộng: khoảng 3.020 units cho một job crawl vừa phải. Nhưng nếu các video đó có thread bình luận sâu (50+ trang mỗi video), bạn sẽ tiêu hết 7.000 units còn lại rất nhanh. Một video có 50.000 bình luận = khoảng 500 trang = 500 units. Crawl 20 video kiểu đó là hết quota trong ngày.
Quy trình xin tăng quota : URL privacy policy, URL ToS, video demo ứng dụng, và giải thích phép tính quota. Phản hồi phổ biến theo cộng đồng là Google thường trả lời trong 3–5 ngày làm việc, nhưng phê duyệt đầy đủ có thể mất vài tuần đến vài tháng, và nhiều đơn bị từ chối — đặc biệt là các case “tôi muốn nhiều dữ liệu hơn để phân tích”.
Khi nên dùng API: Quy mô nhỏ đến trung bình, khi bạn cần dữ liệu có cấu trúc và đáng tin cậy, khi bình luận và thống kê kênh quan trọng, và khi bạn chấp nhận giới hạn quota.
Khi crawl sẽ hợp lý hơn: Dự án quy mô lớn (>10K video/ngày), cần các field API không cung cấp (transcript đầy đủ — captions.download cần OAuth + quyền của chủ video), hoặc khi bạn cần nhiều hơn 500 kết quả tìm kiếm mỗi truy vấn (giới hạn cứng của API bất kể totalResults nói gì).
Cách làm nhanh không cần code: crawl YouTube với Thunderbit
Nếu bạn cần Python cho một data pipeline, hãy dùng 4 phương pháp phía trên. Nhưng nếu bạn chỉ cần dữ liệu YouTube trong 2 phút — có thể bạn là marketer đang lấy số liệu đối thủ, hoặc một developer chỉ muốn kéo dữ liệu nhanh mà không muốn dựng môi trường dự án — thì có một đường ngắn hơn.
là một Chrome extension AI web scraper mà chúng tôi xây dựng cho những trường hợp viết code là quá mức cần thiết. Nó hoạt động trực tiếp trên trang YouTube trong trình duyệt của bạn.
Cách crawl YouTube bằng Thunderbit trong 3 bước
Bước 1: Cài và mở trang kênh YouTube, trang kết quả tìm kiếm, hoặc trang video.
Bước 2: Nhấn "AI Suggest Fields" trong sidebar của Thunderbit. AI sẽ đọc trang và đề xuất các cột như tiêu đề video, lượt xem, ngày đăng, thời lượng, tên kênh và URL thumbnail. Bạn có thể thêm, xóa hoặc đổi tên cột tùy ý.
Bước 3: Nhấn "Scrape" và xuất ra Google Sheets, Excel, CSV, Airtable hoặc Notion. Dữ liệu sẽ được đưa vào một bảng sạch, sẵn sàng sử dụng.
Ai nên dùng cách này?
- Marketer cần dữ liệu kênh đối thủ nhưng không biết code
- Developer muốn kéo dữ liệu nhanh mà không phải tạo virtual environment và cài dependencies
- Bất kỳ ai gặp tường anti-bot — Thunderbit scrape ngay trong phiên trình duyệt đã đăng nhập của chính bạn, kế thừa cookie và PO tokens của bạn. Điều này giúp vượt qua nhiều vấn đề chặn mà các scraper chạy phía server thường gặp
- Thunderbit còn có thể dùng để đi vào từng trang video và làm giàu bảng dữ liệu bằng thêm chi tiết như số like, mô tả, tags
Nếu muốn tìm hiểu sâu hơn cách Thunderbit xử lý YouTube, hãy xem và .
Mẹo crawl YouTube bằng Python mà không bị chặn
Những mẹo này áp dụng cho cả 4 phương pháp Python. Các cơ chế anti-bot của YouTube được , với ba tín hiệu chính: phân tích hành vi IP, yêu cầu chạy JS, và cấu trúc HTML thay đổi liên tục.
Áp dụng cho tất cả phương pháp:
- Rotate cả User-Agent lẫn toàn bộ bộ header —
Accept,Accept-Language,Sec-CH-UAphải khớp với UA đã khai báo. có danh sách cập nhật. - Thêm độ trễ ngẫu nhiên 2–8 giây giữa các request. Khoảng thời gian cố định là một tín hiệu phát hiện.
- Dùng residential proxy cho bất kỳ thứ gì vượt quá vài trang. IP datacenter (AWS, GCP, Hetzner) gần như .
- Rotate session và IP cùng lúc — YouTube gắn session với IP, và cùng một cookie session xuất hiện trên hai IP khác nhau là tín hiệu đỏ.
Với requests + BS4: Đặt cookie CONSENT=YES+cb. Không có nó, request từ EU sẽ bị chuyển hướng sang trang consent không có dữ liệu.
Với Selenium/Playwright: Chạy chế độ headful với xvfb trên Linux server thay vì --headless=new — Chrome headless vẫn để lộ đủ fingerprint cho các bộ phát hiện tinh vi. Cân nhắc , công cụ này áp dụng khoảng 17 biện pháp né phát hiện.
Với yt-dlp: Dùng các option sleep_interval và max_sleep_interval. Cài plugin để sinh PO Token. Dùng --cookies-from-browser chrome với một tài khoản bỏ đi.
Với API: Theo dõi quota trong và batch request thật hiệu quả. Một call videos.list với 50 ID phân tách bằng dấu phẩy chỉ tốn 1 unit — hãy tận dụng.
Với Thunderbit: Các biện pháp anti-bot được xử lý tự động vì việc scrape diễn ra ngay trong session trình duyệt của bạn. Về cơ bản, bạn chỉ đang tự động hóa những gì mình vốn làm thủ công.
Crawl YouTube bằng Python có hợp pháp không?
Điều này còn tùy bạn crawl gì, crawl như thế nào, và bạn làm gì với dữ liệu đó.
Bối cảnh pháp lý đã thay đổi vào năm 2024 với Meta Platforms v. Bright Data (N.D. Cal., tháng 1/2024), nơi . Việc crawl dữ liệu công khai sau phán quyết này trở nên “ít rủi ro hơn đáng kể.” Ở chiều ngược lại, hiQ v. LinkedIn kết thúc bằng một bản án vì vi phạm ToS, CFAA (tạo tài khoản giả), và trespass to chattels — kèm theo lệnh cấm vĩnh viễn.
Điều khoản sử dụng của YouTube nói rất rõ: “Bạn không được phép truy cập Dịch vụ bằng bất kỳ phương tiện tự động nào (như robot, botnet hoặc scraper)” trừ khi có cho phép bằng văn bản trước hoặc được pháp luật cho phép. YouTube Data API là cách truy cập dữ liệu được chính thức chấp thuận.
Một vài nguyên tắc thực tế:
- Crawl dữ liệu công khai cho mục đích nghiên cứu cá nhân hoặc phân tích phi thương mại thường rủi ro thấp hơn
- API là con đường an toàn nhất — vì đã được cấp phép rõ ràng
- Tránh crawl nội dung riêng tư/đòi đăng nhập, tải video có bản quyền để phân phối lại, hoặc vi phạm GDPR với dữ liệu cá nhân trong bình luận
- Bình luận YouTube chứa dữ liệu cá nhân theo GDPR Art. 4(1) — hãy xử lý thông tin của chủ thể dữ liệu EU thật cẩn thận
- Hãy hỏi ý kiến cố vấn pháp lý nếu dự án crawl có mục đích thương mại
Đây không phải là tư vấn pháp lý. Bối cảnh này đang thay đổi rất nhanh — làn sóng mới của các vụ kiện đã crawl YouTube để lấy dữ liệu huấn luyện đang tiếp tục định hình cuộc chơi trong giai đoạn 2025–2026.
Nên chọn phương pháp nào để crawl YouTube bằng Python?
Hướng dẫn quyết định nhanh:
- Cần metadata nhanh từ vài trang? → Method 1 (requests + BS4). Nhanh, nhẹ, không cần gì ngoài
requestsvàbeautifulsoup4. - Cần crawl search results hoặc tương tác với trang động? → Method 2 (Selenium/Playwright). Render đầy đủ bằng browser, hỗ trợ infinite scroll, nhưng chậm và dễ bị phát hiện.
- Cần metadata số lượng lớn, bình luận hoặc transcript? → Method 3 (yt-dlp). Công cụ đơn lẻ mạnh nhất — là có lý do.
- Cần dữ liệu có cấu trúc, đáng tin cậy ở quy mô vừa? → Method 4 (YouTube Data API). Chính thức, sạch sẽ, nhưng bị giới hạn quota .
- Cần dữ liệu trong 2 phút mà không viết code? → . Chạy trên browser, dùng AI, xuất ra Google Sheets chỉ bằng vài cú click.
Không có một phương pháp nào hợp cho mọi trường hợp. Hãy lưu lại bảng so sánh và bảng field dữ liệu có thể trích ở trên — chúng sẽ giúp bạn tiết kiệm rất nhiều thời gian cho dự án tiếp theo. Và nếu bạn muốn khám phá thêm , trên blog Thunderbit có rất nhiều hướng dẫn, từ đến .
Câu hỏi thường gặp
Tôi có thể crawl YouTube mà không cần API key không?
Có. Method 1 (requests + BS4), Method 2 (Selenium/Playwright), và Method 3 (yt-dlp) đều không cần API key. Chỉ Method 4 (YouTube Data API) là cần. Thunderbit cũng chạy mà không cần API key — nó crawl trực tiếp ngay trong trình duyệt của bạn.
Cách nhanh nhất để crawl YouTube bằng Python là gì?
Với Python, yt-dlp và requests + BS4 là nhanh nhất — cả hai đều tránh overhead của browser và có thể lấy metadata trong vài giây mỗi video. yt-dlp đặc biệt nhanh cho tác vụ batch vì nó tự xử lý pagination. Nếu không dùng Python, Thunderbit là lựa chọn nhanh nhất nói chung vì gần như không mất thời gian cài đặt.
Làm sao để crawl bình luận YouTube bằng Python?
yt-dlp có sẵn tính năng lấy bình luận qua option getcomments — đây là cách đơn giản nhất. YouTube Data API cũng hỗ trợ bình luận qua commentThreads.list (1 quota unit mỗi call, tối đa 100 bình luận mỗi trang). Selenium/Playwright cũng làm được bằng cách cuộn và trích phần tử bình luận đã render, nhưng chậm và dễ gãy.
Tôi có thể crawl YouTube Shorts bằng Python không?
Có. yt-dlp xử lý metadata Shorts khá tốt — nó xem Shorts như video bình thường nhưng có thêm một số field riêng. YouTube Data API hỗ trợ một phần (cách tính lượt xem Shorts đã — lượt xem giờ tính mọi lần phát hoặc phát lại). BS4 và Selenium/Playwright hỗ trợ Shorts hạn chế hơn vì khu vực Shorts dùng cấu trúc DOM khác.
Mỗi ngày tôi có thể crawl bao nhiêu video YouTube?
Với YouTube Data API, bạn bị giới hạn khoảng 10.000 quota units/ngày. Nếu dùng videos.list theo lô (50 ID mỗi call, tốn 1 unit), bạn có thể tra tới 500.000 lượt lookup thống kê video mỗi ngày — nhưng search.list tốn 100 units mỗi call nên sẽ ngốn quota rất nhanh. Với các phương pháp crawl (BS4, Selenium, yt-dlp), giới hạn thực tế hơn là cố định: IP block thường xuất hiện sau vài trăm đến vài nghìn request mỗi IP mỗi ngày, tùy proxy và pattern request. Thunderbit dùng hệ thống credit gắn với của bạn.
Tìm hiểu thêm