Voltar ao blogue
Guias
Raluca PenciucLast updated on Mar 31, 20266 min read

Descubra o poder dos dados: como extrair informações valiosas do Booking.com

Descubra o poder dos dados: como extrair informações valiosas do Booking.com

Como agência de viagens online líder, a Booking.com é um verdadeiro tesouro de dados valiosos sobre hotéis e alojamentos para férias em todo o mundo. Desde comentários de hóspedes a preços e disponibilidade, a informação disponível na Booking pode ser extremamente útil para uma vasta gama de finalidades.

Quer seja um empresário a avaliar a concorrência ou um cientista de dados a analisar tendências no setor hoteleiro, o web scraping é uma ferramenta poderosa que o pode ajudar a recolher os dados de que necessita das páginas da Booking.

No final deste tutorial, terá uma compreensão sólida de como fazer web scraping na Booking.com utilizando a popular biblioteca de automação Node.js, Puppeteer. Iremos concentrar-nos na extração de detalhes de anúncios da Madeira, Portugal, mas as técnicas e conceitos abordados neste tutorial podem ser aplicados a outros sites e pontos de dados também.

Pré-requisitos

Se ainda não tiver o seu ambiente Node.js configurado, basta ir ao site oficial para descarregar a versão mais recente para o seu sistema operativo. Em seguida, crie um novo diretório e execute o seguinte comando para inicializar o seu projeto:

npm init -y

Iremos utilizar TypeScript para escrever o código. Este superset do JavaScript adiciona tipagem estática opcional e outras funcionalidades. É útil para projetos de maior dimensão e pode facilitar a deteção precoce de erros. É necessário adicioná-lo às dependências de desenvolvimento do projeto e inicializar o seu ficheiro de configuração:

npm install typescript -save-dev npx tsc -init

Certifique-se apenas de que, no ficheiro tsconfig.json recém-gerado, a propriedade «outDir» está definida como «dist», uma vez que pretendemos separar o código TypeScript do código compilado.

Por último, o comando seguinte irá adicionar o Puppeteer às dependências do nosso projeto:

npm install puppeteer

O Puppeteer é uma biblioteca Node.js que fornece uma API de alto nível para controlar um navegador Chrome sem interface gráfica, que pode ser usado para web scraping e tarefas de automação

Localização dos dados

Para este tutorial, optámos por extrair as propriedades disponíveis nas Ilhas da Madeira, Portugal: https://www.booking.com/searchresults.en-us.html?ss=Madeira+Islands&checkin=2023-01-13&checkout=2023-01-15. É importante adicionar as datas de check-in e check-out ao URL para que todas as informações sobre as propriedades fiquem disponíveis.

Este guia aborda a extração dos seguintes dados das propriedades:

  • o nome
  • o URL
  • o endereço físico
  • o preço
  • a classificação e o número de avaliações
  • a miniatura

Pode vê-los destacados na captura de ecrã abaixo:

Ao abrir as Ferramentas do Desenvolvedor em cada um destes elementos, poderá observar os seletores CSS que iremos utilizar para localizar os elementos HTML. Se ainda não estiver familiarizado com o funcionamento dos seletores CSS, consulte este guia para principiantes.

Análise dos dados

Uma vez que todos os anúncios têm a mesma estrutura e dados, podemos extrair toda a informação da lista completa de propriedades no nosso algoritmo. Após executar o script, podemos percorrer todos os resultados e compilá-los numa única lista.

Após uma primeira olhadela no documento HTML, deve ter reparado que o site da Booking é bastante complexo e que os nomes das classes são, na sua maioria, gerados aleatoriamente.

Felizmente para nós, o site não depende exclusivamente de nomes de classes, e podemos usar o valor de um atributo específico como critério de extração. Na captura de ecrã acima, destacámos como a miniatura, o nome e o URL de um imóvel são acessíveis.

import puppeteer from 'puppeteer';

