【问题标题】:how to scrape links with phantomjs如何使用 phantomjs 抓取链接
【发布时间】:2012-12-19 02:01:40
【问题描述】:

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

我曾尝试过使用CasperJS,这可能是为此设计的更好。

【问题讨论】:

  • 我建议查看cheerio。它非常适合抓取网页的任务,其遍历/操作 API 与 jQuery 非常相似。

标签: javascript beautifulsoup phantomjs casperjs


【解决方案1】:

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

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

【讨论】:

  • +1 希望这在文档中明确说明。作为新手,我花了几个小时才找到这个答案! :-(
  • Uhmmm...你的意思是CasperJS文档图中的“返回原生类型”箭头还是PhantomJS文档中的注释“参数和返回值评估函数必须是一个简单的原始对象。[...]”(注意:CasperJS 中指向WebPage.evaluate 的链接是错误的)?我确定我遗漏了一些东西,因为图表中的脚本很容易被监督,而且作为新手,我天真地认为我可以不用 PhantomJS 文档。无论如何感谢这个出色的工具。
【解决方案2】:

您的代码的唯一问题是您不了解 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);

【讨论】:

    【解决方案3】:

    这是我最近编写的一些使用 PhantomJs 抓取 url 的代码,如果您只提供一个 URL,它将在页面上显示所有 URL,如果您提供一个参数 class|id 后跟一个“类/ID 名称”它将仅显示类/id 的 url。

    ////////////////////////////////////////////////////////// 
    /////  PhantomJS URL Scraper v.1.3 ///// 
    // 
    // Copyrighted by +A.M.Danischewski  2016+ (c)
    // This program may be reutilized without limits, provided this 
    // notice remain intact. 
    // 
    // Usage: phantomjs phantom_urls.js <URL> [["class"|"id"] [<query id/class name>]]
    //
    //   Argument 1: URL -- "https://www.youtube.com/watch?v=8TniRMwL2Vg" 
    //   Argument 2: "class" or "id" 
    //   Argument 3: If Argument 2 was provided, "class name" or "id name" 
    // 
    // By default this program will display ALL urls from a user supplied URL.  
    // If a class name or id name is provided then only URL's from the class 
    // or id are displayed.  
    //  
    /////////////////////////////////// 
    
    var page = require('webpage').create(), 
        system = require('system'),
        address;
    
    if (system.args.length === 1) {
      console.log(' Usage: phantomjs phantom_urls.js <URL> [["class"|"id"] [<query id/class name>]]');
      phantom.exit();
    }
    
    address = system.args[1];
    querytype= system.args[2];
    queryclass = system.args[3];
    page.open(address, function(status) {
      if (status !== 'success') {
        console.log('Error loading address: '+address);
      } else {
       //console.log('Success! In loading address: '+address);   
      }
    });
    
    page.onConsoleMessage = function(msg) {
      console.log(msg);
    }
    
    page.onLoadFinished = function(status) {
       var dynclass="function() { window.class_urls = new Array(); window.class_urls_next=0; var listings = document.getElementsByClassName('"+queryclass+"'); for (var i=0; i < listings.length; i++) { var el = listings[i]; var ellnks=[].map.call(el.querySelectorAll('a'),function(link) {return link.getAttribute('href');}); var elhtml=el.innerHTML; window.class_urls.push(ellnks.join('\\n')); }; return window.class_urls;}"; 
       var    dynid="function() { window.id_urls = new Array(); window.id_urls_next=0; var listings = document.getElementById('"+queryclass+"'); var ellnks=[].map.call(listings.querySelectorAll('a'),function(link) {return link.getAttribute('href');}); var elhtml=listings.innerHTML; window.id_urls.push(ellnks.join('\\n'));  return window.id_urls;}";  
       var  allurls="function() { var links = page.evaluate(function() { return [].map.call(document.querySelectorAll('a'), function(link) { return link.getAttribute('href'); };); };); console.log(links.join('\\n')); }"; 
       var page_eval_function="";  
       if (querytype === "class") {
       console.log(page.evaluate(dynclass).toString().replace(/,/g, "\n")); 
       } else if (querytype === "id") {
       console.log(page.evaluate(dynid).toString().replace(/,/g, "\n")); 
       } else { 
       var links = page.evaluate(function() {
            return [].map.call(document.querySelectorAll('a'), function(link) {
                return link.getAttribute('href');
            });
        });    
           console.log(links.join('\n'));
       }             
       phantom.exit();
    };
    

    【讨论】:

      猜你喜欢
      • 2016-04-29
      • 2023-04-03
      • 1970-01-01
      • 2014-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-20
      相关资源
      最近更新 更多