我正在给网页抓一试,因为我可以看到很多有潜力用它来做有趣的事情。我花了几个小时研究我需要的东西,并且我决定使用带有'request'和'cheerio'模块的node.js来执行刮擦。
因此,对于第一个项目,我认为我会尝试从这个随机句子生成器网站获得一个随机句子:http://watchout4snakes.com/wo4snakes/Random/RandomSentence
标记看起来相对简单,这是我感兴趣的一点:
<div class="resultBox">
<table class="centeredResult">
<tbody><tr>
<td>
<span id="result">An amateur regret slights the lust outside his contentious century.</span>
</td>
</tr>
</tbody></table>
</div>
所以我想要的是在跨度中(显然它在检查实际页面时会有所不同),我编写了以下Javascript文件并在节点中运行它:
var request = require("./node_modules/request/");
cheerio = require('./node_modules/cheerio/');
request('http://watchout4snakes.com/wo4snakes/Random/RandomSentence', function(err, resp, body){
if(!err && resp.statusCode == 200){
console.log("connected...\n");
var $ = cheerio.load(body);
console.log($('#result').html());
}
else console.log("Failed To Connect...");
});
我收到通知,所以我做了一些检查,并确定我正确地抓取了页面的数据。所以我现在要做的就是选择#result
ID字段中的文本。但是我只给了一个空白区域,事实上如果我得到cheerio模块来打印该区域的实际标记,我会得到一个<span ID="result"></span>
,里面没有随机句子。
我最初的猜测是节点在随机语句脚本运行完毕之前正在抓取标记。但我不知道如何诊断正在发生的事情,所以有人有想法吗?
答案 0 :(得分:1)
是的,你的直觉是正确的,因为请求模块在随机语句脚本运行完毕之前正在抓取标记。如果您打印body
,则会看到它包含:
<table class="centeredResult">
<tr>
<td>
<span id="result"></span>
</td>
</tr>
</table>
实际上,请求模块永远不会在获取的页面上执行任何JavaScript。
如果您需要在要抓取的网页上运行JavaScript,我建议您查看phantomjs之类的无头浏览器,这些浏览器可让您通过JavaScript API与网页进行互动。
答案 1 :(得分:1)
在页面上看:
<script>
(function ($) {
$(document).ready(function () {
var options = {
target: '#result',
beforeSubmit: function () {
$('#result').empty();
$.fnWait();
},
success: function () {
$.unblockUI();
}
};
$('#frmSentence').ajaxForm(options)
.find('input[type=submit]')
.click();
});
})(jQuery);
看起来#evidence
span
正在填充AJAX。当您的库加载页面时,它不会执行Javascript,因此它不会加载引号。
如果您只是尝试查询他们从中提取的相同页面,这可能是最简单的。否则,你需要使用能够执行页面上的javascript的东西 - 比如Selenium或类似的东西。
答案 2 :(得分:1)
在浏览器中加载页面,然后查看网络请求。在cheerio停止加载DOM之后,您会看到该句子是异步加载的。 sa POST
到http://watchout4snakes.com/wo4snakes/Random/NewRandomSentence
返回带有引号的纯文本字符串(Content-Type:text / html; charset = utf-8),然后将其插入到DOM中。< / p>
我不知道cheerio,但您可以(a)使用计时器等待几秒钟,或者(b)切换到wd,其中有明确的wait for something,将在DOM元素加载后触发。
答案 3 :(得分:1)
所以在摆弄了我的剧本之后,这就是我最终的结果:
var page = require('webpage').create();
console.log("connecting...");
page.open("http://watchout4snakes.com/wo4snakes/Random/RandomSentence", function(){
console.log('connected');
var content = page.content;
var phrase = page.evaluate(function() {
return document.getElementById("result").innerHTML;
});
console.log(phrase);
});
感谢go-oleg提示使用phantomjs,看起来好像无头浏览器方法允许脚本在抓取HTML内容之前运行。然后我使用page.evaluate()从页面中提取句子。
看起来Phantomjs在我的系统上有一些问题。根据谷歌搜索,没有任何进程退出phantom.exit(),这与Nvidia图形驱动程序有关。此外,脚本相当慢,因为它等待页面的所有元素加载连接可能需要长达10秒,这对于迭代过程来说并不是很好。但我设法得到了句子,所以我将从这里开始,感谢信息人员!