Hướng dẫn tải video Douyin không logo bằng n8n và Puppeteer

Viewed 5

Chia sẻ bởi Little Excel

Douyin, phiên bản gốc của TikTok tại Trung Quốc, đã trở thành một nền tảng video ngắn khổng lồ với hàng tỷ lượt xem mỗi ngày. Tuy nhiên, việc tải xuống các video từ Douyin mà không dính logo hay gặp phải các rào cản kỹ thuật là một thách thức không nhỏ. Trong khi TikTok có thể có những phương pháp tải xuống đơn giản hơn, Douyin lại áp dụng các biện pháp bảo mật chặt chẽ hơn, khiến các phương pháp truyền thống như gửi yêu cầu HTTP trực tiếp thường không hiệu quả.

Dựa trên kinh nghiệm của mình trong việc xử lý các tác vụ tự động hóa và trích xuất dữ liệu, tôi nhận thấy rằng để vượt qua những rào cản này, chúng ta cần một phương pháp tinh vi hơn, kết hợp sức mạnh của một trình duyệt tự động (Puppeteer) và khả năng tự động hóa luồng công việc của n8n. Đây không chỉ là một giải pháp kỹ thuật mà còn là một lối tư duy để giải quyết các vấn đề phức tạp trong thế giới web hiện đại.

Thách thức khi tải video Douyin: Tại sao phương pháp thông thường không hiệu quả?

Khi tôi lần đầu tiếp cận vấn đề tải video Douyin, tôi đã thử áp dụng phương pháp tương tự như khi tải video TikTok – sử dụng các yêu cầu HTTP trực tiếp. Đối với TikTok, việc kiểm tra mã nguồn trang hoặc các yêu cầu mạng thường sẽ cho phép tôi tìm thấy đường dẫn video trực tiếp được nhúng trong một đối tượng JSON nào đó, chỉ cần một vài cookie hợp lệ là có thể tải xuống dễ dàng.

Tuy nhiên, Douyin lại là một câu chuyện khác. Sau khi kiểm tra kỹ lưỡng các yêu cầu mạng trên trang Douyin, tôi nhận ra rằng đường dẫn video trực tiếp không được gửi kèm trong mã HTML ban đầu. Thay vào đó, nó được tải động (dynamically loaded) thông qua các yêu cầu JavaScript sau khi trang đã hiển thị. Điều này có nghĩa là phương pháp chỉ lấy HTML bằng HTTP Request truyền thống sẽ không thể lấy được thông tin video.

Hơn nữa, Douyin còn có các cơ chế bảo mật như yêu cầu đăng nhập hoặc xác minh captcha khi người dùng truy cập lần đầu hoặc khi phát hiện hoạt động đáng ngờ. Việc tự động giải captcha, đặc biệt là loại captcha kéo thả phức tạp, không phải là điều đơn giản và thường đòi hỏi các giải pháp bên thứ ba tốn kém hoặc chuyên biệt.

Giải pháp đột phá: Khám phá đường dẫn video trực tiếp qua Console

Với việc phương pháp HTTP request không khả thi, tôi bắt đầu tìm kiếm những "kẽ hở" khác. Một trong những công cụ mạnh mẽ nhất của nhà phát triển web chính là trình duyệt console. Tôi bắt đầu theo dõi các yêu cầu mạng (network requests), đặc biệt tập trung vào các yêu cầu dạng fetch/xhr và lọc theo từ khóa liên quan đến media.

Trong quá trình này, tôi đã phát hiện ra một số đường dẫn có vẻ là video. Sau khi kiểm tra, tôi xác nhận rằng đây chính là các đường dẫn đến video chất lượng cao, có cả âm thanh, sẵn sàng để tải xuống. Quan trọng hơn, khi tôi đưa đường dẫn này vào một nút HTTP Request trong n8n, việc tải xuống diễn ra mượt mà mà không cần bất kỳ cookie hay tham số bổ sung nào.

