Charger une page Web SPA via AJAX

j'essaie de récupérer une page Web entière en utilisant JavaScript en connectant L'URL. Cependant, le site web est construit comme une Application D'une seule Page (SPA) qui utilise JavaScript/colonne vertébrale.js pour charger dynamiquement la plupart de son contenu après avoir rendu la réponse initiale.

ainsi, par exemple, lorsque j'achemine vers l'adresse suivante:

https://connect.garmin.com/modern/activity/1915361012

puis entrez ceci dans la console (après que la page a été chargée):

var $page = $("html")
console.log("%c✔: ", "color:green;", $page.find(".inline-edit-target.page-title-overflow").text().trim());
console.log("%c✔: ", "color:green;", $page.find("footer .details").text().trim());

alors je vais obtenir le titre de l'activité chargé dynamiquement ainsi que le pied de page chargé statiquement:

Working Screenshot


cependant lorsque j'essaie de charger la page web via un appel AJAX avec $.get() ou .load() je ne vois que des livrées de la réponse initiale (le même que le contenu lors de la plus de vue-source):

view-source:https://connect.garmin.com/modern/activity/1915361012

donc si J'utilise L'un des AJAX suivants appels:

// jQuery.get()
var url = "https://connect.garmin.com/modern/activity/1915361012";
jQuery.get(url,function(data) {
    var $page = $("<div>").html(data)
    console.log("%c✖: ", "color:red;",   $page.find(".page-title").text().trim());
    console.log("%c✔: ", "color:green;", $page.find("footer .details").text().trim());
});

// jQuery.load()
var url = "https://connect.garmin.com/modern/activity/1915361012";
var $page = $("<div>")
$page.load(url, function(data) {
    console.log("%c✖: ", "color:red;",   $page.find(".page-title").text().trim()    );
    console.log("%c✔: ", "color:green;", $page.find("footer .details").text().trim());
});

je vais quand même obtenir le pied de page initial, mais je n'obtiendrai aucun des autres contenus de la page:

Broken - Screenshot


j'ai essayé solution icieval() le contenu de chaque script balise, mais qui n'apparaît pas suffisamment robuste pour charger la page:

jQuery.get(url,function(data) {
    var $page = $("<div>").html(data)
    $page.find("script").each(function() {
        var scriptContent = $(this).html(); //Grab the content of this tag
        eval(scriptContent); //Execute the content
    });
    console.log("%c✖: ", "color:red;",   $page.find(".page-title").text().trim());
    console.log("%c✔: ", "color:green;", $page.find("footer .details").text().trim());
});

Q: N'importe quelles options pour charger complètement une page Web qui sera raclable plus JavaScript?

10
demandé sur KyleMit 2017-08-14 20:30:22

3 réponses

vous ne pourrez jamais répliquer entièrement par vous-même ce qu'une page (SPA) arbitraire fait.

Le seul moyen que je vois est à l'aide d'un navigateur sans PhantomJS ou Chrome Sans Tête, ou Sans Tête Firefox.

je voulais essayer sans Tête, Chrome donc, nous allons voir ce qu'il peut faire avec votre page:

vérification Rapide à l'aide d'REPL

chargez cette page avec Chrome Headless (vous aurez besoin de Chrome 59 sur Mac / Linux, Chrome 60 sur Windows), et trouver le titre de la page avec JavaScript de la REPL:

% chrome --headless --disable-gpu --repl https://connect.garmin.com/modern/activity/1915361012
[0830/171405.025582:INFO:headless_shell.cc(303)] Type a Javascript expression to evaluate or "quit" to exit.
>>> $('body').find('.page-title').text().trim() 
{"result":{"type":"string","value":"Daily Mile - Round 2 - Day 27"}}

NB: pour obtenir le chrome ligne de commande sur un Mac je l'ai fait à l'avance:

alias chrome="'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'"

utilisation programmatique avec Node & Puppeteer

Marionnettiste est une bibliothèque de nœuds (par Google Chrome developers) qui fournit une API de haut niveau pour contrôler le Chrome sans tête sur le protocole DevTools. Il peut également être configuré pour utiliser pleinement (non sans tête) Chrome.

(Étape 0 : Install Noeud& fils si vous ne les avez pas)

Dans un nouveau répertoire:

yarn init
yarn add puppeteer

Créer index.js avec ceci:

const puppeteer = require('puppeteer');
(async() => {
    const url = 'https://connect.garmin.com/modern/activity/1915361012';
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    // Go to URL and wait for page to load
    await page.goto(url, {waitUntil: 'networkidle'});
    // Wait for the results to show up
    await page.waitForSelector('.page-title');
    // Extract the results from the page
    const text = await page.evaluate(() => {
        const title = document.querySelector('.page-title');
        return title.innerText.trim();
    });
    console.log(`Found: ${text}`);
    browser.close();
})();

Résultat:

$ node index.js 
Found: Daily Mile - Round 2 - Day 27
3
répondu Hugues M. 2017-08-30 15:43:42

tout d'Abord: évitez eval - votre politique de sécurité de contenu devrait le bloquer et il vous laisse ouvert aux attaques XSS faciles. Les robots racleurs ne la feront pas fonctionner.

le problème que vous décrivez est commun à tous les SPAs - quand une personne visite ils obtiennent votre script shell de l'application, qui se charge alors dans le reste du contenu - tout bon. Quand un bot visite, il ignore les scripts et renvoie le shell vide.

la solution est le rendu côté serveur. Une façon de le faire est si vous utilisez un render JS (disons React) et un noeud.js sur le serveur, vous pouvez assez facilement construire le JS et le servir de manière statique.

cependant, si vous ne l'êtes pas, vous aurez besoin d'exécuter un navigateur sans tête sur votre serveur qui exécute tous les JS qu'un utilisateur ferait et ensuite sert le résultat au bot.

heureusement quelqu'un d'autre a déjà fait tout le travail ici. Ils ont mis une démo en ligne que vous pouvez essayer avec votre site:

Rendertron preview

1
répondu Keith 2017-08-30 07:39:58

je pense que vous devriez connaître le concept de SPA, SPA est une Application D'une seule Page, il est seulement le fichier HTML statique. lorsque la route change, la page va créer ou modifier DOM noeuds dynamiquement pour obtenir l'effet de page de commutateur en utilisant Javascript.

par conséquent, si vous utilisez $.get(), le serveur va répondre à un fichier html statique qui a une page stable, donc vous ne chargerez pas ce que vous voulez.

si vous voulez utiliser $.get(), il y a deux façons, la première est d'utiliser headless browser par exemple, headless chrome,phantomJS et etc. Il vous aidera à charger la page et vous pouvez obtenir dom noeuds de la page chargée.La deuxième est SSR (Server Slide Render), si vous utilisez SSR, vous obtiendrez les données HTML de la page directement par $.get, parce que la réponse du serveur les données HTML de la page correspondent quand on demande des routes différentes.

Référence:

SSR

le cadre SRR de vue: Nuxt.js

PhantomJS

API de noeud de Chrome Sans Tête

0
répondu Kermit 2017-09-04 05:38:20