网页搜寻基础知识

时间:2014-08-11 22:50:40

标签: javascript node.js xmlhttprequest web-scraping cheerio

我正在给网页抓一试,因为我可以看到很多有潜力用它来做有趣的事情。我花了几个小时研究我需要的东西,并且我决定使用带有'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>,里面没有随机句子。

我最初的猜测是节点在随机语句脚本运行完毕之前正在抓取标记。但我不知道如何诊断正在发生的事情,所以有人有想法吗?

4 个答案:

答案 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 POSThttp://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秒,这对于迭代过程来说并不是很好。但我设法得到了句子,所以我将从这里开始,感谢信息人员!