2016-11-03 11 views
8

私はCasperjsを使用してページからリンクのリストを取得し、それらのリンクのそれぞれを開いて、それらから特定のタイプのデータを配列オブジェクトに追加しようとしていますページ。casperjsは、casper.eachを使用してリンクのリストを反復処理します。

私が抱えている問題は、各リスト項目に対して実行されるループの問題です。

最初に私はlistOfLinksを元のページから入手します。この部分は機能し、長さを使用して、このリストに値が設定されていることを確認できます。

ただし、ループステートメントthis.eachを以下のように使用すると、コンソールステートメントは表示されず、casperjsはこのブロックをスキップするように見えます。

this.eachを標準のforループに置き換えると、「x.htmlのオブジェクトに新しい配列を作成する」というステートメントが1回表示され、その後コードの実行が停止するため、実行は最初のリンクを途中で終了します。 IIFEを使用してもこれは変わりません。

編集:冗長デバッグモードでは、次のことが起こる:

Creating new array object for https://example.com 
[debug] [phantom] Navigation requested: url=about:blank, type=Other, willNavigate=true, isMainFrame=true 

のでthenOpen関数に渡されたURLが空白に変更されます何らかの理由で...

私のような感じ私がここで把握していないCasperjsの非同期性については何かがあり、実際の例に向けて指摘することに感謝します。

casper.then(function() { 

    var date = Date.now(); 
    console.log(date); 

    var object = {}; 
    object[date] = {}; // new object for date 

    var listOfLinks = this.evaluate(function(){ 
    console.log("getting links"); 
    return document.getElementsByClassName('importantLink'); 
    }); 

    console.log(listOfLinks.length); 

    this.each(listOfLinks, function(self, link) { 

    var eachPageHref = link.href; 

    console.log("Creating new array in object for " + eachPageHref); 

    object[date][eachPageHref] = []; // array for page to store names 

    self.thenOpen(eachPageHref, function() { 

     var listOfItems = this.evaluate(function() { 
     var items = []; 
     // Perform DOM manipulation to get items 
     return items; 
     }); 
    }); 

    object[date][eachPageHref] = items; 

    }); 
    console.log(JSON.stringify(object)); 

}); 
+1

は実際にあなたのスクリプトですべての問題を解決する必要がある別の答えを追加しました。 – Vaviloff

答えて

3

私はあなたのスクリプトを実行するためのデモサイトとして独自のStackoverflow.comを使用することに決めました。あなたのコードで修正したマイナーなことがいくつかありました。その結果、PhantomJSの賞品の質問からコメントを得ることができました。変更された何

var casper = require('casper').create(); 

casper 
.start() 
.open('http://stackoverflow.com/questions/tagged/phantomjs?sort=featured&pageSize=30') 
.then(function() { 

    var date = Date.now(), object = {}; 
    object[date] = {}; 

    var listOfLinks = this.evaluate(function(){ 

     // Getting links to other pages to scrape, this will be 
     // a primitive array that will be easily returned from page.evaluate 
     var links = [].map.call(document.querySelectorAll("#questions .question-hyperlink"), function(link) { 
      return link.href; 
     });  
     return links; 
    }); 

    // Now to iterate over that array of links 
    this.each(listOfLinks, function(self, eachPageHref) { 

     object[date][eachPageHref] = []; // array for page to store names 

     self.thenOpen(eachPageHref, function() { 

      // Getting comments from each page, also as an array 
      var listOfItems = this.evaluate(function() { 
       var items = [].map.call(document.getElementsByClassName("comment-text"), function(comment) { 
        return comment.innerText; 
       });  
       return items; 
      }); 
      object[date][eachPageHref] = listOfItems; 
     }); 
    }); 

    // After each links has been scraped, output the resulting object 
    this.then(function(){ 
     console.log(JSON.stringify(object)); 
    }); 
}) 

casper.run(); 

page.evaluateが正しく反復するcasper.each()のために必要とされている単純な配列を返します。 hrefの属性はpage.evaluateですぐに抽出されます。また、この補正:

object[date][eachPageHref] = listOfItems; // previously assigned items which were undefined in this scope 

スクリプト実行の結果は

{"1478596579898":{"http://stackoverflow.com/questions/40410927/phantomjs-from-node-on-windows":["en.wikipedia.org/wiki/File_URI_scheme – Igor 2 days ago\n","@Igor is there something in particular you see wrong, or are you suggesting the phantom module has an incorrect URI? – Danny Buonocore 2 days ago\n","Probably windows security issue not allowing to run an unsigned program. – Vaviloff yesterday\n"],"http://stackoverflow.com/questions/40412726/casperjs-iterating-over-a-list-of-links-using-casper-each":["Thanks, this looked really promising. I made the changes but it didn't solve the problem. And I just realised that in debug mode the following happens: Creating new array object for https://example.com [debug] [phantom] Navigation requested: url=about:blank, type=Other, willNavigate=true, isMainFrame=true and then Casperjs silently fails. It seems that the correct link that gets passed into thenOpen gets changed to about:blank... – cyc665 yesterday\n"]}} 
+1

Thanks、私はあなたのスクリプトがStackoverflowや他のいくつかのWebサイトでうまく動作しています。しかし、それは私がそれを意図したウェブサイト上ではまだ機能しません。多分AJAXや他のスクリプトとは特に複雑です。結局のところ、問題はウェブサイト固有の問題だと私は思う。にもかかわらずあなたの助けをありがとう、これは非常に便利なスクリプトです。 – Laurence

3

あなたは許可されていないevaluate()機能、でDOMノードを戻ってきています。代わりに実際のURLを返すことができます。

注:評価関数の引数と戻り値は、単純なプリミティブオブジェクトでなければなりません。経験則:JSONを使ってシリアル化できるのであれば問題ありません。

クロージャ、関数、DOMノードなどは機能しません!

参考:PhantomJS#evaluate

+0

ありがとう、これは本当に有望だった。私は変更を加えましたが、問題を解決しませんでした。そして、私はちょうどデバッグモードで次のようなことが起こったことを認識しました: 'https://example.comの新しい配列オブジェクトの作成 [デバッグ] [ファントム]ナビゲーション要求:url = about:空白、type =その他、willNavigate = true、isMainFrame = true'とし、Casperjsは黙って失敗する。 thenOpenに渡される正しいリンクがabout:blankに変更されたようです... – Laurence

1

私は解決するために、正しく問題を理解していれば、アイテム[]にグローバルスコープを与えます。あなたのコードでは、私は次のようにしたでしょう:

var items = []; 
this.each(listOfLinks, function(self, link) { 

    var eachPageHref = link.href; 

    console.log("Creating new array in object for " + eachPageHref); 

    object[date][eachPageHref] = []; // array for page to store names 

    self.thenOpen(eachPageHref, function() { 

     this.evaluate(function() { 
     // Perform DOM manipulation to get items 
     items.push(whateverThisItemIs); 
     }); 
    }); 

希望します。

関連する問題