Voltar ao blogue
Guias
Raluca Penciuc20 de fevereiro de 202312 min de leitura

Como extrair dados do YouTube como um profissional: um guia completo

Como extrair dados do YouTube como um profissional: um guia completo

Pré-requisitos

Antes de mais nada, terá de se certificar de que tem o Node.js instalado no seu computador. Se ainda não o tiver, aceda ao site oficial do Node.js e siga as instruções específicas para o seu sistema operativo. É importante referir que deve descarregar a versão de Suporte a Longo Prazo (LTS) para garantir que dispõe de uma versão estável e com suporte.

Em seguida, terá de instalar o Node.js Package Manager (NPM). Este deverá vir incluído automaticamente na instalação do Node.js, mas é sempre bom verificar.

No que diz respeito ao seu ambiente de programação, sinta-se à vontade para usar o IDE que preferir. Neste tutorial, vou usar o Visual Studio Code porque é flexível e fácil de usar, mas qualquer IDE serve. Basta criar uma nova pasta para o seu projeto e abrir um terminal. Execute o seguinte comando para configurar um novo projeto Node.js:

npm init -y

Isto irá criar um ficheiro package.json predefinido para o seu projeto. Pode modificar este ficheiro a qualquer momento, de acordo com as suas necessidades.

Agora é hora de instalar o TypeScript e as definições de tipos para o Node.js. O TypeScript é uma escolha popular entre a comunidade JavaScript devido à sua tipagem estática opcional, que ajuda a evitar erros de tipo no seu código. Para o instalar, execute o seguinte comando:

npm install typescript @types/node --save-dev

Para verificar se a instalação foi bem-sucedida, pode executar o seguinte comando:

npx tsc --versão

Por fim, terá de criar um ficheiro de configuração tsconfig.json na raiz do diretório do seu projeto. Este ficheiro define as opções do compilador para o seu projeto. Se quiser saber mais sobre este ficheiro e as suas propriedades, consulte a documentação oficial do TypeScript.

Em alternativa, pode copiar e colar o código seguinte no seu ficheiro tsconfig.json:

{

   "compilerOptions": {

       "module": "commonjs",

       "esModuleInterop": true,

       "target": "es2017",

       "moduleResolution": "node",

       "sourceMap": true,

       "outDir": "dist"

   },

   "lib": ["es2015"]

}

Para o processo de extração de dados, vou utilizar o Puppeteer, uma biblioteca de navegador sem interface gráfica para Node.js que permite controlar um navegador da Web e interagir com sites de forma programática. Para instalar o Puppeteer, execute o seguinte comando:

npm install puppeteer

Extrair os dados

Para este guia, vou extrair dados de um canal do YouTube com tutoriais relacionados com DevOps: https://www.youtube.com/@TechWorldwithNana/videos. Os dados que me interessam, em particular, são:

  • o avatar do canal
  • o nome do canal
  • o nome do canal
  • o número de subscritores do canal
  • os títulos de todos os vídeos
  • o número de visualizações de todos os vídeos
  • as miniaturas de todos os vídeos
  • o URL de todos os vídeos

Vou incluir capturas de ecrã para cada secção e vou recorrer a seletores CSS para localizar os dados no DOM. Este é o método mais simples e direto, a menos que o site em questão seja conhecido por ter uma estrutura DOM instável.

Se ainda não tem experiência com seletores CSS, consulte esta ficha de referência abrangente que o ajudará a começar num instante.

Vamos começar por criar uma pasta «src» e o ficheiro «index.ts», onde iremos escrever o código. Agora, basta abrir um navegador e aceder ao URL de destino:

import puppeteer from 'puppeteer';

async function scrapeChannelData(channelUrl: string): Promise<any> {

    // Launch Puppeteer

    const browser = await puppeteer.launch({

        headless: false,

    	  args: ['--start-maximized'],

    	  defaultViewport: null

    });

    // Create a new page and navigate to the channel URL

    const page = await browser.newPage();

    await page.goto(channelUrl);

    // Close the browser

    await browser.close();

}

scrapeChannelData("https://www.youtube.com/@TechWorldwithNana/videos");

Para efeitos de depuração visual, vou abrir o navegador no modo não headless. Se pretender alargar a sua aplicação a grande escala, recomendo que experimente o modo headless.

Para executar o script, é necessário compilá-lo primeiro e, em seguida, executar o ficheiro JavaScript gerado. Para facilitar o processo, podemos definir um script no ficheiro package.json que trate destas duas etapas por nós. Basta editar a secção «scripts» do seu ficheiro package.json da seguinte forma:

"scripts": {

    "test": "npx tsc && node dist/index.js"

},

Agora, basta executar o seguinte comando para executar o seu código:

npm run test

Desde a primeira execução, notamos um primeiro problema: a janela de consentimento de cookies em ecrã inteiro que nos impede de aceder aos dados.

Página de consentimento de cookies do YouTube com botões para aceitar ou rejeitar todos

Felizmente, está visível na janela de visualização, pelo que podemos usar as Ferramentas do Desenvolvedor para encontrar o seu identificador e clicar nele.

Caixa de diálogo de consentimento de cookies do YouTube com as ferramentas de desenvolvimento do navegador a destacar o elemento do botão «Aceitar tudo»

Também adicionamos um tempo de espera adicional para permitir que a navegação seja concluída. O código ficará assim:

await page.waitForSelector('button[aria-label="Aceitar tudo"]')

await page.click('button[aria-label="Aceitar tudo"]')

await page.waitForTimeout(10 * 1000)

Informações sobre o canal

Na captura de ecrã abaixo, podemos ver destacadas as secções que contêm os dados do canal que pretendemos extrair.

Página do canal do YouTube com as ferramentas de desenvolvimento do navegador a destacar o nome do canal e os metadados relativos ao número de inscritos

Uma boa regra prática para facilitar a localização dos elementos HTML é escolher seletores CSS únicos. Por exemplo, para extrair o avatar do canal, vou escolher o elemento HTML personalizado yt-img-shadow com o id avatar. Em seguida, extraio o atributo src do seu elemento filho img .

const channelAvatar = await page.evaluate(() => {

    const el = document.querySelector('yt-img-shadow#avatar > img');

    return el ? el.getAttribute('src') : null;

});

console.log(channelAvatar)

Para o nome do canal, temos o conteúdo de texto do elemento yt-formatted-string com o id text.

const channelName = await page.evaluate(() => {

    const el = document.querySelector('yt-formatted-string#text');

    return el ? el.textContent : null;

});

console.log(channelName)

Para obter o identificador do canal, vamos localizar o elemento yt-formatted-string com o id channel-handle e extrair o seu conteúdo de texto.

const channelHandle = await page.evaluate(() => {

    const el = document.querySelector('yt-formatted-string#channel-handle');

    return el ? el.textContent : null;

});

console.log(channelHandle)

E, por fim, para obter o número de subscritores do canal, basta aceder ao elemento yt-formatted-string com o id subscriber-count e recuperar o seu conteúdo de texto.

const subscriberCount = await page.evaluate(() => {

    const el = document.querySelector('yt-formatted-string#subscriber-count');

    return el ? el.textContent : null;

});

console.log(subscriberCount)

Ao executar o script novamente, deverá ver o seguinte resultado:

https://yt3.googleusercontent.com/kXyR8Aa32KXnZWVdkAFUYK5utM752kSJPHGtYiJ4ev6BmdFHi-dl1EFbI3TogmHBjszwc7m2=s176-c-k-c0x00ffffff-no-rj

TechWorld with Nana

@TechWorldwithNana

709K subscribers

Dados de vídeo

Passando aos dados do vídeo, também destaquei as secções relevantes do documento HTML. Aqui, devemos extrair uma lista de elementos, pelo que analisamos primeiro os contentores principais e, em seguida, percorremos cada um deles.

Grelha de vídeos de um canal do YouTube com as ferramentas de desenvolvimento do navegador a destacar o código HTML de uma miniatura de vídeo e do link do título

Seguimos a mesma abordagem da secção anterior: escolhemos alguns seletores CSS únicos para localizar os dados de que precisamos, com foco nos seus IDs. O código deve ficar mais ou menos assim:

const videos = await page.evaluate(() => {

    const videosEls = Array.from(document.querySelectorAll('div#dismissible'))

    return videosEls.map(video => {

        const titleEl = video.querySelector('yt-formatted-string#video-title');

        const viewsEl = video.querySelector('div#metadata-line > span');

        const thumbnailEl = video.querySelector('yt-image.ytd-thumbnail > img');

        const locationEl = video.querySelector('a#thumbnail');

        return {

            title: titleEl ? titleEl.textContent : null,

            views: viewsEl ? viewsEl.textContent : null,

            thumbnail: thumbnailEl ? thumbnailEl.getAttribute('src') : null,

            location: locationEl ? locationEl.getAttribute('href') : null

        }

    })

})

console.log(videos)

Quando executar o código, o resultado deverá ser uma lista de objetos JavaScript. Cada um deles deverá conter o título, o número de visualizações, a miniatura e a localização de cada elemento de vídeo na página.

No entanto, irá notar que, a partir de certo ponto, a sua lista começa a ficar assim:

{

    title: 'GitLab CI/CD Full Course released - CI/CD with Docker | K8s | Microservices!',  

    views: '114K views',

    thumbnail: null,

    location: '/watch?v=F7WMRXLUQRM'

},

{

    title: 'Kubernetes Security Best Practices you need to know | THE Guide for securing your K8s cluster!',

    views: '103K views',

    thumbnail: null,

    location: '/watch?v=oBf5lrmquYI'

},

{

    title: 'How I learn new technologies as a DevOps Engineer (without being overwhelmed)',

    views: '366K views',

    thumbnail: null,

    location: '/watch?v=Cthla7KqU04'

},

{

    title: 'Automate your Multi-Stage Continuous Delivery and Operations | with Keptn',	 

    views: '59K views',

    thumbnail: null,

    location: '/watch?v=3EEZmSwMXp8'

},

Embora os elementos de vídeo ainda tenham uma miniatura e o seletor CSS não tenha mudado, o valor extraído é nulo. Isto acontece normalmente quando um site implementa o carregamento diferido, o que significa que o resto da lista é carregado à medida que se percorre a página até ao fim.

Para resolver este problema, basta instruir o nosso script para percorrer a página do canal para baixo.

async function autoScroll(page: any, scroll_number: number): Promise<any> {

    await page.evaluate(async (scroll_number: number) => {

        await new Promise((resolve) => {

            let totalHeight = 0;

        	const timer = setInterval(() => {

                const scrollHeight = window.innerHeight * scroll_number;

                window.scrollBy(0, window.innerHeight);

                totalHeight += window.innerHeight;

                if (totalHeight > scrollHeight) {

                    clearInterval(timer);

                	  resolve(true);

                }

        	}, 1000);

    	  });

    }, scroll_number);

}

Esta função recebe como parâmetros a nossa página aberta e um número de movimentos de deslocamento. Em seguida, tenta deslocar a página uma distância igual à altura da janela tantas vezes quantas o parâmetro scroll_number indicar. Estes movimentos são realizados a cada 1 segundo.

Agora basta chamar a função antes do trecho de código que extrai a lista de vídeos.

await autoScroll(página, 10)

await página.waitForTimeout(2 * 1000)

Adicionei um tempo de espera adicional de 2 segundos para que o site tenha tempo de carregar completamente os elementos finais da lista. Ao executar o script novamente, poderá ver primeiro como ocorrem os movimentos de deslocamento e, em seguida, que todos os elementos da lista têm uma miniatura.

Evitar ser bloqueado

Embora o guia até este ponto tenha parecido simples, existem vários desafios com que os programas de extração de dados da Web costumam deparar-se. O YouTube, em particular, implementa muitas técnicas anti-bot para impedir que scripts automatizados extraiam os seus dados.

Algumas dessas técnicas são:

  • CAPTCHAs: resolver CAPTCHAs pode ser demorado e difícil para um programa de extração de dados, o que pode funcionar como um impedimento para os bots.
  • Desafios de JavaScript: podem incluir tarefas como resolver problemas matemáticos, preencher um CAPTCHA ou encontrar um elemento específico na página. Um bot que não consiga completar o desafio será detetado e poderá ser bloqueado.
  • Verificações do User-Agent: O YouTube pode verificar a string do User-Agent das solicitações recebidas para determinar se estas provêm de um navegador ou de um programa de extração de dados. Se a string do User-Agent não for reconhecida como pertencente a um navegador válido, a solicitação poderá ser bloqueada.
  • Bloqueio de IP: O YouTube pode bloquear pedidos provenientes de determinados endereços IP que se sabe estarem associados a bots ou a atividades de scraping.
  • Honeypots: O YouTube pode utilizar honeypots, que são elementos ocultos na página, visíveis apenas para os bots. Se for detetado um bot a interagir com um honeypot, este pode ser identificado e bloqueado.

Lidar com cada uma destas questões pode aumentar significativamente a complexidade e o custo do seu código de scraping. É aqui que as APIs de scraping desempenham um papel importante, uma vez que resolvem estes problemas por predefinição e estão disponíveis a um preço mais baixo.

A WebScrapingAPI é um exemplo desse tipo de serviço. Oferece funcionalidades avançadas para contornar as técnicas de deteção de bots e extrair com precisão os dados de que necessita.

Podemos experimentar rapidamente a WebScrapingAPI instalando o SDK do Node.js no nosso pequeno projeto:

npm i webscrapingapi

Agora aceda à página inicial para criar uma conta, o que lhe dará automaticamente a sua chave API e um período de teste gratuito. A chave API encontra-se no painel de controlo e irá utilizá-la para autenticar os seus pedidos à API:

