22 octobre 2021 · 5 min de lecture
Le “Web scraping” est une technique pour extraire le contenu des sites internet dans le but d’archiver les données de manière structurée. Les données sont extraites directement depuis le code source. Le travail consiste à les rechercher dans une jungle de balises HTML.
Il est pourtant bien plus simple de récupérer ces données dans un format structuré. Ceci est possible en interceptant les requêtes web entre votre navigateur et le site internet.
Cette méthode fonctionne, entre autres, sur les réseaux sociaux ou les sites de petites annonces (mais assurez-vous de respecter leurs conditions d’utilisation).
Les sites internet contiennent beaucoup de Javascript. Il est utilisé notamment pour rafraichir les données dans le navigateur sans recharger toute la page. Dans cette situation la page web envoie une requête HTTP au serveur web pour obtenir les nouvelles données à injecter dans la page. Celles-ci sont transmises généralement en JSON, un format de données structuré.
Voyons comment intercepter les requêtes avec Playwright et Electron.
Avant d’entrer dans le vif du sujet il convient d’identifier la requête que vous souhaitez intercepter :
Ouvrez votre navigateur et chargez le site internet sur lequel vous voulez travailler. Si besoin, connectez-vous sur le site avec vos identifiants.
Ouvrez les outils pour développeurs (touche F12
). Cliquez sur Réseaux
. Toutes les requêtes HTTP entre le navigateur et le site web sont listées. Rechargez la page ou naviguez sur le site pour voir l’activité. Parmi elles se trouvent celle qui vous intéresse. Le but est de trouver son nom.
Par exemple sur un site de petites annonces que je ne nommerai pas, la requête search
reçoit un JSON contenant les données à afficher sur la page web.
Dans l’onglet Headers
, l’information Request URL
vous donne le chemin complet de l’URL sur laquelle nous pourrons utiliser une expression régulière.
Playwright est un outil développé en “open-source” par Microsoft. Il permet d’automatiser des tests sur les différents navigateurs internet.
Installez tout d’abord NodeJS et Visual Studio Code sur votre ordinateur.
Créez un dossier et ouvrez une invite de commande. Puis tapez :
npm init
Appuyez sur ENTREE pour valider les options par défaut.
Ajoutons Playwright au projet, comme dépendance de développement :
npm i -D playwright
Ouvrez le dossier avec Visual Studio Code (ou votre éditeur préféré):
code .
Créez le fichier main.js
à côté du fichier package.json
:
const { chromium } = require('playwright')
async function main () {
const browser = await chromium.launch({
headless: false
});
const context = await browser.newContext();
const page = await context.newPage();
page.on('response', (response) => {
if (!/jsonsearch/.test(response.url())) { return }
console.log(response.status(), response.url())
response.json().then((json) => {
console.log(json) // à vous de traiter ensuite les données de ce JSON
}).catch((error) => {
console.error(error)
})
});
await page.goto('https://en.jeffprod.com');
}
main()
Explications du code ci-dessus :
if (!/jsonsearch/.test(response.url())) { return }
: On veut intercepter les requêtes dont l’URL contient jsonsearch
. Car comme indiqué dans le paragraphe des prés-requis, nous l’avons identifié au préalable. Ici, on ne tient pas compte des URL qui ne contiennent pas ce terme via une expression régulière.console.log(response.status(), response.url())
: on affiche, pour information, le code réponse HTTP (normalement 200) et l’URL interceptée.console.log(json)
: le JSON intercepté est disponible dans cette variable. Pour la suite, vous êtes le seul à savoir quoi faire de ces données.Pour tester le programme, dans package.json
ajoutez la ligne suivante dans la partie scripts
:
"scripts": {
"start": "node main.js"
}
Vous pouvez alors démarrer le programme avec la commande :
npm run start
Electron permet la création d’applications de bureau pour Windows, Mac et Linux avec du HTML, CSS et NodeJS. L’application est un navigateur internet basé sur Chromium.
Suivez le tutoriel officiel pour créer les bases de votre application.
Nous allons intercepter les requêtes grâce à l’API de débogage. Voici un exemple modifié du fichier main.js
. La partie relative au sujet de cet article est indiquée entre les commentaires Debugger API
:
const { app, BrowserWindow } = require('electron')
let mainWin
let requestIDs = new Set()
function createWindow () {
mainWin = new BrowserWindow({
width: 800,
height: 600
})
// -----------------------------------------------------------------------
// Debugger API
const getResponse = (requestId) => {
mainWin.webContents.debugger.sendCommand('Network.getResponseBody', { requestId })
.then(function(response) {
let jsonresp
try {
jsonresp = JSON.parse(response.body)
} catch (err) {
console.error('invalid JSON', err)
return
}
console.log(jsonresp) // à vous de traiter ensuite les données de ce JSON
}).catch((err) => {
console.error(err)
})
}
mainWin.webContents.debugger.on('detach', (event, reason) => {
console.log('Debugger detached due to : ', reason)
})
mainWin.webContents.debugger.on('message', (event, method, params) => {
if (method === 'Network.requestWillBeSent' && /jsonsearch/.test(params.request.url)) {
requestIDs.add(params.requestId)
}
if (method === 'Network.loadingFinished' && requestIDs.has(params.requestId)) {
console.log('got loadingFinished for an interesting request')
requestIDs.delete(params.requestId)
getResponse(params.requestId)
}
})
mainWin.webContents.debugger.attach('1.3')
mainWin.webContents.debugger.sendCommand('Network.enable')
mainWin.loadURL('https://en.jeffprod.com')
// end debugger API
// -----------------------------------------------------------------------
} // function createWindow
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
Remplacez /jsonsearch/
par l’expression régulière de l’URL que vous souhaitez intercepter.
La technique est la suivante :
if (method === 'Network.requestWillBeSent' && /jsonsearch/.test(params.request.url))
: si une requête va être émise et qu’elle nous intéresse (l’URL contient jsonsearch
), on sauve l’ID de cette requête dans la variable tableau requestIDs
.if (method === 'Network.loadingFinished' && requestIDs.has(params.requestId))
: pour toute requête dont l’état est terminé, si son ID est dans notre tableau de sauvegarde, on récupère le corps de la requête via la fonction getResponse
.