All Posts

sftp没有关闭session导致服务器sshd进程未关闭

项目中需要用Sftp上传下载文件,通过jsch中的sftp实现。代码上了服务器之后,发觉服务器多了很多进程没有被关闭。 连接sftp代码: protected boolean connectToServer() { try { JSch jsch = new JSch(); jsch.getSession(userName, hostname, port); Session sshSession = jsch.getSession(userName, hostname, port); logger.debug("HostName:" + hostname + "|Port:" + port); logger.debug("Session created"); sshSession.setPassword(password); Properties sshConfig = new Properties(); sshConfig.put("StrictHostKeyChecking", "no"); sshSession.setConfig(sshConfig); sshSession.setTimeout(TIMEOUT); //ms sshSession.connect(); sftp = (ChannelSftp) sshSession.openChannel("sftp"); sftp.connect(); if (!sftp.isConnected()) { logger.error("Failed to connect FTP server " + hostname); return false; } logger.debug("Username:" + userName + "|Password:" + password); } catch (Exception ex) { logger.

javascript中的对象字面量为啥这么酷

原文链接 : Why object literals in JavaScript are cool 原文作者 : Dmitri Pavlutin 译者 : neal1991 个人主页:http://neal1991.pythonanywhere.com 在ECMAScript 2015之前,Javascript中的对象字面量(也称为对象初始化器)是非常基础的。能够定义两种类型的属性: 成对出现的名称以及相应的值{ name1: value1 } Getters { get name(){..} } 以及setters { set name(val){..} } 可以用于动态的属性值。 遗憾的是,这个对象字面量可能会出现下面这样的情况: var myObject = { myString: 'value 1', get myNumber() { return this._myNumber; }, set myNumber(value) { this._myNumber = Number(value); } }; myObject.myString; // => 'value 1' myObject.

javascript中无法将string转化为json对象

在一次项目之中,我要对请求的相应做一些处理,得到的响应差不多是这中格式‘{total:1,result:[{“age”:1}]}’.可以看到我拿到的这个相应和JSON的格式是非常相似的,一开始我认为只要用JSON.parse进行转化,但是这始终会报错,无法进行转化。后来我用了个笨办法把前面的东西都去掉了拿到’[{“age”:1}]‘进行转化。 后来我又找一找这个问题的原因,原来是我这个字符串中的key没有用双引号进行包裹,这并不是一个合法的JSON格式,它可以被人为是一个Javascript对象,但还不是一个合法的JSON,所以无法解析。JSON对象是由对象成员组成,而成员是由key-value键值组成。key值是一个字符串,字符串由unicode字符组成,用双引号包围,用反斜杠转义。可以是单个字符。 但是在现实应用中,很少有人知道JSON里的key需要双引号来包裹的,浏览器里面的属性都是没有双引号的,从而返回的结果无法解析。 知道问题的原因,就自然而然有相应的解决办法了。第一个办法就是本办法,手工加上双引号,也就是用正则表达式匹配;另外一个方法就是用eval直接执行, var obj = eval('('+str')') 不过你需要了解这个str里面到底有什么,这样才能防止一些恶意程序,避免带来安全问题。

判断数组中元素多个属性是否重复

js中判断数组元素的重复的方法有很多,可以用hash的方法或者排序之后再进行比较,但是我们这里说的case是这样的。假设我有一个数组[{name:'neal',age:'18'},{name:'neal',age:'18'},{name:'jane',age:'20'}].假如数组中元素name和age这两个属性都相同我们则给这个元素加一个属性flag设置为true,否则设置为false.其实就是判断数组中元素中多个属性是否重复的问题了。 这种问题有一个比较死的方法就是拿两个循环来做处理 for (var i = 0,len = collection.length;i < len;i++) { var count = 0; for (var j = 0;j < len;j++) { if (collection[i].name === collection[j].name && collection[i].age === collection[j].age) { count = count + 1; } } if (count > 1) { collection[i].flag = true; } else { collection[i].flag = false; } } return collection; }; 另外一种方法是使用underscore.js里面的方法了,不过由于underscore一次只能按照一个属性来groupBy,所以也需要多次嵌套 collection = _.groupBy(collection,'name'); for (var i in collection) { if (collection[i].

moongoose对象无法新增删除属性

昨天用nodes中的moongoose去查询一个结果遇到一个大坑,这个坑貌似用moongoose可能会遇到。背景是这样的,我在nodejs中去查询document,得到的可以看作是一个对象list。在这个结果集中,我要去寻找这个结果中的某个属性是否和其他的结果重复,并给它添加一个属性作为标志。举例子,我们获得的结果就像是[{name:'neal',age:'18'},{name:'neal',age:'19'}], 我希望把它变成[{name:'neal',age:'18',flag:true},{name:'neal',age:'19',flag:true}]。奇怪的事情发生了,我无法在这些对象中新增这个flag属性,这肿么可能。我尝试各种方法,但是还是存不进去。 后来去stack overflow一查,发觉居然是mongoose 的问题。。。。我压根没有想过是mongoose的问题。原来mongoose是ODM(object document mapper),类似于操作关系型数据库的ORM,我们使用mongoose取到的数据结构依赖我们定义的schema结构,因为我们当初没有定义flag属性,所以最终返回的结果就没有这个属性了。 这个问题应该也有很多解决方法,这里就说一下我看到的一些方法。比如事先在schema增加这个属性,但是我觉得有时候就是不想定义这个属性才在后面加的;还有一个就是把返回的结果用toObject()方法进行转化,这样就可以像普通的对象一样增加属性了;其实本质的原因似乎是document .toObjet()里面需要一个vituals :true 的属性来实现,而默认的是false。可能我说的还不是特别透彻,可以去看一下官方的api http://mongoosejs.com/docs/api.html#document_Document-toObject

nodejs回调大坑

最近看到nodejs,因为有一个处理里面有好几个异步操作,调入回调大坑,不禁觉得很恶心,真的很讨厌发明这种写法的人,简直反社会!!!遂转载一篇解坑的文章,原文地址:http://www.infoq.com/cn/articles/nodejs-callback-hell/。 Node.js需要按顺序执行异步逻辑时一般采用后续传递风格,也就是将后续逻辑封装在回调函数中作为起始函数的参数,逐层嵌套。这种风格虽然可以提高CPU利用率,降低等待时间,但当后续逻辑步骤较多时会影响代码的可读性,结果代码的修改维护变得很困难。根据这种代码的样子,一般称其为"callback hell"或"pyramid of doom",本文称之为回调大坑,嵌套越多,大坑越深。 坑的起源 后续传递风格 为什么会有坑?这要从后续传递风格(continuation-passing style–CPS)说起。这种编程风格最开始是由Gerald Jay Sussman和Guy L. Steele, Jr. 在AI Memo 349上提出来的,那一年是1975年,Schema语言的第一次亮相。既然JavaScript的函数式编程设计原则主要源自Schema,这种风格自然也被带到了Javascript中。 这种风格的函数要有额外的参数:“后续逻辑体”,比如带一个参数的函数。CPS函数计算出结果值后并不是直接返回,而是调用那个后续逻辑函数,并把这个结果作为它的参数。从而实现计算结果在逻辑步骤之间的传递,以及逻辑的延续。也就是说如果要调用CPS函数,调用方函数要提供一个后续逻辑函数来接收CPS函数的“返回”值。 回调 在JavaScript中,这个“后续逻辑体”就是我们常说的回调(callback)。这种作为参数的函数之所以被称为回调,是因为它一般在主程序中定义,由主程序交给库函数,并由它在需要时回来调用。而将回调函数作为参数的,一般是一个会占用较长时间的异步函数,要交给另一个线程执行,以便不影响主程序的后续操作。如下图所示: 下面一个例子说明回调样例的恶心之处: module.exports = function (param, cb) { asyncFun1(param, function (er, data) { if (er) return cb(er); asyncFun2(data,function (er,data) { if (er) return cb(er); asyncFun3(data, function (er, data) { if (er) return cb(er); cb(data); }) }) }) } 像function(er,data)这种回调函数签名很常见,几乎所有的Node.js核心库及第三方库中的CPS函数都接收这样的函数参数,它的第一个参数是错误,其余参数是CPS函数要传递的结果。比如Node.js中负责文件处理的fs模块,我们再看一个实际工作中可能会遇到的例子。要找出一个目录中最大的文件,处理步骤应该是: 用fs.readdir获取目录中的文件列表; 循环遍历文件,获取文件的stat; 找出最大文件; 以最大文件的文件名为参数调用回调。 这些都是异步操作,但需要顺序执行,后续传递风格的代码应该是下面这样的: var fs = require('fs') var path = require('path') module.

利用tesseract-ocr进行验证码识别

因为爬虫项目需要模拟登陆,可是有一个网站的登录需要输入验证码。其实这种登录有2种解决方案,一种是利用cookie,一种是识别图片。前者需要人工登录一次,而且有时效限制,故不太现实。后者可以,但是难点是如何识别出验证码。 这里面就要介绍一个神器了,tesseract-ocr这个项目是一个开源项目,可以用于图像识别。不过这个项目现在托管于google,所以不好下载,你可以搜一下,选择在国内下载。http://download.csdn.net/detail/neal1991/9502931 一开始我觉得我的验证码还挺好识别的,因为都是数字,如下图: 但是我发觉直接来识别还是来识别不了的,最好还是先要对图片进行一些预处理。说到图片的预处理就要说到另外一个软件了,就是imagemagick,这个是一个开源的图片处理项目,你可以去http://www.imagemagick.org/script/binary-releases.php根据你自己的系统进行相应得下载。这个软件还有相应的开发api,你可以自行的根据需要去下载。记住,这个软件安装后,配置环境变量后,需要重新启动的,一开始我还以为是什么问题呢。后来发现重新启动之后,就生效了,可以直接在cmd中使用。在这我就不说什么别的了。 首先是对图片进行预处理: convert 1.jpg -colorspace gray -normalize -threshold 50% 1.tif 这里主要是先做一个灰度图转化,然后进行归一化处理,最后设立一个阈值,进行二值化,这样最后的结果还是比较清晰的,如下图:然后再用tesseract进行识别: tesseract 1.tif result 是不是很简单? 在github上面写了一个nodejs的程序可以直接执行,不过需要安装nodejs,链接如下: https://github.com/neal1991/code-recognition

模拟.net post请求属性

这两天在做一个nodejs的爬虫项目,需要模拟post请求获得网站数据。遇到2个asp.net的网站,掉到坑里面,调试了好几天。总结一下过程。 一般我们模拟post请求的时候最重要的就是post请求里面的formdata就可以了。怎么看formdata呢,以谷歌浏览器为例,打开开发者工具,到network中,点击查询,然后找到你所请求的网页,点击,就能看到请求的各种详细信息了。 我们可以看到里面包含了各种各样的属性,但一般.net网站会多一些特殊的属性,比如上图里面的compressedviestate和eventvalidation属性。我查了一下这些属性貌似是.net机制自有的一些属性。compressedviewstate好像是反映webform的控件的状态信息,而eventvalidation好像是用于服务器端的验证。后来我发现一个规律,如果我在postdata不加这些属性,返回来的响应是一个空的页面,就是其他的部分都有,但是就是包含数据的div里面没有任何数据。但是如果你把这些属性的值填错,就会返回一些乱码的响应数据。后来就一直调试,也苦苦不知道原因。 后来,别人和我介绍了一个神器,curl,这个linux系统自带的,但是windows需要自己安装,不过下载的速度很慢。你用这个可以直接模拟post请求,这样就可以很方便的验证这个请求到底是不是有效的。你在network哪个请求的页面右键,copy as cURL,然后把这个命令拿去执行,这个其实就是一个curl命令。我把它放在linux终端执行能够获得正确的相应,但是放到windows下却不行,后来发现是因为windows里面命令行长度限制,而这个命令有一万多个字符。但是这表明如果使用正确的参数,是可以获得正确的响应的。 高潮来了,我准备在记事本删掉这些属性值的时候,突然发现__COMPRESSEDVIEWSTATE那个是2个下划线,我突然感觉就是这个原因,果然。。。。。。。 这个问题是在是太坑爹了,主要自己一开始写属性的时候也没注意,也没想到这一块,所以花了这么长时间来调试。绕来绕去,发现还不是那个问题。但是现在还有一个问题,我直接是把这些属性用一些固定值的,我并不知道这些值是不是一直有效的。本来我想先发送一个空的post请求然后获取这些属性的,然后填充进去再实现post请求,但是还是一些奇怪的问题,所以我也就没这么做了。 总的来说,写代码还是特别坑,小心入坑!!!!

nodejs爬虫编码问题

最近再做一个nodejs网站爬虫的项目,但是爬一些网站的数据出现了中文字符乱码的问题。查了一下,主要是因为不是所有的网站的编码格式都是utf-8,还有一些网站用的是gb2312或者gbk的编码格式。所以需要做一个处理来进行编码的解码。至于网站的编码怎么看,可以通过去检查中的network去看。 根据相应的编码格式,进行相应的设置。utf-8就不要说了,下面就以gbk为例,说一下解码的方式。 var request = require('request'); var cheerio = request('cheerio'); var iconv = require('iconv-lite'); request ({ url : 'http://www.taobao.com', encodeing = null },function(err,res,body){ if (err) throw err; // decode the content of the website body = iconv.decode(body,'gbk'); var $ = cheerio.load(body); console.log($('head title').text()); }) 或者是使用一个gbk包,但我觉得还是上面的方式比较好。

js的事件流理解

面试问到js的事件流,当时说的不是很清楚,现在觉得有必要把这个弄清楚。 事件捕获和事件冒泡 事件流描述的是从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。 事件流主要分为两种,即事件捕获和事件冒泡,这二者接受事件处理的顺序不同。假设下面的代码: <body> <div id="outer"> <div id="inner"></div> </div> </body> 这两个事件流分别的是IE公司和netspace公司提出来的,冒泡事件流支持的浏览器更多。 冒泡事件流中,事件的传递顺序是从子元素向父元素传递。假设我们给div绑定一个click事件。那么在冒泡事件流中,事件的传递顺序是:inner->outer->body。然而捕获事件流的顺序则截然想法:body->outer->innner。 DOM事件流 DOM2级事件规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。还是以上面的代码为例,单击inner则会按照下面的顺序触发事件:document->html->body->outer->ineer->outer->body->html->document。在DOM事件流中,实际的目标inner在捕获阶段不会接受到事件。这意味着在捕获阶段,事件到outer就停止了,下一个阶段是“处于目标”阶段,于是事件在inner 上发生,并在事件处理中呗看成是冒泡阶段的一部分。然后,冒泡阶段发生,事件又传播回文档。 事件处理程序 响应某个时间的函数叫做事件处理程序。DOM0级的事件处理程序很简单,onclick就是常用的DOM0级事件处理函数,只会在冒泡阶段被处理。 而DOM2级事件定义了两个方法用于处理置顶和删除事件处理程序的操作addEventListener()和removeEventListener(),所有DOM节点都包含这两个方法,并且它们都接受3个参数:要处理的事件名,作为事件处理的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序,反之则是在事件冒泡阶段处理程序。DOM2级方法添加事件处理程序的好处是可以添加多个事件处理程序,会按照添加顺序被处理(无论是捕获还是冒泡)。 而IE不同的它有自己的方法attachEvent()和detachEvent,这两个接受相同的两个参数:事件处理程序名称和事件处理程序函数。 跨浏览器的事件处理程序 var EventUtil = { addHandler: function(element,type,handler) { if (element.addEventListener) { element.addEventListener(type,handler,false); } else if (element.attachEvent) { element.attachEvent('on'+type,handler); } else { element['on'+type] = handler; } }, removeHandler: function(element,type,handler) { if (element.removeEventListener) { element.removeEventListener(type,handler,false); } else(element.detachEvent) { element.detachEvent('on' +type,handler); } else { element['on'+type] = null; } } }