async function scrapeBookingData(booking_url: string): Promise<void> {

    // Launch Puppeteer

    const browser = await puppeteer.launch({

        headless: false,

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

    	  defaultViewport: null

    })

    const page = await browser.newPage()

    // Navigate to the channel URL

    await page.goto(booking_url)

    // Extract listings name

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

        const names = document.querySelectorAll('div[data-testid="title"]')

    	  const names_array = Array.from(names)

    	  return names ? names_array.map(n => n.textContent) : []

    })

    console.log(listings_name)

    // Extract listings location

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

        const locations = document.querySelectorAll('a[data-testid="title-link"]')

    	  const locations_array = Array.from(locations)

    	  return locations ? locations_array.map(l => l.getAttribute('href')) : []

    })

    console.log(listings_location)

    // Extract listings thumbnail

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

        const thumbnails = document.querySelectorAll('[data-testid="image"]')

    	  const thumbnails_array = Array.from(thumbnails)

    	  return thumbnails ? thumbnails_array.map(t => t.getAttribute('src')) : []

    })

    console.log(listings_thumbnail)

    await browser.close()

}

scrapeBookingData("https://www.booking.com/searchresults.en-us.html?ss=Madeira+Islands&checkin=2023-01-13&checkout=2023-01-15")

Utilizámos o Puppeteer para abrir uma instância do navegador, criar uma nova página, navegar até ao nosso URL de destino, extrair os dados mencionados e, em seguida, fechar o navegador. Para fins de depuração visual, estou a utilizar o modo não headless do navegador.

Conforme explicado acima, os dados eram facilmente acessíveis graças ao atributo “data-testid”, que atribuiu um valor único ao elemento HTML. Execute o seguinte comando para executar o script:

npx tsc && node dist/index.js

O seu terminal deverá apresentar 3 resultados de lista do mesmo tamanho, representando os nomes, as URLs e as miniaturas de todas as propriedades na página atual.

Para a secção seguinte do documento HTML, destacámos o endereço, a classificação e o número de avaliações de uma propriedade.

// Extract listings address

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

    const addresses = document.querySelectorAll('[data-testid="address"]')

    const addresses_array = Array.from(addresses)

    return addresses ? addresses_array.map(a => a.textContent) : []

})

console.log(listings_address)

// Extract listings rating and review count

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

    const ratings = document.querySelectorAll('[data-testid="review-score"]')

    const ratings_array = Array.from(ratings)

    return ratings ? ratings_array.map(r => r.textContent) : []

})

console.log(listings_rating)

Tal como antes, utilizámos o atributo “data-testid”. Ao executar o script novamente, deverão aparecer mais 2 listas, tal como as anteriores.

E, finalmente, na última secção, extraímos o preço do imóvel. O código não será diferente do que fizemos anteriormente:

// Extract listings price

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

    const prices = document.querySelectorAll('[data-testid="price-and-discounted-price"]')

    const prices_array = Array.from(prices)

    return prices ? prices_array.map(p => p.textContent) : []

})

console.log(listings_price)

Para facilitar o processamento posterior dos dados extraídos, vamos combinar as listas resultantes numa única lista.

// Group the lists

const listings = []

for (let i = 0; i < listings_name.length; i++) {

    listings.push({

        name: listings_name[i],

        url: listings_location[i],

        address: listings_address[i],

        price: listings_price[i],

        ratings: listings_rating[i],

        thumbnails: listings_thumbnail[i]

    })

}

console.log(listings)

O resultado final deverá agora ter este aspeto:

[

  {

    name: 'Pestana Churchill Bay',

    url: 'https://www.booking.com/hotel/pt/pestana-churchill-bay.html?aid=304142&label=gen173nr-1FCAQoggJCFnNlYXJjaF9tYWRlaXJhIGlzbGFuZHNIMVgEaMABiAEBmAExuAEXyAEM2AEB6AEB-AEDiAIBqAIDuAK9luydBsACAdICJGViMWY2MmRjLWJhZmEtNGZhZC04MDAyLWQ4MmU3YjU5MTMwZtgCBeACAQ&ucfs=1&arphpl=1&checkin=2023-01-13&checkout=2023-01-15&group_adults=2&req_adults=2&no_rooms=1&group_children=0&req_children=0&hpos=1&hapos=1&sr_order=popularity&srpvid=42cc81de452009eb&srepoch=1673202494&all_sr_blocks=477957801_262227867_0_1_0&highlighted_blocks=477957801_262227867_0_1_0&matching_block_id=477957801_262227867_0_1_0&sr_pri_blocks=477957801_262227867_0_1_0__18480&tpi_r=2&from_sustainable_property_sr=1&from=searchresults#hotelTmpl',

    address: 'Câmara de Lobos',

    price: '911 lei',

    ratings: '9.0Wonderful 727 reviews',

    thumbnails: 'https://cf.bstatic.com/xdata/images/hotel/square200/202313893.webp?k=824dc3908c4bd3e80790ce011f763f10fd4064dcb5708607f020f2e7c92d130e&o=&s=1'

  },

  {

    name: 'Hotel Madeira',

    url: 'https://www.booking.com/hotel/pt/madeira-funchal.html?aid=304142&label=gen173nr-1FCAQoggJCFnNlYXJjaF9tYWRlaXJhIGlzbGFuZHNIMVgEaMABiAEBmAExuAEXyAEM2AEB6AEB-AEDiAIBqAIDuAK9luydBsACAdICJGViMWY2MmRjLWJhZmEtNGZhZC04MDAyLWQ4MmU3YjU5MTMwZtgCBeACAQ&ucfs=1&arphpl=1&checkin=2023-01-13&checkout=2023-01-15&group_adults=2&req_adults=2&no_rooms=1&group_children=0&req_children=0&hpos=2&hapos=2&sr_order=popularity&srpvid=42cc81de452009eb&srepoch=1673202494&all_sr_blocks=57095605_262941681_2_1_0&highlighted_blocks=57095605_262941681_2_1_0&matching_block_id=57095605_262941681_2_1_0&sr_pri_blocks=57095605_262941681_2_1_0__21200&tpi_r=2&from_sustainable_property_sr=1&from=searchresults#hotelTmpl',

    address: 'Se, Funchal',

    price: '1,045 lei',

    ratings: '8.3Very Good 647 reviews',

    thumbnails: 'https://cf.bstatic.com/xdata/images/hotel/square200/364430623.webp?k=8c1e510da2aad0fc9ff5731c3874e05b1c4cceec01a07ef7e9db944799771724&o=&s=1'

  },

  {

    name: 'Les Suites at The Cliff Bay - PortoBay',

    url: 'https://www.booking.com/hotel/pt/les-suites-at-the-cliff-bay.html?aid=304142&label=gen173nr-1FCAQoggJCFnNlYXJjaF9tYWRlaXJhIGlzbGFuZHNIMVgEaMABiAEBmAExuAEXyAEM2AEB6AEB-AEDiAIBqAIDuAK9luydBsACAdICJGViMWY2MmRjLWJhZmEtNGZhZC04MDAyLWQ4MmU3YjU5MTMwZtgCBeACAQ&ucfs=1&arphpl=1&checkin=2023-01-13&checkout=2023-01-15&group_adults=2&req_adults=2&no_rooms=1&group_children=0&req_children=0&hpos=3&hapos=3&sr_order=popularity&srpvid=42cc81de452009eb&srepoch=1673202494&all_sr_blocks=395012401_247460894_2_1_0&highlighted_blocks=395012401_247460894_2_1_0&matching_block_id=395012401_247460894_2_1_0&sr_pri_blocks=395012401_247460894_2_1_0__100000&tpi_r=2&from_sustainable_property_sr=1&from=searchresults#hotelTmpl',

    address: 'Sao Martinho, Funchal',

    price: '4,928 lei',

    ratings: '9.5Exceptional 119 reviews',

    thumbnails: 'https://cf.bstatic.com/xdata/images/hotel/square200/270120962.webp?k=68ded1031f5082597c48eb25c833ea7fcedc2ec2bc5d555adfcac98b232f9745&o=&s=1'

  }

]

Alternativas

Embora o tutorial até este ponto tenha parecido simples, devemos mencionar as ressalvas normalmente encontradas na extração de dados da web, especialmente no caso de querer expandir o seu projeto.

Atualmente, os sites implementam várias técnicas de deteção de bots e recolhem dados do navegador para que possam impedir ou bloquear o tráfego automatizado. O Booking.com não é exceção a esta regra. Utilizando a proteção PerimeterX, o site realiza verificações no seu IP e recolhe várias informações:

  • propriedades do objeto Navigator (deviceMemory, languages, platform, userAgent, webdriver, etc.)
  • enumeração de tipos de letra e plugins
  • verificações das dimensões do ecrã
  • e muito mais.