Tuy nhiên, việc bắt được đường dẫn này qua network request vẫn còn khá thủ công. Điều này khiến tôi suy nghĩ về một cách tiếp cận tự động hóa trình duyệt, cụ thể là Puppeteer. Puppeteer cho phép chúng ta không chỉ tương tác với trình duyệt như một người dùng thực mà còn có thể "bắt" các yêu cầu mạng và thậm chí truy cập vào các đối tượng JavaScript trên trang web.

Thật tình cờ, tôi tìm thấy một bài đăng trên một diễn đàn lập trình, nơi một thành viên đã chia sẻ một mẹo nhỏ nhưng vô cùng giá trị. Người đó chỉ ra rằng trên trang Douyin, khi một clip được phát, có một đối tượng JavaScript toàn cục được gọi là player. Khi tôi gõ player vào console của trình duyệt và nhấn Enter, một kho tàng thông tin đã hiện ra. Trong đó, tôi tìm thấy player.videoList. Đối tượng videoList này chứa một mảng các thông tin video. Bằng cách truy cập player.videoList[0].playAddr[0].src, tôi có thể lấy được đường dẫn tải xuống trực tiếp của video! Đây chính là chìa khóa quan trọng.

Kết nối Puppeteer với trình duyệt đang chạy: Vượt qua rào cản captcha và đăng nhập

Mặc dù đã tìm thấy cách lấy đường dẫn video, thách thức tiếp theo là làm sao để Puppeteer có thể truy cập trang Douyin mà không bị hỏi captcha. Nếu sử dụng Puppeteer để mở một trình duyệt mới hoàn toàn, gần như chắc chắn chúng ta sẽ gặp phải captcha kéo thả phức tạp.

Giải pháp tôi đề xuất là kết nối Puppeteer với một phiên bản trình duyệt Chrome/Chromium đang chạy và đã được xác thực (tức là đã đăng nhập, đã vượt qua captcha).

Để làm được điều này, chúng ta cần:

  1. Chạy Chrome với Remote Debugging được kích hoạt:

    • Trước tiên, bạn cần xác định đường dẫn đến thư mục profile người dùng của Chrome. Bạn có thể tìm thấy nó bằng cách gõ chrome://version vào thanh địa chỉ và tìm dòng "Profile Path".
    • Sau đó, mở terminal (hoặc Command Prompt trên Windows) và chạy Chrome với các tham số sau.
      # Trên Windows (ví dụ)
      "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="C:\Users\YourUser\AppData\Local\Google\Chrome\User Data"
      
      # Trên macOS (ví dụ)
      /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir="/Users/YourUser/Library/Application Support/Google/Chrome"
      
      # Trên Linux (ví dụ)
      google-chrome --remote-debugging-port=9222 --user-data-dir="/home/youruser/.config/google-chrome"
      
    • Khi bạn chạy lệnh này, một cửa sổ Chrome sẽ mở ra, và bạn sẽ thấy một thông báo trong terminal có dạng: "DevTools listening on ws://127.0.0.1:9222/devtools/browser/..." Đây chính là browser websocket endpoint. Hãy sao chép toàn bộ đường dẫn này.
  2. Kết nối Puppeteer trong n8n:

    • Trong n8n, bạn sẽ sử dụng node "Execute Command" hoặc một custom node có tích hợp Puppeteer. Thay vì để Puppeteer tự mở trình duyệt, chúng ta sẽ cấu hình nó để kết nối tới browser websocket endpoint đã có sẵn.
    • Trong đoạn mã Puppeteer, bạn sẽ sử dụng hàm puppeteer.connect() thay vì puppeteer.launch().

Khi Puppeteer kết nối thành công, nó sẽ sử dụng chính phiên trình duyệt Chrome mà bạn đang mở, tận dụng trạng thái đăng nhập và các cookie đã có sẵn.

Triển khai quy trình tự động với n8n và Puppeteer

Bây giờ, chúng ta sẽ đi sâu vào việc xây dựng quy trình trong n8n.

1. Cấu hình node "Execute Command" (Puppeteer):

Đoạn mã JavaScript dưới đây sẽ được đặt trong node "Execute Command".

