const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra-plugin-stealth");
puppeteer.use(StealthPlugin());
const videoLink = "https://www.youtube.com/watch?v=6qpXszX_ixw"; // link to video page
async function scrollPage(page, scrollContainer) {
let lastHeight = await page.evaluate(`document.querySelector("${scrollContainer}").scrollHeight`);
while (true) {
await page.evaluate(`window.scrollTo(0, document.querySelector("${scrollContainer}").scrollHeight)`);
await page.waitForTimeout(2000);
let newHeight = await page.evaluate(`document.querySelector("${scrollContainer}").scrollHeight`);
if (newHeight === lastHeight) {
break;
}
lastHeight = newHeight;
}
}
async function fillDataFromPage(page, newDesign) {
const dataFromPage = await page.evaluate((newDesign) => {
const date = document
.querySelector(newDesign ? "#description-inline-expander > yt-formatted-string span:nth-child(3)" : "#info-strings yt-formatted-string")
?.textContent.trim();
const views = document
.querySelector(newDesign ? "#description-inline-expander > yt-formatted-string span:nth-child(1)" : "#info-text #count")
?.textContent.trim();
return {
title: document.querySelector(`${newDesign ? "#title >" : "#info-contents"} h1`)?.textContent.trim(),
likes: parseInt(
document
.querySelector(`${newDesign ? "#top-row" : "#menu"} #top-level-buttons-computed > ytd-toggle-button-renderer:first-child #text`)
?.getAttribute("aria-label")
.replace(",", "")
),
channel: {
name: document.querySelector(`${newDesign ? "#owner" : "ytd-video-owner-renderer"} #channel-name #text > a`)?.textContent.trim(),
link: `https://www.youtube.com${document.querySelector(`${newDesign ? "#owner" : ""} ytd-video-owner-renderer > a`)?.getAttribute("href")}`,
thumbnail: document.querySelector(`${newDesign ? "#owner" : "ytd-video-owner-renderer"} #avatar #img`)?.getAttribute("src"),
},
date,
views: views && parseInt(views.replace(",", "")),
description: newDesign
? document.querySelector("#description-inline-expander > yt-formatted-string")?.textContent.replace(date, "").replace(views, "").trim()
: document.querySelector("#meta #description")?.textContent.trim(),
duration: document.querySelector(".ytp-time-duration")?.textContent.trim(),
hashtags: Array.from(document.querySelectorAll(`${newDesign ? "#super-title" : "#info-contents .super-title"} a`)).map((el) =>
el.textContent.trim()
),
suggestedVideos: Array.from(document.querySelectorAll("ytd-compact-video-renderer")).map((el) => ({
title: el.querySelector("#video-title")?.textContent.trim(),
link: `https://www.youtube.com${el.querySelector("#thumbnail")?.getAttribute("href")}`,
channelName: el.querySelector("#channel-name #text")?.textContent.trim(),
date: el.querySelector("#metadata-line span:nth-child(2)")?.textContent.trim(),
views: el.querySelector("#metadata-line span:nth-child(1)")?.textContent.trim(),
duration: el.querySelector("#overlays #text")?.textContent.trim(),
thumbnail: el.querySelector("#img")?.getAttribute("src"),
})),
comments: Array.from(document.querySelectorAll("#contents > ytd-comment-thread-renderer")).map((el) => ({
author: el.querySelector("#author-text")?.textContent.trim(),
link: `https://www.youtube.com${el.querySelector("#author-text")?.getAttribute("href")}`,
date: el.querySelector(".published-time-text")?.textContent.trim(),
likes: el.querySelector("#vote-count-middle")?.textContent.trim(),
comment: el.querySelector("#content-text")?.textContent.trim(),
avatar: el.querySelector("#author-thumbnail #img")?.getAttribute("src"),
})),
};
}, newDesign);
return dataFromPage;
}
async function getYoutubeVideoPageResults() {
const browser = await puppeteer.launch({
headless: false,
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(60000);
await page.goto(videoLink);
await page.waitForSelector("#contents");
const isDesign1 = await page.$("#title > h1");
if (isDesign1) {
await page.click("#description-inline-expander #expand");
} else {
await page.click("#meta #more");
}
const scrollContainer = "ytd-app";
await scrollPage(page, scrollContainer);
await page.waitForTimeout(10000);
const infoFromVideoPage = await fillDataFromPage(page, isDesign1);
await browser.close();
return infoFromVideoPage;
}
getYoutubeVideoPageResults().then((result) => console.dir(result, { depth: null }));