2

我是PhantomJS的新手,試圖捕獲Trade Me的主頁。這裏是我到目前爲止的代碼:在所有內容異步加載後捕獲頁面

var page = require('webpage').create(); 

page.open('http://trademe.co.nz', function() { 

    // Checks for bottom div and scrolls down from time to time 
    window.setInterval(function() { 
     // Checks if there is a div with class=".has-more-items" 
     // (not sure if this is the best way of doing it) 
     // var count = page.content.match(/class=".site-footer"/g); 
     var footer_visible = page.evaluate(function() { 
     return $('.site-footer').is(':visible'); 
     }); 

     if(!footer_visible) { // Didn't find 
     console.log('Scrolling'); 
     page.evaluate(function() { 
      // Scrolls to the bottom of page 
      window.document.body.scrollTop = document.body.scrollHeight; 
     }); 
     } 
     else { // Found 
     console.log('Found'); 
     // Do what you want 
     window.setTimeout(function() { 
      console.log('Capturing'); 
      page.render('phantom-capture.png', {format: 'png'}); 
      phantom.exit(); 
     }, 10000); 
     } 
    }, 1000); // Number of milliseconds to wait between scrolls 

}); 

有幾件事情是難不倒我:

  1. 永遠不會被打印的字Scrolling
  2. 它最終得到Found,並且該單詞被打印10次。我認爲這是因爲它包含在setInterval塊中,間隔爲1秒,並且由setTimeout引起的等待時間爲10秒?
  3. 頁面最終呈現給PNG文件,但這些異步加載的面板的內容仍爲空,並顯示Loading...消息。

我是新來的這一切,我的Javascript知識是很生疏。

回答

2

瑞安多爾蒂提供了很好的解釋,爲什麼console.log('Scrolling');不會被調用,你想通了自己爲什麼Found打印10倍!

我想談談如何處理這些ajaxified頁面。通常當你使用這些網站時,你可以找出一個判斷頁面是否已經加載的標準,或者至少是你需要的部分(儘管有時候,正如Ryan正確地指出的那樣,它可能非常困難,尤其是如果有的話在頁面上有很多外部資源和/或內聯框)。

在這種情況下,我想我們可以決定頁面在沒有「加載」標籤時加載。所以我們關閉JavaScript並檢查這些標籤。原來他們是<div class="carousel-loading-card">。這意味着我們只需要等到他們走了。但要觸發它們的加載,我們必須模擬頁面滾動。在PhantomJS中,您可以通過更改page.scrollPosition設置來「本地」執行此操作。

var page = require('webpage').create(); 

// Let's not confuse the target site by our default useragent 
// and native viewport dinemsions of 400x300 
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0'; 
page.viewportSize = { width: 1280, height: 1024 }; 

var totalHeight, scroll = 0; 

page.open('http://trademe.co.nz', function(){ 

    totalHeight = page.evaluate(function(){ 
     return $(document).height(); 
    }); 

    wait(); 

}); 

function wait() 
{ 
    var loading = page.evaluate(function(){ 
     return $(".carousel-loading-card").length; 
    }); 

    if(loading > 0) { 

     if(scroll <= totalHeight) 
     { 
      scroll += 200; 

      page.scrollPosition = { 
       top: scroll, 
       left: 0 
      }; 

      page.render('trademe-' + (new Date()).getTime() + '.jpg'); 
     } 

     console.log(loading + " panels left. Scroll: " + scroll + "px"); 
     setTimeout(wait, 3000);   

    } else { 
     // Restore defaults to make a full page screenshot at the end 
     page.scrollPosition = { top: 0, left: 0 };   
     page.render('trademe-ready.png'); 
     phantom.exit(); 
    } 

} 
+1

檢查'carousel-loading-card'項目的好主意! –

3

您正遇到如何判斷網頁何時完全加載的常見問題。這實際上很難!我很久以前寫了一篇關於這個問題的博文:https://sorcery.smugmug.com/2013/12/17/using-phantomjs-at-scale/(請參閱問題1)以下是我對您的代碼和問題的反饋:

首先,您不需要滾動以瞭解頁腳是否jQuery的:visible選擇器將返回true,如果元素佔用文檔中的空間,而不是它在視口內:https://api.jquery.com/visible-selector/。一般來說,我也不會使用PhantomJS的視口可見性,因爲它確實無法運行。

其次,當根據PhantomJS頁面已經「裝」的page.open()回調將閃光。這個主要是意味着它已經完全加載了HTML及其包含的所有資源。但是,這並不意味着加載了異步加載的內容。

第三,我相信你看到「找到」十次,因爲你正在使用window.setInterval檢查使用window.setTimeout做渲染頁腳輸出。發生了什麼事是這樣的:

  1. PhantomJS開始加載頁面,並呼籲您的回調傳遞到page.open()一旦加載。
  2. 頁腳是負載可見的,所以footer_visible是真的
  3. 第一時間「發現」塊運行。這會設置一個函數,在將來呈現頁面的10秒內運行,然後退出。但因爲它使用了window.setTimeout,所以你的腳本還在繼續。
  4. 腳本繼續,並且由於您的外部函數設置爲每秒運行一次,它會再次運行!它檢查頁腳,找到它並設置一個函數,以10秒的速度運行以渲染頁面。它繼續這樣做10秒。
  5. 10秒後,第一個設置爲渲染頁面的函數執行此操作,然後告訴PhantomJS退出。這會殺死在10秒內設置爲渲染頁面的所有其他功能。

如果你真的想渲染頁面時頁腳在文檔中,這裏是你的固定碼:

var page = require('webpage').create(); 

page.open('http://trademe.co.nz', function() { 

    window.setInterval(function() { 
     var footer_visible = page.evaluate(function() { 
      return $('.site-footer').is(':visible'); 
     }); 

     if(footer_visible) { 
      page.render('phantom-capture.png', {format: 'png'}); 
      phantom.exit(); 
     } 
    }, 1000); 
}); 

然而,這並不會渲染,一旦所有的內容都加載,這是一個更難的問題。請閱讀我的博客文章鏈接到上面有關如何做到這一點的提示。這是一個非常困難的問題。如果你不想閱讀我的博客文章,這是一個TLDR;

通過大量的人工測試和QA我們最終來到一個 解決方案,我們跟蹤每一個HTTP請求PhantomJS使得 和觀看交易的每一步(啓動,進展,結束 失敗)。只有每一個請求完成(或失敗等) 我們開始'等待'。我們讓頁面500ms開始製作更多 請求或完成將內容添加到DOM。超時後,我們 假設頁面已完成。

+0

[此問題](http://stackoverflow.com/q/11340038/1816580)已經涵蓋了您。我發現這些答案有最好的主意:[1](http://stackoverflow.com/a/21401636/1816580),[2](http://stackoverflow.com/a/38468106/1816580),[3] ](http://stackoverflow.com/a/38132403/1816580)。 –