// Khai báo URL video Douyin, có thể được truyền từ một node khác
const videoPageURL = $input.first().json.url || 'https://www.douyin.com/video/7292150929281359142';

let browser;
let page;

try {
  // Kết nối đến trình duyệt Chrome đã mở và kích hoạt remote debugging
  // Thay thế đường dẫn websocket bằng của bạn
  browser = await puppeteer.connect({
    browserWSEndpoint: 'ws://127.0.0.1:9222/devtools/browser/a4387532-690a-4229-847e-d03d36cf751e',
    defaultViewport: null
  });

  page = await browser.newPage();

  await page.goto(videoPageURL, {
    waitUntil: 'networkidle2', // Chờ cho đến khi mạng không còn hoạt động trong 500ms
    timeout: 60000 
  });

  // Chờ cho đối tượng 'player' sẵn sàng trên trang
  await page.waitForFunction('window.player && window.player.videoList && window.player.videoList.length > 0', { timeout: 30000 });

  const videoDownloadURL = await page.evaluate(() => {
    return window.player.videoList[0].playAddr[0].src;
  });

  if (!videoDownloadURL) {
    throw new Error('Không thể tìm thấy đường dẫn tải video.');
  }

  return [{ json: { videoUrl: videoDownloadURL } }];

} catch (error) {
  throw new Error(`Đã xảy ra lỗi: ${error.message}`);
} finally {
  if (page) {
    await page.close();
  }
  if (browser) {
    // Chúng ta chỉ ngắt kết nối, không đóng trình duyệt
    await browser.disconnect(); 
  }
}

Lưu ý:

  • waitUntil: 'networkidle2' là một tùy chọn tốt hơn domcontentloaded trong trường hợp này, vì nó đảm bảo các script động đã chạy xong.
  • Trong khối finally, chúng ta sử dụng browser.disconnect() thay vì browser.close() để chỉ ngắt kết nối của Puppeteer mà không đóng cửa sổ trình duyệt đang chạy.

2. Node HTTP Request để tải video:

Sau khi node Puppeteer trả về videoDownloadURL, bạn sẽ nối một node "HTTP Request" vào đó.

  • Method: GET
  • URL: {{ $json.videoUrl }}
  • Response Format: File

3. Node Response (tùy chọn, cho API):

Nếu bạn muốn biến quy trình này thành một API, bạn có thể thêm một node "Webhook" làm trigger và một node "Respond to Webhook" ở cuối để trả về URL video.

Tối ưu hóa và mở rộng: Tạo API tải video và trích xuất hàng loạt

Tạo API tiện lợi:

Việc kết nối một node Webhook ở đầu luồng làm cho quy trình trở thành một API mạnh mẽ. Người dùng có thể gửi một yêu cầu HTTP đến endpoint của webhook kèm theo URL Douyin, và n8n sẽ tự động xử lý.

Trích xuất hàng loạt video:

Đối với những người muốn tải xuống nhiều video từ một trang hồ sơ Douyin, bạn có thể viết một đoạn mã Puppeteer để cuộn trang (scroll) và thu thập tất cả các URL video trên trang, sau đó trả về một mảng các URL. Tiếp theo, sử dụng node "Split in Batches" của n8n để lặp qua từng URL và thực hiện quy trình tải xuống.

Kết luận

Việc tải video Douyin không logo, đặc biệt khi đối mặt với các rào cản như captcha, hoàn toàn có thể thực hiện được với sự kết hợp đúng đắn giữa các công cụ. Bằng cách tận dụng khả năng tự động hóa trình duyệt của Puppeteer và sự linh hoạt của n8n, chúng ta có thể xây dựng được một quy trình tự động hóa mạnh mẽ.

Quan trọng nhất, việc kết nối Puppeteer với một phiên trình duyệt đang chạy là một "mẹo" đắt giá, giúp chúng ta tránh được các vấn đề về xác minh liên tục. Hy vọng những chia sẻ chi tiết này từ kinh nghiệm của tôi sẽ giúp bạn tự tin xây dựng giải pháp tải video Douyin của riêng mình!

0 Answers