Prérequis
Si votre environnement Node.js n'est pas encore configuré, rendez-vous simplement sur leur site web officiel pour télécharger la dernière version adaptée à votre système d'exploitation. Créez ensuite un nouveau répertoire et exécutez la commande suivante pour initialiser votre projet :
npm init -y
Nous utiliserons TypeScript pour écrire le code. Ce sur-ensemble de JavaScript ajoute un typage statique facultatif et d’autres fonctionnalités. Il est utile pour les projets de grande envergure et permet de détecter plus facilement les erreurs à un stade précoce. Vous devez l’ajouter aux dépendances de développement du projet et initialiser son fichier de configuration :
npm install typescript -save-dev npx tsc -init
Assurez-vous simplement que, dans le fichier tsconfig.json nouvellement généré, la propriété « outDir » est définie sur « dist », car nous avons l'intention de séparer le code TypeScript du code compilé.
Enfin, la commande suivante ajoutera Puppeteer aux dépendances de notre projet :
npm install puppeteer
Puppeteer est une bibliothèque Node.js qui fournit une API de haut niveau pour contrôler un navigateur Chrome sans interface graphique, pouvant être utilisé pour le web scraping et les tâches d'automatisation
Emplacement des données
Pour ce tutoriel, nous avons choisi d'extraire les propriétés disponibles dans les îles de Madère, au Portugal : https://www.booking.com/searchresults.en-us.html?ss=Madeira+Islands&checkin=2023-01-13&checkout=2023-01-15. Il est important d'ajouter les dates d'arrivée et de départ à l'URL afin que toutes les informations sur les propriétés soient disponibles.
Ce guide couvre l'extraction des données suivantes relatives aux propriétés :
- le nom
- l'URL
- l'adresse physique
- le prix
- la note et le nombre d'avis
- la vignette
Vous pouvez les voir mis en évidence sur la capture d'écran ci-dessous :
En ouvrant les outils de développement sur chacun de ces éléments, vous pourrez repérer les sélecteurs CSS que nous utiliserons pour localiser les éléments HTML. Si vous débutez avec les sélecteurs CSS, n'hésitez pas à consulter ce guide pour débutants.
Analyse des données
Comme toutes les annonces ont la même structure et les mêmes données, nous pouvons extraire toutes les informations de la liste complète des propriétés dans notre algorithme. Après avoir exécuté le script, nous pouvons parcourir tous les résultats et les compiler en une seule liste.
Après un premier coup d'œil au document HTML, vous avez peut-être remarqué que le site web de Booking est assez complexe et que les noms de classes sont pour la plupart générés de manière aléatoire.
Heureusement pour nous, le site web ne repose pas uniquement sur les noms de classes, et nous pouvons utiliser la valeur d’un attribut spécifique comme critère d’extraction. Dans la capture d’écran ci-dessus, nous avons mis en évidence l’accessibilité de la vignette, du nom et de l’URL d’une propriété.
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")
Nous avons utilisé Puppeteer pour ouvrir une instance de navigateur, créer une nouvelle page, accéder à notre URL cible, extraire les données mentionnées, puis fermer le navigateur. À des fins de débogage visuel, j’utilise le mode non-headless du navigateur.
Comme expliqué ci-dessus, les données étaient facilement accessibles grâce à l'attribut « data-testid » qui attribuait une valeur unique à l'élément HTML. Exécutez la commande suivante pour lancer le script :
npx tsc && node dist/index.js
Votre terminal devrait afficher 3 résultats de liste de même taille, représentant les noms, les URL et les vignettes de toutes les propriétés de la page actuelle.
Pour la section suivante du document HTML, nous avons mis en évidence l'adresse, la note et le nombre d'avis pour une propriété.
// 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)
Comme précédemment, nous avons utilisé l'attribut « data-testid ». En relançant le script, vous devriez voir s'afficher deux listes supplémentaires, identiques aux précédentes.
Enfin, dans la dernière section, nous avons extrait le prix de la propriété. Le code sera identique à ce que nous avons fait précédemment :
// 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)
Pour faciliter le traitement ultérieur des données extraites, nous allons regrouper les listes obtenues en une seule.
// 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)
Le résultat final devrait maintenant ressembler à ceci :
[
{
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'
}
]Alternatives
Même si le tutoriel semblait simple jusqu'à présent, nous devons mentionner les pièges généralement rencontrés dans le web scraping, en particulier lorsque vous souhaitez développer votre projet.
De nos jours, les sites web mettent en œuvre diverses techniques de détection des bots et collectent des données de navigateur afin de pouvoir empêcher ou bloquer le trafic automatisé. Booking.com ne fait pas exception à cette règle. À l'aide de la protection PerimeterX, le site web effectue des vérifications sur votre adresse IP et collecte de multiples informations :
- les propriétés de l'objet Navigator (deviceMemory, languages, platform, userAgent, webdriver, etc.)
- énumération des polices et des plugins
- vérification des dimensions de l'écran
- et bien d'autres encore.
Une solution à ces défis consiste à utiliser une API de scraping, qui offre un moyen simple et fiable d'accéder aux données de sites web comme Booking.com sans avoir à créer et à maintenir votre propre scraper.
WebScrapingAPI est un produit de ce type, qui utilise la rotation de proxys pour contourner les CAPTCHA et randomise les données du navigateur afin d'imiter un utilisateur réel. Pour commencer, il suffit de créer un compte et d'obtenir votre clé API depuis le tableau de bord. Cette clé sert à authentifier vos requêtes.
Pour tester rapidement l'API avec le projet Node.js existant, nous pouvons utiliser le SDK correspondant. Il suffit d'exécuter la commande suivante :
npm install webscrapingapi
Il ne vous reste plus qu'à adapter les sélecteurs CSS précédents à l'API. La fonctionnalité de règles d'extraction vous permet d'analyser les données avec un minimum de modifications, ce qui en fait un outil puissant dans votre boîte à outils 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();Conclusion
Dans ce tutoriel, nous avons abordé les bases du web scraping sur Booking.com à l'aide de Node.js et Puppeteer. Nous vous avons montré comment configurer votre environnement et extraire les détails des annonces pour Madère, au Portugal. Cependant, ces techniques et concepts peuvent également s'appliquer à d'autres sites web et sources de données.
Le web scraping peut être un outil extrêmement utile tant pour les entreprises que pour les data scientists. En collectant des données sur Booking.com, vous pouvez obtenir des informations précieuses sur le secteur de l'hôtellerie, évaluer la concurrence, et bien plus encore. Cependant, il est important de garder à l'esprit que le web scraping peut enfreindre les conditions d'utilisation de certains sites web, et il est toujours recommandé de vérifier les politiques spécifiques avant de procéder.
Bien qu'il soit possible de créer votre propre outil de web scraping, le recours à un service professionnel peut souvent s'avérer une option plus sûre et plus efficace, en particulier pour les projets de grande envergure. Un prestataire professionnel disposera de l'expertise et des ressources nécessaires pour relever tous les défis qui pourraient se présenter et fournir des résultats de haute qualité.
Nous espérons que ce tutoriel vous a plu et que vous vous sentez désormais prêt à collecter des données précieuses sur Booking.com à l'aide d'un environnement Node.js. Merci de votre lecture !




