版权所有: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游戏排行信息

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

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

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

    如何做一个网站 小编想做一个网站,采用技术为:C# + MVC Web+ easyUI 小编经过几天的学习,以及指了几位大神指导,初见效果.建立网站的思路:先列举需要用到了几个知识点,然后逐一攻克,然 ...

  2. 介绍一款非常适合做微网站并且免费的CMS系统

    在微网站火热的今天,寻找一款具备 web app功能的CMS系统能够大大提高我们的工作效率,eBSite升级到3.0后,开始支持web app 皮肤,也就是创建一个站点,会同时绑定一个PC版皮肤与一个 ...

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

    Linux系统下利用wget命令把整站下载做镜像网站 2011-05-28 18:13:01 | 1次阅读 | 评论:0 条 | itokit  在linux下完整的用wget命令整站采集网站做镜像 ...

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

    java调用phantomjs采集ajax加载生成的网页 日前有采集需求,当我把所有的对应页面的链接都拿到手,准备开始根据链接去采集(写爬虫爬取)对应的终端页的时候,发觉用程序获取到的数据根本没有对应 ...

  5. ASP.NET CORE做的网站运行在docker实践

    用VS2017 建立了 DotNet Core 2.2 的网站后,如何转移到 Docker 下运行? 下面分两种方式来实践: 1.直接手动命今行,将本机目录映射进Docker,运行网站.2.制作 Im ...

  6. ASP.NET MVC 做的网站项目

    感谢博客园团队日夜为广大需要获取知识人们所做的奉献 博客园团队您们辛苦了 ASP.NET MVC 实现有论坛功能的网站(有iis发布网站 这是之前写的... www.lazyfitness.cn 经过 ...

  7. [Web 前端] 如何在React中做Ajax 请求?

    cp from : https://segmentfault.com/a/1190000007564792 如何在React中做Ajax 请求? 首先:React本身没有独有的获取数据的方式.实际上, ...

  8. [Python爬虫] 之一 : Selenium+Phantomjs动态获取网站数据信息

    本人刚才开始学习爬虫,从网上查询资料,写了一个利用Selenium+Phantomjs动态获取网站数据信息的例子,当然首先要安装Selenium+Phantomjs,具体的看 http://www.c ...

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

    使用MVCPager做AJAX分页所需要注意的地方: 1.版本问题,推荐使用2.0以上,对ajax支持才比较的好了 2.当需要使用页索引输入或下拉框以及使用Ajax分页模式时,必须用Html.Regi ...

随机推荐

  1. LinkedBlockingQueue源码解析(3)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 4.3.public E take() throws InterruptedException 原理: 将队 ...

  2. linux常用命令大全(linux基础命令入门到精通+命令备忘录+面试复习+实例)

    作者:蓝藻(罗蓝国度) 创建时间:2018.7.3 编辑时间:2019.4.29 前言 本文特点 授之以渔:了解命令学习方法.用途:不再死记硬背,拒绝漫无目的: 准确无误:所有命令执行通过(环境为ce ...

  3. 如何在Qt资源文件中包含和释放exe等各种类型文件?

    操作系统:Windows 10 X64 企业版 Qt: 5.8.0 QtCreater: 4.2.1 刚刚开始学习Qt,不断遇到困难和挑战,前几天在各个QQ群里询问如何在Qt的资源文件中包含和释放ex ...

  4. 二,mysql优化——sql优化基本概念

    1,SQL优化的一般步骤 (1)通过show status命令了解各种SQL执行效率. (2)通过执行效率较低的SQL语句(重点select). (3)通过explain分析低效率的SQL语句的执行情 ...

  5. javaWeb登录注册页面

    简单的登陆注册页面 1.配置JDBC驱动连接数据库 2. 配置struts2框架 3. 利用1 2完成登录页面, 注意做到不耦合,即servlet Api和控制器完全脱离) 4. 利用1 2 制作注册 ...

  6. jquery, jquery-ui, requirejs, bootstrap 的关系理解

    jquery 是 基于 javascript 的一个语法衍生,更方便操作dom, 事件,css 整体来说更好用,更简洁. jquery-ui 是基于 jquery 实现的各种更好看,交互更友好的的界面 ...

  7. sublime text3 --前端工程师必备

    sublime text3 --前端工程师必备神器 导读目录: 下载与Emmet插件安装 sublime text3 中cssrem安装与使用 sublime Text 3的中文文件名显示为方框的问题 ...

  8. Android 中的冷启动和热启动

    App的Activity退出之后,应用的进程并不会被杀死,而是保留在那里.当再次打开App的Activity时,会从已有的进程中创建Activity,是为“热启动”.若打开Activity时没有进程, ...

  9. Annotate类

    在Annotate类中有个Annotator接口,定义如下: /** A client that has annotations to add registers an annotator, * th ...

  10. 前端通信:ajax设计方案(四)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组

    马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...