网页抓取基础知识

Web Scraping Basics

本文关键字:基础知识 抓取 网页      更新时间:2023-09-26

我要试一试网页抓取,因为我可以看到用它做很多有趣的事情的潜力。我花了几个小时研究我需要什么,我决定使用node.js与'request'和'cheerio'模块来执行抓取。

因此,对于第一个项目,我想我会尝试从这个随机句子生成器站点获取一个随机句子: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>

所以我想要的位在span中(显然它在实际页面的检查中会有所不同),我编写了以下Javascript文件并在node中运行:

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>里面没有随机的句子。

我最初的猜测是节点在随机句子脚本完成运行之前抓取标记。但我不知道怎么诊断,有谁有办法吗?

是的,您的直觉是正确的,因为请求模块在随机句子脚本完成运行之前抓取标记。如果你打印出body,你会看到它包含:

<table class="centeredResult">
    <tr>
        <td>
            <span id="result"></span>
        </td>
    </tr>
</table> 

事实上,请求模块永远不会在获取的页面上执行任何JavaScript。

如果你需要JavaScript在你抓取的页面上运行,我建议你看看像phantomjs这样的无头浏览器,它可以让你通过JavaScript API与页面进行交互。

查看页面:

<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或类似的东西。

在浏览器中加载页面,并查看网络请求。您将看到,在cheerio停止加载DOM之后,语句被异步加载。有一个POSThttp://watchout4snakes.com/wo4snakes/Random/NewRandomSentence返回一个纯文本字符串(内容类型:text/html;charset=utf-8),然后插入到DOM中。

我不知道cheerio,但你可以(a)使用计时器等待几秒钟,或(b)切换到wd有一个明确的等待的东西,这将触发一旦DOM元素已经加载。

在对我的脚本进行了一些修改之后,我最终得到了这样的结果:

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);
});

多亏了使用phantomjs的提示,看起来好像无头浏览器方法允许脚本在抓取HTML内容之前运行。然后使用page.evaluate()从页面中提取句子。

看起来好像Phantomjs在我的系统上有一些问题。没有一个进程在phantom.exit()上退出,根据谷歌搜索,这与Nvidia显卡驱动有关。此外,该脚本相当慢,因为它等待页面的所有元素加载连接可能需要长达10秒的时间,这对于迭代过程来说不是很好。但是我设法得到了这个句子,所以我会从这里开始,谢谢你的信息!