鼓捣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 +正则筛选输出我真正需要的信息。

我觉得这玩意的坑点在于

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

上面举例的jquery网络地址是不对的,大家自己找一个

2console.log()在不同的作用域有不同的语义

这个最坑。我早上浪费了一上午在这个方法里面。用这个框架,首先要把

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

这句方法的注释默念一千遍,这个是在页面操作的。比如console.log("草泥马"),不是在我们phantomjs那个控制台里面输出那个文本,而是浏览器的。。。

所以最后在数据的获取的时候,我用了取巧的办法,onConsoleMessage+正则提取

3Unsafe 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:\Scriptsf:
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/

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

时间: 2025-01-08 17:25:48

鼓捣phantomjs,做ajax网站的信息采集的相关文章

如何做一个网站 (C# + MVC Web+ easyUI )

如何做一个网站 小编想做一个网站,采用技术为:C# + MVC Web+ easyUI 小编经过几天的学习,以及指了几位大神指导,初见效果.建立网站的思路:先列举需要用到了几个知识点,然后逐一攻克,然后再组装扩展功能知识点如下:1.登陆页面(A.图片验证码:B.登陆身份验证:C.登陆身份保存与注销)2.主窗体页面布局(A.easyUI layout页面布局:B.easyUI tree 树形菜单:C.easyUI tree tabs 展示子窗体)3.easyUI DataGrid使用,点击查询刷新

java调用phantomjs采集ajax加载生成的网页

java调用phantomjs采集ajax加载生成的网页 日前有采集需求,当我把所有的对应页面的链接都拿到手,准备开始根据链接去采集(写爬虫爬取)对应的终端页的时候,发觉用程序获取到的数据根本没有对应的内容,可是我的浏览器看到的内容明明是有的,于是浏览器查看源代码也发觉没有,此时想起该网页应该是ajax加载的.不知道ajax的小朋友可以去学下web开发啦. 采集ajax生成的内容手段不外乎两种.一种是通过http观察加载页面时候的请求,然后我们模仿该请求去得到对应的内容,第二种则是模仿浏览器行为

Linux系统下利用wget命令把整站下载做镜像网站

Linux系统下利用wget命令把整站下载做镜像网站 2011-05-28 18:13:01 | 1次阅读 | 评论:0 条 | itokit  在linux下完整的用wget命令整站采集网站做镜像 的命令是及无视网站根目录下的robots.txt限制.并且可以模拟一个正常浏览者的信息下载该网站. C/C++ Code复制内容到剪贴板 wget -m -e robots=off -U "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.

自己想要做一个网站应该怎么做

软件开发和网站开发完全是两个不同的,两个地方侧重的是不一样的.软件开发是属于手机端的开发,主要面向是安卓,ios开发,网站开发是电脑端的开发,语言分很多种:常用的有java.php..net,每个语言都有自己的特点和风格.软件开发主要分两种安卓开发和ios开发,安卓开发学习书籍书的话建议买 精通Android2 ,或者 Android2高级编程 这两本书,讲解的细致,但是一定要结合sdk来看.看完之后就可以自己动手做做项目了.对于java基础,我现在的感觉是 如果要深入学习android平台,j

别再问我做一个网站多少钱了!

「一辆车子多少钱?一个房子多少钱?」 这问题在工程师或设计师的眼里就如「一辆车子多少钱?一个房子多少钱?」,这个问题实在空泛到一个让人无法言语的境界,这也是我最常被问到的问题「做一个网站多少钱?」.说真的我大概能了解提问人的想法,或许只要说出个大概就是他们要的答案,例如说个多少X千和多少X万之间,或许我的职业病,我实在没有办法容忍这种不明确的答案. 为何我回答不了这个问题的原因大概是,最起码,给我一个参考的范例嘛,例如你问「这一台这样的车子,二手的,T牌2005年产,你估多少?」虽然提供的资讯不

作为程序员我是怎么想做一个网站的?

原文地址:http://www.cnblogs.com/phphuaibei/p/3364469.html 本身作为一个网站开发者,做网站本来是件很容易的事情,但是真正到了给自己做一个网站的时候,却不知道该如何下手了! 事件描述: 本来想做一个简单的活动日历,可以在月历视图里面查看每周活动,就怎么简单!-----一个网页的需求 突然我想到,每周的活动详情还是要一个页面,还需要对应的后天发布,管理--------一个CMS的需求 如果有活动,那么他们可能要跟帖讨论问题,还有她们也可以发活动的---

JSP+Ajax网站开发小知识

一.JSP基础 1.<select  name="love"  size="3">其中的size属性指定了列表框显示选项的条数,如果所有选项多于这个数,将会出现滚动条. 2.addCookie(Cookie  cookie)方法将其放入客户端,获取Cookie对象可调用request对象的Cookie[]  getcookies()方法. Cookie   myCookie  =  new  Cookie("name",  "

mvc中使用remote属性来做ajax验证

mvc中使用remote属性来做ajax验证比较容易 : [Remote("Action", "Controller", AdditionalFields = "Currency")] public decimal Amount {get; set;} 生成HTML: <input class="form-control" data-val="true" data-val-number="字

使用MVCPager做AJAX分页所走的弯路

使用MVCPager做AJAX分页所需要注意的地方: 1.版本问题,推荐使用2.0以上,对ajax支持才比较的好了 2.当需要使用页索引输入或下拉框以及使用Ajax分页模式时,必须用Html.RegisterMvcPagerScriptResource方法注册MvcPager客户端jQuery插件,不注册此插件则选择或输入页索引后将无法跳转,Ajax功能也无法正常运行. 具体代码:@{Html.RegisterMvcPagerScriptResource();}  注:在view中加 3.一定要