鼓搗phantomjs,做ajax網站的信息采集


 版權所有:http://www.cnblogs.com/zeusro/ 

引用不給稿費的,切你jj

准備工作: 

1phantomjs的安裝

2 phantomjs環境變量的配置

需求:

采集手機淘寶某店鋪的所有商品的ID

難點:

1頁面是ajax的,不能用傳統方法(webrequest,正則提取)提取數據,所以這才是我用 phantomjs的原因 

那么對於這部分內容,除了要確保加載頁面完成后,還要等待其所有資源加載完畢,確保DOM是符合我們預期的,才開始采集。

2模塊化

加載到nodejs里面,用於批量采集。

方法:把變動的參數做成

3淘寶的反采集

4數據的持久化

開工:

我以http://shop100338207.m.taobao.com/#list 舉例。

var webpage = require('webpage'), page = webpage.create();
var fs = require('fs');
page.viewportSize = { width: 1024, height: 800 };
page.clipRect = { top: 0, left: 0, width: 1024, height: 800 };
page.settings = {
    javascriptEnabled: true,
    loadImages: true,
    webSecurityEnabled: false,
    userAgent: 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36 LBBROWSER'
    //要指定谷歌ua,我用火狐無法瀏覽
};
var lastReceived = new Date().getTime();
var requestCount = 0;
var responseCount = 0;
var requestIds = [];
var startTime = new Date().getTime();

page.onLoadStarted = function () {
    page.startTime = new Date();
};//獲取頁面開始加載的時間



page.open('http://shop100338207.m.taobao.com/#list', function () {
    console.log('start');
    if (status === 'fail') {
        console.log('open page fail!');
    } else {
        waitFor(function () {
            return page.evaluate(function () {
                //判斷頁面加載完成的信號,
                return $("a:first-child", ".goods-list-items").length > 0;
            });
        }, function () {
            //頁面加載完成后我們的DOM操作,
            //引入外部js庫
            page.includeJs("http://xxxx/jquery-1.9.1.min.js", function () {
                page.evaluate(function () { //操作頁面事件
                    console.log("jQuery version:" + jQuery.fn.jquery);
                    $("a", ".goods-list-items").each(function () {
                        console.log($(this).attr("href"));
                    });
                });
                setTimeout(function () {
                    page.render('../snapshot/taoba2o.png');
                }, 2000);
                //console.log()
                var t = Date.now() - page.startTime; //頁面加載完成后的當前時間減去頁面開始加載的時間,為整個頁面加載時間
                console.log('firstLoadPage time :' + t + 'ms');
                console.log("end");
                setTimeout(function () {
                    page.close();
                    phantom.exit();
                }, 0);
            });
        });
    }
});

function screan(filename) {
    page.render(filename);
}


function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
        start = new Date().getTime(),
        condition = false,
        interval = setInterval(function () {
            if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
                // If not time-out yet and condition not yet fulfilled
                screan('../snapshot/taobao.png');
                condition = (typeof (testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
            } else {
                if (!condition) {
                    // If condition still not fulfilled (timeout but condition is 'false')
                    console.log("'waitFor()' timeout");
                    phantom.exit(1);
                } else {
                    // Condition fulfilled (timeout and/or condition is 'true')
                    console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
                    typeof (onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 250); //< repeat check every 250ms
};

page.onCallback = function (data) {
    console.log('CALLBACK: ' + JSON.stringify(data));
    // Prints 'CALLBACK: { "hello": "world" }'
};


page.onAlert = function (msg) {
    console.log('ALERT: ' + msg);
};

page.onConsoleMessage = function (msg, lineNum, sourceId) {
    console.log('CONSOLE:' + msg);
    //var d = "http://h5.m.taobao.com/awp/core/detail.htm?id=43064483679";
    var re = new RegExp("[/?id=]+[0-9]{11}");
    var arr = (msg.match(re));
    //if (arr != null) {
    //    console.log(msg.match(re)[0].replace("?id=", ""));
    //}
};


page.onError = function (msg, trace) {
    var msgStack = ['ERROR: ' + msg];
    if (trace && trace.length) {
        msgStack.push('TRACE:');
        trace.forEach(function (t) {
            msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function + '")' : ''));
        });
    }

    console.error(msgStack.join('\n'));

};

 

扯淡

我的算法是,用某個元素的出現作為頁面加載完成的信號。在頁面加載完成,我用dom處理把數據輸出到console.log().js那邊用page.onConsoleMessage +正則篩選輸出我真正需要的信息。

我覺得這玩意的坑點在於

引入jquery(includeJs ,injectJs傻傻分不清啊有木有)並且運用其方法

上面舉例的jquery網絡地址是不對的,大家自己找一個

console.log()在不同的作用域有不同的語義

這個最坑。我早上浪費了一上午在這個方法里面。用這個框架,首先要把

page.evaluate(function () {} //操作頁面事件

這句方法的注釋默念一千遍,這個是在頁面操作的。比如console.log("草泥馬"),不是在我們phantomjs那個控制台里面輸出那個文本,而是瀏覽器的。。。

所以最后在數據的獲取的時候,我用了取巧的辦法,onConsoleMessage+正則提取

 Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL file://./embed_images.js. Domains, protocols and ports must match.

這個影響視覺而已,屏蔽這JB玩意用下面的代碼退出就行了

setTimeout(function(){
    phantom.exit();
}, 0);

特別的裝逼技巧

因為我沒有模塊化,只是單純一個文件運行,一遍情況下,每次開CMD,然后balala很麻煩的,做成批處理(.bat)打開就可以了

 

cd  F:\Scripts\
f:
phantomjs test.js
pause

 

版權所有:http://www.cnblogs.com/zeusro/ 

引用不給稿費的,切你jj 

參考鏈接:

中文入門參考

http://my.oschina.net/rasine/blog/335997#OSC_h3_6

phantomjs使用說明

http://www.zhouhua.info/2014/03/19/phantomjs/

waitforjs

https://github.com/ariya/phantomjs/blob/master/examples/waitfor.js

 Does Phantom.js capture all AJAX?

http://stackoverflow.com/questions/14747643/does-phantom-js-capture-all-ajax

Using PhantomJS to embed all images of a webpage produces warnings but works

http://stackoverflow.com/questions/26608391/using-phantomjs-to-embed-all-images-of-a-webpage-produces-warnings-but-works

PhantomJS 不支持哪些操作?
http://www.zhihu.com/question/26653233

Using PhantomJS to make your AJAX web applications crawlable by Google

http://blog.istepaniuk.com/phantomjs-to-make-your-ajax-web-crawlable-by-google/

 借助Nodejs在服務端使用jQuery采集17173游戲排行信息

 

咦,貌似文中有一些坑沒填平,等下次吧,哈哈。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM