我正在尝试通过插入URL来使用JavaScript获取整个网页。但是,该网站是作为单页应用程序(SPA)构建的,它使用JavaScript / backbone.js在呈现初始响应后动态加载其大部分内容。
例如,当我路由到以下地址时:
https://connect.garmin.com/modern/activity/1915361012
然后将其输入控制台(页面加载后):
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());
然后我将获得动态加载的活动标题以及静态加载的页脚:
然而,当我尝试通过与$.get()
或.load()
的AJAX调用加载网页时,我只会收到初始响应(与内容相同)当超过view-source)时:
view-source:https://connect.garmin.com/modern/activity/1915361012
因此,如果我使用以下任一AJAX调用:
// 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());
});
我仍会获得初始页脚,但不会获得任何其他页面内容:
我已经尝试了solution here到eval()
每个script
代码的内容,但这看起来不够强大,无法实际加载页面:
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());
});
问:完全加载可通过JavaScript报废的网页的任何选项?
答案 0 :(得分:3)
您永远无法完全复制任意(SPA)页面的内容。
我看到的唯一方法是使用无头浏览器,例如PhantomJS或Headless Chrome或Headless Firefox。
我想尝试无头Chrome,所以让我们看看它对你的网页有什么作用:
使用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'"
Puppeteer是一个节点库(由Google Chrome开发人员提供),它提供了一个高级API,可通过DevTools协议控制无头Chrome。它也可以配置为使用完整(非无头)Chrome。
(步骤0:安装Node&amp; Yarn,如果你没有这些)
在新目录中:
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
答案 1 :(得分:1)
首先关闭:避免eval
- 您的内容安全策略应该阻止它,让您容易受到轻松的XSS攻击。刮刮胶机肯定不会运行它。
您所描述的问题在所有SPA中都很常见 - 当一个人访问时,他们会获得您的应用程序shell脚本,然后加载其余内容 - 这一切都很好。当机器人访问时,他们会忽略脚本并返回空壳。
解决方案是服务器端渲染。一种方法是,如果您在服务器上使用JS渲染器(比如React)和Node.js,您可以相当轻松地构建JS并静态地提供它。
但是,如果您不是,那么您需要在服务器上运行无头浏览器,执行用户所需的所有JS,然后将结果提供给机器人。
幸运的是其他人已经done all the work here了。他们已经在线进行了演示,您可以try out with your site:
答案 2 :(得分:0)
我认为你应该知道SPA的概念,
SPA是单页应用程序,它只是静态的html文件。当路由变换时,页面将动态创建或修改DOM
个节点,以通过使用Javascript实现切换页面的效果。
因此,如果您使用$.get()
,服务器将响应具有稳定页面的静态html文件,因此您无法加载所需内容。
如果您想使用$.get()
,它有两种方式,第一种方式是使用headless browser
,例如,headless chrome
,phantomJS
等。它会帮助您加载页面,您可以获取已加载页面的dom
个节点。第二个是SSR
(Server Slide Render
),如果您使用SSR
,您将获得页面的HTML数据直接由$.get
,因为服务器响应请求不同路由时对应页面的HTML数据。
参考:
vue的SRR框架:Nuxt.js