如何用phantomjs刮取链接

joh*_*ual 14 javascript beautifulsoup phantomjs casperjs

可以PhantomJS使用的替代BeautifulSoup

我正在尝试搜索Etsy并访问所有链接.在Python中,我知道如何做到这一点(使用BeautifulSoup)但今天我想知道我是否可以使用PhantomJS做同样的事情.我没有走得太远.

该脚本应在Etsy上搜索"hello kitty"并返回所有产品 <a class="listing-thumb" href=...></a>并在控制台中打印.理想情况下,我稍后会访问它们并获取我需要的信息.现在它只是冻结了.有任何想法吗?

var page = require('webpage').create();
var url = 'http://www.etsy.com/search?q=hello%20kitty';

page.open(url, function(status){
    // list all the a.href links in the hello kitty etsy page
    var link = page.evaluate(function() {
        return document.querySelectorAll('a.listing-thumb');
    });
    for(var i = 0; i < link.length; i++){ console.log(link[i].href); }
    phantom.exit();
});
Run Code Online (Sandbox Code Playgroud)

我玩过CasperJS玩具,可能更适合这个.

NiK*_*iKo 35

PhantomJS evaluate()无法序列化并返回复杂对象,如HTMLElements或NodeLists,因此您必须将它们映射到可序列化的东西:

var page = require('webpage').create();
var url = 'http://www.etsy.com/search?q=hello%20kitty';

page.open(url, function(status) {
    // list all the a.href links in the hello kitty etsy page
    var links = page.evaluate(function() {
        return [].map.call(document.querySelectorAll('a.listing-thumb'), function(link) {
            return link.getAttribute('href');
        });
    });
    console.log(links.join('\n'));
    phantom.exit();
});
Run Code Online (Sandbox Code Playgroud)

注意:这里我们使用[].map.call()以便将a NodeList视为标准Array.

  • +1希望这在文档中明确说明.作为新手,我花了几个小时才找到这个答案!:-( (7认同)
  • 嗯......你的意思是CasperJS文档图中的"*return native types*"箭头或PhantomJS文档中的注释"*参数和evaluate函数的返回值必须是一个简单的原始对象.[... ]*"(注意:CasperJS中的链接到[WebPage.evaluate](https://github.com/ariya/phantomjs/wiki/API-Reference-WebPage#evaluatefunction-arg1-arg2--object)是错误的)?我确定我错过了一些东西,因为图中的脚本很容易被监督,而且作为新手,我天真地认为我可以不用PhantomJS doc.无论如何,谢谢这个神奇的工具. (2认同)

Dar*_*kas 4

您的代码的唯一问题是您不了解 phantomjs 范围。您有幻像范围和页面范围。您尝试将 JavaScript DOM 对象引用(无法序列化)从页面范围(page.evaluate 在页面范围中运行)返回到幻像主范围。我认为这是不可能的。下面是有效的代码:

var page = require('webpage').create();
var url = 'http://www.etsy.com/search?q=hello%20kitty';

// for debug (to see if page returns status code 200)
page.onResourceReceived = function(response) {
    if (response.url === url) {
        console.log('Resorce: "' + response.url + '" status: '  + response.status);

        if (response.status === 200) {
            console.log(response.url);
            for (var i = 0; i < response.headers.length; i++) {
                console.log(response.headers[i].name + ': ' + response.headers[i].value);
            }
        }
    }
};

page.onLoadFinished = function(status){
    console.log('Status: ' + status);

    console.log('Starting evaluate...');
    var links = page.evaluate(function() {
        var nodes = [],
            matches = document.querySelectorAll("a.listing-thumb");

            for(var i = 0; i < matches.length; ++i) {
                nodes.push(matches[i].href);
            }

            return nodes;
    });
    console.log('Done evaluate... count: ' + links.length);

    if (links && links.length > 0) {
        for(var i = 0; i < links.length; ++i) {
            console.log('(' + i + ') ' + links[i]);
        }
    } else {
        console.log("No match found!");
    }

    phantom.exit(0);
};

page.open(url);
Run Code Online (Sandbox Code Playgroud)