【问题标题】:Parse Error When Creating Array CasperJS创建数组 CasperJS 时解析错误
【发布时间】:2014-08-19 04:06:11
【问题描述】:

我正在尝试抓取网站上的多个属性。我打算将它们加载到一个数组中,然后将该数组加载到我服务器上 db 上的一个表中。

我尝试创建函数 getInfo() 并将这些 XPath 属性中的每一个加载到数组中(如果这是人们建议的,我可能只是将其加载到表中)。我在casper.repeat 步骤中调用了该函数5 次。我收到一个解析错误。我不知道这里出了什么问题,因为这是我设置数组以抓取 URL 并将它们添加到数组中的方式(我在手册中找到):Now let’s scrape Google!

任何见解将不胜感激。

代码:

var links = [];
var utils = require('utils');
var casper = require('casper').create();
casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36');

function getInfo() {
    var info = document.querySelectorAll(fetchText((x(//*[@id="body"]/div[1]/ul[1]/li[3]/span[1]/span[2]/a)))
    + ', ' + fetchText((x(//*[@id="body"]/div[1]/ul[1]/li[2]/h2/text()))
    + ', ' + fetchText((x()))
    + ', ' + fetchText((x(//*[@id="body"]/div[1]/ul[1]/li[4]/ul/li/span[2]/a)))
    + ', ' + fetchText((x(//*[@id="body"]/div[1]/ul[1]/li[2]/h2/span)))
    + ', ' + fetchText((x(//*[@id="body"]/div[1]/ul[1]/li[5]/div[2]/ul/li[5]/span[2]/a)))
    + ', ' + fetchText((x(//*[@id="body"]/div[1]/ul[1]/li[5]/div[2]/ul/li[1]/span[2])))
    + ', ' + fetchText((x(//*[@id="key"]))
    + ', ' + fetchText((x()))
    + ', ' + fetchText((x(//*[@id="body"]/div[1]/ul[1]/li[5]/div[2]/ul/li[2]/span[2])))
    + ', ' + fetchText((x(//*[@id="body"]/div[1]/ul[1]/li[5]/div[2]/ul/li[6]/span[2]/span[2]/a)))
    + ', ' + fetchText((x())));
    return Array.prototype.map.call(info, function());
}


// This was changed.
casper.repeat(5, function() {
    this.thenOpen(bURL + links[i], function() {
        this.wait(3000);
        info = info.concat(this.evaluate(getInfo));

    });
i++;
}).run();

【问题讨论】:

  • 我删除了您的部分问题,因为它与您最初的问题无关。如果你能说得更清楚,你可以稍后再问一个新问题。

标签: javascript arrays xpath phantomjs casperjs


【解决方案1】:

您的代码存在多个问题。

1。解析错误

您看到的解析错误是这一行:

return Array.prototype.map.call(info, function());

至少应该是

return Array.prototype.map.call(info, function(){});

2。未定义的错误

问题已被编辑,因此这部分不再有意义。

这可能是一个错字,但这一行:

links = links.concat(this.evaluate(getLinks));

应该是

links = links.concat(this.evaluate(getInfo));

因为您的代码中没有getLinks 函数。

3。增量问题

问题已被编辑,因此本节不再有意义。

这样您将使用初始增量打开同一页面 5 次,因为您在 thenOpen 回调中增加了增量。 CasperJS 本质上是异步的,您只需安排步骤(如 thenOpen 调用)。

casper.repeat(5, function() {
    this.thenOpen(googleSearch + '&start=' + increment, function() { ... });
    increment += 10;
}).run();

4。异步/同步问题

您的wait(3000) 没有做任何事情,因为它是一个异步步进函数,后跟一个同步的evaluateconcat。 Step 函数将在当前 step 结束时执行(此处为 thenOpen),但同步函数会立即执行。您可以使用waitthen 回调来实现同步功能。所有then* 和所有wait* 函数都是异步步进函数。

this.thenOpen(googleSearch + '&start=' + increment, function() {
    this.wait(3000, function(){
        // aggregate results for the 'BP' search
        links = links.concat(this.evaluate(getLinks));
    });
});

5。 XPath 不是正则表达式

XPaths 表达式不像正则表达式那样原生于 javascript。没有 XPath 对象。 XPath 是字符串,因此您需要引用它们。这个

x(//*[@id="key"])

必须是

x('//*[@id="key"]')

同样x("") 不是有效的 XPath。

它必须被引用,因为在字符串之外以// 开头的所有内容都是javascript 中的注释。如果你这样做 fetchText(x(//comment)) 你会得到很多未闭合的括号。这就是 XPath 被表示为字符串的原因。

6。页面上下文

现在开始您的脚本。据我了解,您想从页面中获取一些文本并将它们作为数组发送到某处。

您在getInfo 中使用document.querySelectorAll,这表明getInfo 在页面上下文内部执行(使用evaluate),因为在页面上下文之外没有document 这样的东西。由于页面上下文执行是沙盒的,因此您不能使用大多数 CasperJS 函数。只有__utils__ 被注入到页面上下文中。 fetchText 不是其中之一,XPath 实用程序 x 也是如此,您必须将其添加到脚本的顶部:

var x = require('casper').selectXPath;

另一个奇怪的事情是你想在document.querySelectorAll 中使用选定的文本,这只有在文本实际上是 CSS 选择器的情况下才有意义,因为你正在抓取谷歌搜索,所以它们可能不是。

接下来就是

return Array.prototype.map.call(info, function(){});

将返回一个包含undefined 值的数组。

解决方案:

您不需要页面上下文。你可以完全在外面做:

function getInfo() {
    var info = [
        casper.fetchText(x('//*[@id="body"]/div[1]/ul[1]/li[3]/span[1]/span[2]/a'))
        , casper.fetchText(x('//*[@id="body"]/div[1]/ul[1]/li[2]/h2/text()'))
        , casper.fetchText(x('//*[@id="body"]/div[1]/ul[1]/li[4]/ul/li/span[2]/a'))
        , casper.fetchText(x('//*[@id="body"]/div[1]/ul[1]/li[2]/h2/span'))
        , casper.fetchText(x('//*[@id="body"]/div[1]/ul[1]/li[5]/div[2]/ul/li[5]/span[2]/a'))
        , casper.fetchText(x('//*[@id="body"]/div[1]/ul[1]/li[5]/div[2]/ul/li[1]/span[2]'))
        , casper.fetchText(x('//*[@id="key"]'))
        , casper.fetchText(x('//*[@id="body"]/div[1]/ul[1]/li[5]/div[2]/ul/li[2]/span[2]'))
        , casper.fetchText(x('//*[@id="body"]/div[1]/ul[1]/li[5]/div[2]/ul/li[6]/span[2]/span[2]/a'))
    ]; // this is your array
    return info;
}

casper.repeat(5, function() {
    this.thenOpen(googleSearch + '&start=' + increment, function() {
        this.wait(3000, function(){
            links = links.concat(getInfo());
        });
    });
    increment += 10;
}).then(function(){
    // do something with `links` here
}).run();

【讨论】:

  • 这非常有帮助。谢谢你。但是,您删除的功能不正确。我用应该在问题中的正确的替换它(它位于// This was changed. 下)。我想返回每个数组节点并检查以确保数据存储正确。另外,我添加了+ ',' +,所以当我提取数据时,我可以用它作为一种分离它的方法。为什么那行不通?我替换了你所说的,但仍然收到解析错误。
  • 我没有添加这个,因为我不明白在哪里实现它:return Array.prototype.map.call(info, function(){});。也许这就是问题所在?另外,我没有将所有代码都放在这里。有些东西我忽略了,因为我觉得它们无关紧要。这可能看起来为什么有些东西很奇怪(对不起)。最后,我有var casper = require('casper').create();...var casper = require('casper').create().selectXPath; 合法吗?
  • @user3930517 不,最后一件事不好,因为您使用 XPath 实用程序覆盖了 casper 引用。另一个解析问题在我的回答中的编号 5 下进行了描述。请花点时间了解每一点。我已经详细描述了一切。
  • 好的,谢谢。 ...不。我读了你的整个评论。这很有帮助。我觉得你不理解我。我不是在说 XPath 不是正则表达式,我是在问如何将数组节点内的每个 XPath 分开以供将来提取。
  • 好吧,我不明白您将 XPath 表达式分开以供将来提取是什么意思。如果某些内容以 // 开头,则它是 javascript 中的注释。由于所有 XPath 都以 // 开头,因此它后面的所有内容都被解析为 cmets。这意味着您最终会得到很多未闭合的括号:(//comment),这就是您收到解析错误的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-26
  • 1970-01-01
  • 2011-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多