鼓捣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
PhantomJS 不支持哪些操作?
http://www.zhihu.com/question/26653233Using PhantomJS to make your AJAX web applications crawlable by Google
http://blog.istepaniuk.com/phantomjs-to-make-your-ajax-web-crawlable-by-google/
咦,貌似文中有一些坑没填平,等下次吧,哈哈。
最新文章
- 模拟器报Installation error: INSTALL_FAILED_CONTAINER_ERROR解决方法
- NOIP2013pj小朋友的数字[DP 最大子段和]
- 移动App的REST API设计实践
- 邮箱格式验证demo
- jquery.pagination.js分页插件的使用
- duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复
- POJ3080——Blue Jeans(暴力+字符串匹配)
- 使用WIF实现单点登录Part III —— 正式实战 -摘自网络
- .net常考面试题
- Objective-C 链式编程思想
- JavaScript 作用域 匿名函数 模仿块级作用域(私有作用域)
- NSNumber(把数字存进数组字典等的问题)
- JSP userBean setProperty getProperty指令使用
- Vivado Turtorial 01 —— 使用vivado中debug功能(类似ISE中ChipScope)
- nodejs 函数 :html2js
- linux运维掌握不熟练命令用法记录
- 来自极客头条的 35 个 Java 代码性能优化总结
- Java基础知识(JAVA之泛型)
- [LeetCode&;Python] Problem 561. Array Partition I
- eclipse中java build path下 allow output folders for source folders 无法勾选,该如何解决 eclipse中java build path下 allow output folders for source folders 无法勾选,
热门文章
- ORM-Dapper快速学习
- Hbuilder系列索引
- Restframework 分页器 Pagnation 组件实例-5
- openstack 创建虚拟机的时候报错: Failed to allocate the network(s), not rescheduling.].
- 【AUTO Uninstaller 中文版-详细使用教程】AUTODESK系列软件MAYA/CAD/3DSMAX/INVENTOR终极完美修复卸载工具 Windows x64位 【原创搬家】
- Good Bye 2017(送命场)
- Flask从入门到精通之链接的使用
- Java MVC和三层架构
- day 69crm(6) stark组件 action 和 多层过滤效果
- python3异常处理 try