Javascript 通过AJAX加载SPA网页

Javascript 通过AJAX加载SPA网页,javascript,jquery,ajax,single-page-application,jquery-load,Javascript,Jquery,Ajax,Single Page Application,Jquery Load,我正在尝试通过插入URL使用JavaScript获取整个网页。但是,该网站是作为一个单页应用程序(SPA)构建的,它使用JavaScript/在呈现初始响应后动态加载大部分内容 例如,当我路由到以下地址时: https://connect.garmin.com/modern/activity/1915361012 然后将其输入控制台(页面加载后): var$page=$(“html”) console.log(“%c✔: ", "颜色:绿色;“,$page.find(“.inline edit

我正在尝试通过插入URL使用JavaScript获取整个网页。但是,该网站是作为一个单页应用程序(SPA)构建的,它使用JavaScript/在呈现初始响应后动态加载大部分内容

例如,当我路由到以下地址时:

https://connect.garmin.com/modern/activity/1915361012
然后将其输入控制台(页面加载后):

var$page=$(“html”)
console.log(“%c✔: ", "颜色:绿色;“,$page.find(“.inline edit target.page title overflow”).text().trim());
console.log(“%c✔: ", "颜色:绿色;“,$page.find(“footer.details”).text().trim());
然后,我将获得动态加载的活动标题以及静态加载的页脚:


但是当我尝试通过AJAX调用或加载网页时,我只收到初始响应(与查看源代码时的内容相同):

查看源代码:https://connect.garmin.com/modern/activity/1915361012
所以,若我使用以下AJAX调用之一:

//jQuery.get()
变量url=”https://connect.garmin.com/modern/activity/1915361012";
get(url,函数(数据){
var$page=$(“”).html(数据)
console.log(“%c✖: ", "颜色:红色;“,$page.find(“.page title”).text().trim());
console.log(“%c✔: ", "颜色:绿色;“,$page.find(“footer.details”).text().trim());
});
//jQuery.load()
变量url=”https://connect.garmin.com/modern/activity/1915361012";
变量$page=$(“”)
$page.load(url、函数(数据){
console.log(“%c✖: ", "颜色:红色;“,$page.find(“.page title”).text().trim());
console.log(“%c✔: ", "颜色:绿色;“,$page.find(“footer.details”).text().trim());
});
我仍将获取初始页脚,但不会获取任何其他页面内容:


我已经尝试了使用to
eval()
来加载每个
script
标记的内容,但这看起来不够健壮,无法实际加载页面:

jQuery.get(url,函数(数据){
var$page=$(“”).html(数据)
$page.find(“脚本”).each(函数(){
var scriptContent=$(this.html();//获取此标记的内容
eval(scriptContent);//执行内容
});
console.log(“%c✖: ", "颜色:红色;“,$page.find(“.page title”).text().trim());
console.log(“%c✔: ", "颜色:绿色;“,$page.find(“footer.details”).text().trim());
});

Q:是否有任何选项可以完全加载可通过JavaScript刮取的网页?

首先:避免
eval
-您的内容安全策略应该阻止它,并使您容易受到XSS攻击。刮削机器人肯定不会运行它

你所描述的问题对所有SPA来说都很常见——当一个人访问时,他们会得到你的应用程序外壳脚本,然后加载到其余的内容中——一切都很好。当机器人访问时,它们会忽略脚本并返回空壳

解决方案是服务器端渲染。一种方法是,如果您在服务器上使用JS渲染器(比如React)和Node.JS,那么您可以相当轻松地构建JS并静态地为其提供服务

但是,如果您没有,那么您需要在服务器上运行一个无头浏览器,该浏览器执行用户将执行的所有JS,然后将结果提供给bot

幸运的是,其他人已经这样做了。他们在网上发布了一个演示,您可以:


你永远无法自己完全复制任意(SPA)页面的功能

我看到的唯一方法是使用无头浏览器,如或或

我想尝试无头Chrome,让我们看看它对您的页面有什么作用:

使用内部REPL进行快速检查 使用Chrome Headless加载该页面(在Mac/Linux上需要Chrome 59,在Windows上需要Chrome 60),然后从REPL中查找带有JavaScript的页面标题:

% 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"}}
注意:为了让
chrome
命令行在Mac上工作,我事先做了以下操作:

alias chrome="'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'"
以编程方式与节点和傀儡器一起使用 是一个节点库(由Google Chrome开发者开发),它提供了一个高级API来通过DevTools协议控制headless Chrome。它也可以配置为使用全(非无头)镀铬

(步骤0:安装&如果没有)

在新目录中:

yarn init
yarn add puppeteer
使用以下命令创建
index.js

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();
})();
结果:

$ node index.js 
Found: Daily Mile - Round 2 - Day 27

我想你应该知道SPA的概念, SPA是单页应用程序,它只是静态html文件。当路由发生变化时,页面会动态创建或修改
DOM
节点,使用Javascript实现切换页面的效果

因此,如果使用
$.get()
,服务器将响应一个具有稳定页面的静态html文件,因此您不会加载所需内容

如果你想使用
$.get()
,它有两种方法,第一种是使用
无头浏览器
,例如
无头chrome
phantomJS
等。它将帮助你加载页面,你可以获得加载页面的
dom
节点。第二种是
SSR
服务器幻灯片渲染
),如果您使用
SSR
,您将通过
$直接获取页面的HTML数据。get
,因为服务器在请求不同路由时会响应相应页面的HTML数据

参考:

vue的SRR框架:


最终目标是什么?如果您想获取数据,直接访问原始数据可能更容易(取决于您的来源,显然,如果您知道您的ID,则无需cookie或任何东西即可获取数据)。如果您真的想加载整个页面,然后从DOM中挖掘数据,唯一的通用解决方案是使用“可检测的”无头浏览器,例如或我同意避免eval,但最终需要一种方法来启动加载页面内容的脚本。Garmin.com不是我的网站,因此我无法启用任何服务器端渲染解决方案。伦德顿似乎没有采取行动