簡體   English   中英

通過在PhantomJS中循環來抓取多個URL

[英]Scraping multiple URLs by looping in PhantomJS

我正在使用PhantomJS抓取某些網站,因此使用r提取信息。 我正在關注教程。 單個頁面的所有功能都可以正常運行,但是我找不到任何有關如何自動化多個頁面的簡單教程。 到目前為止,我的實驗是:

var countries = [ "Albania" ,"Afghanistan"];
var len = countries.length;
var name1 = ".html";
var add1 = "http://www.kluwerarbitration.com/CommonUI/BITs.aspx?country=";
var country ="";
var name ="";
var add="";


for (i=1; i <= len; i++){

    country = countries[i]
    name = country.concat(name1)
    add = add1.concat(name1)

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

    var fs = require('fs');
    var path = name

    page.open(add, function (status) {
        var content = page.content;
        fs.write(path,content,'w')
        phantom.exit();
    });

}

我在運行代碼時似乎沒有任何錯誤,該腳本僅為第二個國家/地區創建了一個html文件,其中包含有關我感興趣的小表的頁面異常的所有信息。

我試圖從類似的問題中收集一些信息。 但是,同樣因為我找不到簡單的可復制示例,所以我不理解自己在做什么錯。

主要問題似乎是您退出得太早。 您正在循環創建多個page實例。 由於PhantomJS是異步的,因此對page.open()的調用立即存在,並執行下一個for循環迭代。

for循環非常快,但是Web請求很慢。 這意味着即使在加載第一頁之前,循環也已完全執行。 這也意味着,加載的第一頁也將退出PhantomJS,因為你打電話phantom.exit()在每個那些page.open()回調。 我懷疑第二個URL由於某種原因會更快,因此總是被寫入。

var countFinished = 0, 
    maxFinished = len;
function checkFinish(){
    countFinished++;
    if (countFinished + 1 === maxFinished) {
        phantom.exit();
    }
}

for (i=1; i <= len; i++) {
    country = countries[i]
    name = country.concat(name1)
    add = add1.concat(country)

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

    var fs = require('fs');
    var path = name

    page.open(add, function (status) {
        var content = page.content;
        fs.write(path, content,'w')
        checkFinish();
    });
}

問題在於您要創建很多page實例而沒有清理。 完成使用后,應關閉它們:

for (i=1; i <= len; i++) {
    (function(i){
        country = countries[i]
        name = country.concat(name1)
        add = add1.concat(country)

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

        var fs = require('fs');
        var path = name

        page.open(add, function (status) {
            var content = page.content;
            fs.write(path, content,'w');
            page.close();
            checkFinish();
        });
    })(i);
}

由於JavaScript具有函數級作用域,因此您需要使用IIFE在page.open()回調中保留對正確page實例的page.open() 有關此問題的更多信息,請參見此問題: 問:循環內的JavaScript閉合–簡單的實際示例

如果您不想在此之后進行清理,則應在所有這些URL上使用相同的page實例。 我已經有一個關於在這里執行此操作的答案: A:遍歷url以執行相同的操作

鑒於我對js的了解非常有限,我考慮了解決該問題的方法。 我仍然對正確解決問題感興趣,但是我預計這將花費一些時間。

目前,我通過在R中進行一些實驗性工作來獲得所需的結果。我沒有在js中運行循環,而是使用R編寫了多個單個js代碼,從而繞過了“ phantomjs是異步問題”。

訣竅在於使用帶有參數quote = F的write.table導出js代碼塊,並使用.js作為文件擴展名,以便將其正確識別為js文件。 我猜想這種解決方法將適用性限制在其他類似的任務上,但是它仍然可以幫助某人。 評論非常感謝。

countries <- c("Afghanistan", "Albania", "Algeria")

for (i in unique(countries)){

  df <- data.frame(lines=character(11), 
                   stringsAsFactors=FALSE) 
  outputline <- paste("var path = '", i, ".html'" , sep="")
  inputline <- paste("page.open('http://www.kluwerarbitration.com/CommonUI/BITs.aspx?country=", i ,"', function (status) {", sep="")
  df$lines[1] <- "var webPage = require('webpage');"
  df$lines[2] <- "var page = webPage.create();"
  df$lines[3] <- "var fs = require('fs');"
  df$lines[4] <- ""
  df$lines[5] <- outputline
  df$lines[6] <- ""
  df$lines[7] <- inputline
  df$lines[8] <-  "  var content = page.content;"
  df$lines[9] <-  "  fs.write(path,content,'w')"
  df$lines[10] <-  "  phantom.exit();"
  df$lines[11] <-  "});"

  write.table(df, paste(i, ".js", sep = ""), sep=" ", quote=F, row.names=F, col.names=F)

}

library(rvest)
library(stringr)
library(plyr)
library(dplyr)
library(ggvis)
library(knitr)
options(digits = 4)


 #run all individual javascript files
index <- 1
for (i in countries){
 javacode <- paste0("./phantomjs", sep=" ",  countries, ".js")
  system(javacode[index])
 index <- index + 1
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM