有些网站的DOM和内容是在页面加载时动态生成的。 (基于Angularjs的网站因此而臭名昭着)
您使用什么方法? 我尝试了phantomjs和jsdom,但似乎在我刮之前我无法让页面执行它的javascript。
这是一个简单的jsdom示例(不是基于angularjs但仍然是动态生成的)
var env = require('jsdom').env;
exports.scrape = function(link, callback) {
var config = {
url: link,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36'
},
done: jsdomDone
};
env(config);
}
function jsdomDone(err, window) {
var info = null;
if(err) {
console.error(err);
} else {
var $ = require('jquery')(window);
console.log($('.profilePic').attr('src'));
}
}
exports.scrape('https://www.facebook.com/elcompanies');
我尝试了phantomjs,取得了一定的成功。
var page = new WebPage()
var fs = require('fs');
page.onLoadFinished = function() {
console.log("page load finished");
window.setTimeout(function() {
page.render('export.png');
fs.write('1.html', page.content, 'w');
phantom.exit();
}, 10000);
};
page.open("https://www.facebook.com/elcompanies", function() {
page.evaluate(function() {
});
});
在这里,我等待onLoadFinished事件,甚至放一个10秒的计时器。有趣的是,虽然我的export.png页面图像捕获显示了一个完全呈现的页面,但我的1.html并没有在合适的位置显示.profilePic类元素。它似乎是坐在一些javascript代码中,被某种“ require(”TimeSlice“)包围.guard(function(){bigPipe.onPageletArrive({... ”block
如果你能为我提供一个从这个页面上删除图像的工作示例,那将会很有帮助。
答案 0 :(得分:4)
我使用nightmarejs在Facebook上做了一些拼抢
这是我用来从Facebook页面的某些帖子中获取一些内容的代码。
module.exports = function checkFacebook(callback) {
var nightmare = Nightmare();
Promise.resolve(nightmare
.viewport(1000, 1000)
.goto('https://www.facebook.com/login/')
.wait(2000)
.evaluate(function(){
document.querySelector('input[id="email"]').value = facebookEmail
document.querySelector('input[id="pass"]').value = facebookPwd
return true
})
.click('#loginbutton input')
.wait(1000)
.goto('https://www.facebook.com/groups/bierconomia')
.evaluate(function(){
var posts = document.getElementsByClassName('_1dwg')
var length = posts.length
var postsContent = []
for(var i = 0; i < length; i++){
var pTag = posts[i].getElementsByTagName('p')
postsContent.push({
content: pTag[0] ? pTag[0].innerText : '',
productLink: posts[i].querySelector('a[rel = "nofollow"]') ? posts[i].querySelector('a[rel = "nofollow"]').href : '',
photo: posts[i].getElementsByClassName('_46-i img')[0] ? posts[i].getElementsByClassName('_46-i img')[0].src : ''
})
}
return postsContent
}))
.then(function(results){
log(results)
return new Promise(function(resolve, reject) {
var leanLinks = results.map(function(result){
return {
post: {
content: result.content,
productLink: extractLinkFromFb(result.productLink),
photo: result.photo
}
}
})
resolve(leanLinks)
})
})
我觉得有用的噩梦就是你可以使用wait函数等待X ms或者某个特定的类来渲染。
答案 1 :(得分:1)
这是因为基于AJAX调用生成的网页具有异步AJAX调用,您无法依赖onLoad事件(因为数据仍然不可用)。
在我个人看来,最可靠的方法是跟踪从这个HTML调用哪些REST服务并直接调用它们。有时您需要使用HTML中的值或从其他调用中获取的值。
我知道这可能听起来很复杂,事实上确实如此。您需要调试页面并了解所调用的内容。但这肯定会奏效。
顺便说一句,使用chrome开发人员工具将有助于完成此任务。只需观察在网络选项卡中进行的呼叫。您甚至可以观察每次AJAX呼叫中发送和接收的内容。
答案 2 :(得分:0)
如果这是一次性的事情,也就是说,如果我只想抓一次页面,我只需使用浏览器和artoo-js。
答案 3 :(得分:0)
我从未尝试过使用幻像在磁盘上写一个页面,但我有两个观察结果:
1)您正在使用fs.write将内容写入磁盘,但writeFile是异步调用。这意味着您需要将其更改为fs.writeFileSync或在关闭幻像之前使用回调。
2)我希望你不要期望将HTML写入文件并在浏览器中打开它并像保存png时那样呈现它,因为它不会以这种方式工作。有些对象可以直接存储在DOM属性中,当然有值存储在javascript变量中,这些东西永远不会被保留。