Guia de início rápido do painel de controlo, apresentando três passos: chave de acesso à API, API Playground e integração na sua aplicação

E é tudo, já podes começar a programar!

import webScrapingApiClient from 'webscrapingapi';

const client = new webScrapingApiClient("YOUR_API_KEY");

async function exampleUsage(target_url: string) {

    const api_params = {

        'render_js': 1,

    	  'proxy_type': 'datacenter',

    	  'country': 'us',

    	  'timeout': 60000,

    	  'js_instructions': JSON.stringify([

            {

                action: "click",

                selector: 'button[aria-label="Accept all"]',

                timeout: 10000

         	}

    	  ]),

    	  'extract_rules': JSON.stringify({

        	avatar: {

                selector: "yt-img-shadow#avatar > img",

                output: "@src",

        	},

        	name: {

                selector: "yt-formatted-string#text",

                output: "text",

        	},

        	handle: {

                selector: "yt-formatted-string#channel-handle",

                output: "text",

        	},

        	subscribers: {

                selector: "yt-formatted-string#subscriber-count",

                output: "text",

        	},

        	videoTitles: {

                selector: "yt-formatted-string#video-title",

                output: "text",

                all: "1"

        	},

        	videoViews: {

                selector: "div#metadata-line > span",

                output: "text",

                all: "1"

        	},

        	videoThumbnails: {

                selector: "yt-image.ytd-thumbnail > img",

                output: "@src",

                all: "1"

        	},

        	videoLocations: {

                selector: "a#thumbnail",

                output: "@href",

                all: "1"

        	},

        })

    }

    const response = await client.get(target_url, api_params);

    if (response.success) {

        console.log(response.response.data);

    } else {

        console.log(response.error.response.data);

    }

}

exampleUsage("https://www.youtube.com/@TechWorldwithNana/videos");

Traduzimos o algoritmo e os seletores CSS descritos anteriormente para a API. O parâmetro«js_instructions»irá gerir a janela de cookies, ao clicar no botão «Aceitar tudo». Por fim,oparâmetro«extract_rules»irá gerir a extração de dados.

const scroll_number = 10

let scroll_index = 0

for (let i = 0; i < scroll_number; i++) {

    const js_instructions_obj = JSON.parse(api_params.js_instructions)

    js_instructions_obj.push({

        action: "scrollTo",

        selector: `ytd-rich-grid-row.ytd-rich-grid-renderer:nth-child(${scroll_index + 3})`,

        block: "end",

     	  timeout: 1000

    })

    api_params.js_instructions = JSON.stringify(js_instructions_obj)

    scroll_index += 3

}

Depois, mesmo antes de enviar o pedido, lembre-se de ajustar também a lógica de deslocamento. Isto será ligeiramente diferente, uma vez que instruímos a API para se deslocar até à terceira linha de vídeos 10 vezes.

Conclusão

Neste artigo, explorámos o fascinante campo da extração de dados da Web e aprendemos a extrair dados do YouTube utilizando o Node.js e o Puppeteer. Abordámos a configuração necessária para a extração de dados da Web, bem como o processo de extração de dados de canais do YouTube.

A extração de dados da Web pode ser uma ferramenta extremamente útil para aceder a dados de sites. No entanto, é importante ter em conta os vários desafios e aspetos a considerar que isso implica. Estes podem incluir CAPTCHAs, conteúdo dinâmico, limitação de taxa ou alterações nos sites.

Se está a pensar em extrair dados do YouTube ou de qualquer outro site, é essencial ponderar os prós e os contras e determinar se a extração de dados da Web é a melhor solução para as suas necessidades. Em alguns casos, utilizar uma API ou adquirir dados de uma fonte fiável pode ser uma opção mais adequada do que a extração de dados.

Independentemente da abordagem que escolher, é fundamental respeitar os termos de serviço e as leis de direitos de autor aplicáveis aos dados a que está a aceder. E se decidir extrair dados do YouTube, lembre-se de utilizar um programa de extração profissional para garantir que obtém dados precisos e atualizados de forma segura e eficiente.

Espero que este artigo tenha sido útil para si, agora que está a dar os primeiros passos na sua jornada para aprender sobre web scraping e como extrair dados do YouTube!

Sobre o autor
Raluca Penciuc, Desenvolvedora Full-Stack na WebScrapingAPI
Raluca PenciucDesenvolvedor Full-Stack

Raluca Penciuc é programadora Full Stack na WebScrapingAPI, onde desenvolve scrapers, aperfeiçoa estratégias de evasão e procura formas fiáveis de reduzir a deteção nos sites-alvo.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.