Uma solução para estes desafios é utilizar uma API de scraping, que oferece uma forma simples e fiável de aceder a dados de sites como o Booking.com sem a necessidade de criar e manter o seu próprio scraper.

A WebScrapingAPI é um produto desse tipo, que utiliza rotação de proxies para contornar CAPTCHAs e randomiza os dados do navegador para imitar um utilizador real. Para começar, basta registar-se para criar uma conta e obter a sua chave API no painel de controlo. Esta chave é utilizada para autenticar os seus pedidos.

Para testar rapidamente a API com o projeto Node.js já existente, podemos utilizar o SDK correspondente. Basta executar o seguinte comando:

npm install webscrapingapi

Agora, basta ajustar os seletores CSS anteriores à API. A funcionalidade de regras de extração permite analisar dados com modificações mínimas, tornando-a uma ferramenta poderosa no seu conjunto de ferramentas de web scraping.

import webScrapingApiClient from 'webscrapingapi';

const client = new webScrapingApiClient("YOUR_API_KEY");

async function exampleUsage() {

    const api_params = {

        'render_js': 1,

    	  'proxy_type': 'datacenter',

    	  'timeout': 60000,

    	  'extract_rules': JSON.stringify({

            names: {

                selector: 'div[data-testid="title"]',

                output: 'text',

                all: '1'

        	},

        	locations: {

                selector: 'a[data-testid="title-link"]',

                output: '@href',

                all: '1'

        	},

        	addresses: {

                selector: '[data-testid="address"]',

                output: 'text',

                all: '1'

        	},

        	prices: {

                selector: '[data-testid="price-and-discounted-price"]',

                output: 'text',

                all: '1'

        	},

        	ratings: {

                selector: '[data-testid="review-score"]',

                output: 'text',

                all: '1'

        	},

        	thumbnails: {

                selector: '[data-testid="image"]',

                output: '@src',

                all: '1'

        	}

        })

    }

    const URL = "https://www.booking.com/searchresults.en-us.html?ss=Madeira+Islands&checkin=2023-01-13&checkout=2023-01-15"

    const response = await client.get(URL, api_params)

    if (response.success) {

        // Group the lists

    	  const listings = []

    	  for (let i = 0; i < response.response.data.names.length; i++) {

            listings.push({

               name: response.response.data.names[i],

               url: response.response.data.locations[i],

               address: response.response.data.addresses[i],

               price: response.response.data.prices[i],

               ratings: response.response.data.ratings[i],

               thumbnails: response.response.data.thumbnails[i]

            })

        }

        console.log(listings)

    } else {

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

    }

}

exampleUsage();

Conclusão

Neste tutorial, abordámos os conceitos básicos de como fazer web scraping no Booking.com utilizando Node.js e Puppeteer. Mostrámos-lhe como configurar o seu ambiente e extrair detalhes de anúncios para a Madeira, Portugal. No entanto, estas técnicas e conceitos podem ser aplicados a outros sites e pontos de dados também.

O web scraping pode ser uma ferramenta incrivelmente útil tanto para empresas como para cientistas de dados. Ao recolher dados do Booking.com, pode obter informações valiosas sobre o setor hoteleiro, avaliar a concorrência e muito mais. No entanto, é importante ter em mente que o web scraping pode violar os termos de utilização de alguns sites, e é sempre uma boa ideia verificar as políticas específicas antes de prosseguir.

Embora seja possível criar o seu próprio web scraper, recorrer a um serviço profissional pode muitas vezes ser uma opção mais segura e eficiente, especialmente para projetos de maior dimensão. Um scraper profissional terá os conhecimentos e os recursos necessários para lidar com quaisquer desafios que possam surgir e fornecer resultados de alta qualidade.

Esperamos que tenha gostado deste tutorial e que agora se sinta preparado para recolher dados valiosos da Booking.com utilizando um ambiente Node.js. Obrigado pela leitura!

Sobre o autor
Raluca Penciuc, Desenvolvedor Full-Stack @ 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.