Actualmente estoy escribiendo un programa simple que toma el nombre de una canción de mi bot de discordia, encuentra el video y lo pasa a una función para convertirlo a mp3. Mi problema es que el titiritero no hace clic en el video y en su lugar solo devuelve el enlace de la página de búsqueda.
Aquí está mi código para tomar el enlace y pasarlo a través de la descarga:
async function findSongName(stringWithName){ let stringName = stringWithName.replace(commands.play, '') const link = 'https://www.youtube.com'; const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto(link) await page.type('ytd-searchbox#search.style-scope.ytd-masthead', stringName); page.keyboard.press('Enter'); await page.click('yt-interaction#extended'); console.log(page.url()) await browser.close() }Parece que desea obtener el título y la URL del resultado principal para una búsqueda de YT. Para empezar, no necesita comenzar en la página de inicio de YT. Simplemente navegue a https://www.youtube.com/results?search_query=${yourQuery} para acelerar las cosas y reducir la complejidad.
A continuación, si ve la fuente de la página de /results , hay una gran estructura de datos globales (~1 MB) llamada ytInitialData que tiene todos los resultados relevantes (junto con muchas otras cosas irrelevantes, es cierto). Teóricamente, podría tomar la página con Axios , analizar ytInitialData con Cheerio , tomar sus datos usando una matriz simple/objeto JS y omitir Puppeteer por completo.
Por supuesto, usar la API de búsqueda de YT es la forma más confiable y adecuada.
Sin embargo, dado que está utilizando Puppeteer, los datos se pueden extraer de los "#items a#video-title" de la siguiente manera:
const puppeteer = require("puppeteer"); const searchYT = async (page, searchQuery) => { const encodedQuery = encodeURIComponent(searchQuery); const url = `https://www.youtube.com/results?search_query=${encodedQuery}`; await page.goto(url); const sel = "a#video-title"; await page.waitForSelector(sel); return page.$$eval(sel, els => els.map(e => ({ title: e.textContent.trim(), href: e.href, })) ); }; let browser; (async () => { browser = await puppeteer.launch({headless: true}); const [page] = await browser.pages(); await page.setRequestInterception(true); page.on("request", req => { req.resourceType() === "image" ? req.abort() : req.continue(); }); const results = await searchYT(page, "stack overflow"); console.log(results); })() .catch(err => console.error(err)) .finally(() => browser?.close()) ;Salida (para el término de búsqueda "desbordamiento de pila"):
[ { title: 'Stack Overflow is full of idiots.', href: 'https://www.youtube.com/watch?v=I_ZK0t9-llo' }, { title: "How To Use Stack Overflow (no, ForrestKnight, it's not full of idiots)", href: 'https://www.youtube.com/watch?v=sMIslcynm0Q' }, { title: 'How to use Stack Overflow as a Beginner ?', href: 'https://www.youtube.com/watch?v=Vt-Wf7d0CFo' }, { title: 'How Microsoft Uses Stack Overflow for Teams', href: 'https://www.youtube.com/watch?v=mhh0aK6yJgA' }, // ... ] Como solo quiere el primer resultado, entonces está aquí, pero si quiere más que el lote inicial, trabaje a través de ytInitialData como se describe arriba o desplace la página hacia abajo con Titiritero.
Ahora que tiene una URL de video que desea convertir en un mp3, le recomiendo youtube-dl . Hay envoltorios de Node que puede instalar para acceder a su API fácilmente, como node-youtube-dl, que fue el primer resultado cuando busqué y nunca antes lo había usado.