一行命令实现录屏,支持热键和鼠标操作,区域、帧率、格式任你选择
作者:天元浪子
来源:CSDN 博客
市面上的录屏工具软件有很多,基本都是窗口程序。毕竟,离开GUI的支持,设置参数、选择录像区域等操作都会变得非常困难。不过,窗口程序也并非无往不胜,即便是屏幕录像这样交互频繁的应用,控制台程序也同样可以大显身手,甚至比窗口程序的效率更高、操作更便捷。
今天,我带给同学们的是一款命令行模式的录屏软件,可将屏幕指定区域的内容录制成GIF动画文件或MP4、AVI、WMV等格式的视频文件,录像区域、格式、帧率等参数,既可以由命令行传入,也可以通过鼠标和热键来调整。虽然只是实现了录屏功能,却涉及了以下诸多知识点:
1.使用pynput模块的keyboard和mouse侦听键盘和鼠标,实现热键机制和鼠标选取。
2.使用pywin32模块的win32api、win32gui和win32con捕捉当前窗口句柄,实现窗口的隐藏和显示。
3.使用pillow模块的ImageGrab实现屏幕截图。
4.使用imageio模块生成GIF或MP4文件。
5.使用Python标准模块optparse构造linux风格的使用界面,遵循GNU/POSIX语法规则设置参数选项。
6.使用批处理命令编写批处理文件,最终生成桌面快捷方式。
除了上述知识点外,这款屏幕录像机还用到了定时器、线程、队列等技术,以及生产者-消费者模式,几乎就是一个Python技术博览馆。
1
监听键盘和鼠标
尽管pywin32也可以监听键盘和鼠标,但我选择是的pynput模块,因为它实在是太好用了,还可以跨平台。除了监听,pynput模块也可以用来操控键盘和鼠标。pynput模块的安装很简单,直接使用pip安装即可。
pip install pynput
pynput模块提供了keyboard和mouse两个类用于监听键盘和鼠标,实例化时只需要提供相应的事件函数即可。通过下面的简单例子,新手也很容易掌握pynput的使用要点。友情提示:不要在运行这段代码的命令行窗口中测试鼠标左键,因为点击左键会影响程序执行,导致反应迟滞。
from pynput import keyboard, mousedef on_click(x, y, button, pressed):"""鼠标按键"""action = '按下' if pressed else '弹起'if button == mouse.Button.left:print('左键%s,(%d,%d)'%(action, x, y))elif button == mouse.Button.right:print('右键%s,(%d,%d)'%(action, x, y))def on_press(key):"""键按下"""if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:print('Ctr键按下')def on_release(key):"""键弹起"""if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:print('Ctr键弹起')elif key == keyboard.Key.esc:print('再见')return Falsemonitor_m = mouse.Listener(on_click=on_click)
monitor_m.start()monitor_k = keyboard.Listener(on_press=on_press, on_release=on_release)
monitor_k.start()
monitor_k.join()
2
隐藏或显示控制台窗口
作为录屏软件,录制时需要将自身窗口隐藏,而开始录制前或录制结束后又需要显示自身窗口。虽然最小化、最大化窗口也可以满足使用要求,但我选择使用pywin32来隐藏或显示控制台窗口。pywin32模块的安装命令如下:
pip install pypiwin32
下面的3行语句分别实现获取当前窗口句柄、隐藏和显示窗口句柄指定的窗口。
import win32gui, win32api, win32conhwnd = win32gui.GetForegroundWindow() # 获取最前窗口句柄
win32gui.ShowWindow(hwnd, win32con.SW_HIDE) # 隐藏hwnd指定的窗口
win32gui.ShowWindow(hwnd, win32con.SW_SHOW) # 显示hwnd指定的窗口
3
屏幕截图
无所不能的pywin32也可以截屏,据说速度很快。为此我专门测试了全屏幕(1902x1080)截取,发现pywin32和pillow的ImageGrab在速度上堪堪打了个平手,但pywin32截图需要从构建DC开始,大约十几行代码,而ImageGrab只需要一行代码。既然代码简洁,比速度也不逊色,还有什么理由不选择ImageGrab呢?
ImageGrab子模块提供了一个截屏的函数grab,返回一个PIL图像对象。grab函数接受一个四元组参数用以指定截图区域的左上角和右下角在屏幕上的坐标,若省略参数,grab函数将截取整个屏幕。
from PIL import ImageGrabim = ImageGrab.grab((1200,600,1920,1080)) # 截取大小为720×480的屏幕区域
im.show()
im = ImageGrab.grab() # 截取整个屏幕
im.show()
虽然代码中看起来ImageGrab是从PIL模块导入的,但实际上ImageGrab来自pillow模块,这是由于版本历史的原因造成的困惑。如果你还没有安装pillow模块,请使用如下的命令安装:
pip install pillow
4
生成动画和视频文件
Python图像库有很多,imageio是后起之秀,也是其中的佼佼者,尤其在动画和视频领域,更是独领风骚。在imageio诞生之前,生成GIF动画需要几百行代码,而且因为依赖库升级频繁,几乎每隔一段时间就需要重写一次。现在有了imageio,一切都变得云淡风轻了。安装imageio时,请一并安装imageio-ffmpeg,这是imageio生成视频文件的依赖库。
pip install imageio
pip install imageio-ffmpeg
imageio提供了两种生成动画或视频文件的方法:imageio.mimsave函数和imageio.get_writer函数。imageio.mimsave函数接收一个由PIL对象组成的列表作为参数,生成文件前需要将每一帧图像转成PIL对象并存入列表——这意味着生成文件必须在最后一帧图像捕捉完成之后才能开始。
# imageio.mimsave(out_file, pil_list, format='GIF', fps=fps, loop=loop)
# out_file - 输出文件名
# pil_list - 列表,元素类型为PIL对象
# format - 输出格式
# fps - 帧率(每秒播放的帧数)
# loop - 循环次数,0表示无限循环(视频格式不支持该参数)
imageio.get_writer函数类似于open函数,返回了一个文件对象,该对象提供append_data方法,可以将单帧的PIL对象对写入输出文件。写入完成后,不要忘记使用close方法关闭文件对象。使用imageio.get_writer函数生成动画或视频文件,可以很好得支持生产者-消费者模式,捕捉一帧写入一帧,停止录屏后文件即告生成。
# writer = imageio.get_writer(out_file, fps=fps) # gif格式可增加loop参数
# writer.append_data(im_pil) # im_pil为PIL对象
# writer.close()
5
定时器
录屏依赖于精准的定时器,遗憾的是Python并没有提供一个像样的定时器,因此只能自己写一个了。关于定时器的介绍,请参考我昨天写的博文《无所不能的Python竟然没有一个像样的定时器?试试这个!》,这里就不再赘述了。
6
完整代码
源文件名为ScreenRecorder.py,全部代码不足300行,代码中用到的各个模块和技术要点都已介绍过了,关键之处均有注释。
# -*- coding:utf-8 -*-import os, time
import optparse
import threading
import imageio
import queue
import numpy as np
from PIL import Image, ImageGrab
import win32gui, win32api, win32con
from pynput import keyboard, mouseclass PyTimer:"""定时器类"""def __init__(self, func, *args, **kwargs):"""构造函数"""self.func = funcself.args = argsself.kwargs = kwargsself.running = Falsedef _run_func(self):"""运行定时事件函数"""th = threading.Thread(target=self.func, args=self.args, kwargs=self.kwargs)th.setDaemon(True)th.start()def _start(self, interval, once):"""启动定时器的线程函数"""if interval < 0.010:interval = 0.010if interval < 0.050:dt = interval/10else:dt = 0.005if once:deadline = time.time() + intervalwhile time.time() < deadline:time.sleep(dt)# 定时时间到,调用定时事件函数self._run_func()else:self.running = Truedeadline = time.time() + intervalwhile self.running:while time.time() < deadline:time.sleep(dt)deadline += interval # 更新下一次定时时间if self.running: # 定时时间到,调用定时事件函数self._run_func()def start(self, interval, once=False):"""启动定时器interval - 定时间隔,浮点型,以秒为单位,最高精度10毫秒once - 是否仅启动一次,默认是连续的"""th = threading.Thread(target=self._start, args=(interval, once))th.setDaemon(True)th.start()def stop(self):"""停止定时器"""self.running = Falseclass ScreenRecorder:"""屏幕记录器"""def __init__(self, out, fps=10, nfs=1000, loop=0):"""构造函数"""self.format = ('.gif', '.mp4', '.avi', '.wmv')ext = os.path.splitext(out)[1].lower()if not ext in self.format:raise ValueError('不支持的文件格式:%s'%ext)self.out = outself.ext = extself.fps = fpsself.nfs = nfsself.loop = loopself.cw = win32api.GetSystemMetrics(win32con.SM_CXSCREEN)self.ch = win32api.GetSystemMetrics(win32con.SM_CYSCREEN)self.set_box((0, 0, self.cw, self.ch))self.ctr_is_pressed = Falseself.hidding = Falseself.recording = Falseself.pos_click = (0,0)self.q = Noneself.hwnd = self._find_self()self.info = Noneself.help()self.status()def _find_self(self):"""找到当前Python解释器的窗口句柄"""return win32gui.GetForegroundWindow() # 获取最前窗口句柄def set_box(self, box):"""设置记录区域"""x0, y0, x1, y1 = boxdx, dy = (x1-x0)%16, (y1-y0)%16dx0, dx1 = dx//2, dx-dx//2dy0, dy1 = dy//2, dy-dy//2self.box = (x0+dx0, y0+dy0, x1-dx1, y1-dy1)def help(self):"""热键提示"""print('---------------------------------------------')print('Ctr + 回车键:隐藏/显示窗口')print('Ctr + 鼠标左键或右键拖拽:设置记录区域')print('Ctr + PageUp/PageDown:更改记录格式')print('Ctr + Up/Down:调整帧率')print('Ctr + 空格键:开始/停止记录')print('Esc:退出')print()def status(self):"""当前状态"""if self.info:print('\r%s'%(' '*len(self.info.encode('gbk')),), end='', flush=True)recording_text = '正在记录' if self.recording else '准备就绪'if self.ext == 'gif':loop_str = '循环%d次'%self.loop if self.loop > 0 else '循环'else:loop_str = '不循环'self.info = '\r输出文件:%s | 帧率:%d | 区域:%s'%(self.out, self.fps, str(self.box))print(self.info, end='', flush=True)def start(self):"""开始记录"""self.q = queue.Queue(100)self.timer = PyTimer(self.capture)self.timer.start(1/self.fps)th = threading.Thread(target=self.produce)th.setDaemon(True)th.start()def stop(self):"""停止记录"""self.timer.stop()def capture(self):"""截屏"""if not self.q.full():im = ImageGrab.grab(self.box)self.q.put(im)def produce(self):"""生成动画或视频文件"""if self.ext == '.gif':writer = imageio.get_writer(self.out, fps=self.fps, loop=self.loop)else:writer = imageio.get_writer(self.out, fps=self.fps)n = 0while self.recording and n < self.nfs:if self.q.empty():time.sleep(0.01)else:im = np.array(self.q.get())writer.append_data(im)n += 1writer.close()def on_press(self, key):"""键按下"""if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:self.ctr_is_pressed = Truedef on_release(self, key):"""键释放"""if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:self.ctr_is_pressed = Falseelif key == keyboard.Key.space and self.ctr_is_pressed:if self.recording: # 停止记录self.stop()self.recording = Falseif self.hidding:win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW) # 显示窗口self.hidding = Falseelse: # 开始记录self.start()self.recording = Trueif not self.hidding:win32gui.ShowWindow(self.hwnd, win32con.SW_HIDE) # 隐藏窗口self.hidding = Trueelif key == keyboard.Key.enter and self.ctr_is_pressed:if self.hidding: # 显示窗口win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW) # 显示窗口self.hidding = Falseself.status()else: # 隐藏窗口win32gui.ShowWindow(self.hwnd, win32con.SW_HIDE) # 隐藏窗口self.hidding = Trueelif (key == keyboard.Key.page_down or key == keyboard.Key.page_up) and self.ctr_is_pressed:i = self.format.index(self.ext)if key == keyboard.Key.page_down:self.ext = self.format[(i+1)%len(self.format)]else:self.ext = self.format[(i-1)%len(self.format)]folder = os.path.split(self.out)[0]dt_str = time.strftime('%Y%m%d%H%M%S')self.out = os.path.join(folder, '%s%s'%(dt_str, self.ext))self.status()elif key == keyboard.Key.left and self.ctr_is_pressed:if self.fps > 1:self.fps -= 1self.status()elif key == keyboard.Key.right and self.ctr_is_pressed:if self.fps < 40:self.fps += 1self.status()elif key == keyboard.Key.esc:print('\n程序已结束')return Falsedef on_click(self, x, y, button, pressed):"""鼠标按键"""if (button == mouse.Button.left or button == mouse.Button.right) and self.ctr_is_pressed:if pressed:self.pos_click = (x, y)elif self.pos_click != (x, y):x0, y0 = self.pos_clickself.set_box((min(x0,x), min(y0,y), max(x0,x), max(y0,y)))self.status()def parse_args():"""获取参数"""parser = optparse.OptionParser()parser.add_option('-o', '--out', action='store', type='string', dest='out', default='', help='输出文件名')parser.add_option('-f', '--fps', action='store', type='int', dest='fps', default='10', help='帧率')parser.add_option('-n', '--nfs', action='store', type='int', dest='nfs', default='1000', help='最大帧数')parser.add_option('-l', '--loop', action='store', type='int', dest='loop', default=0, help='循环')return parser.parse_args()if __name__ == '__main__':options, args = parse_args()if options.out:out = options.outfolder = os.path.split(out)[0]if folder and not os.path.isdir(folder):raise ValueError('路径不存在:%s'%folder)else:dt_str = time.strftime('%Y%m%d%H%M%S')out = os.path.join(os.getcwd(), '%s.mp4'%(dt_str,))sr = ScreenRecorder(out, fps=options.fps, nfs=options.nfs, loop=options.loop)monitor_m = mouse.Listener(on_click=sr.on_click)monitor_m.start()monitor_k = keyboard.Listener(on_press=sr.on_press, on_release=sr.on_release)monitor_k.start()monitor_k.join()
7
linux风格的使用界面
通过sys模块的sys.argv接收命令行参数,是很多Python程序员的首选。不过,sys.argv无法处理默认参数、关键字参数,当参数较多时也极易发生张冠李戴的错误。熟悉linux的程序员,更喜欢使用GNU/POSIX语法设置参数选项。
ScreenRecorder.py借助于Python的标准模块optparse,可以很容易地提供linux风格的使用界面。下图中-h或者–help选项是optparse模块自动生成的。
假如要录屏到文件d:\demo.mp4,帧率为25,下面的两种写法是等价的。
python .\ScreenRecorder.py -o d:\demp.mp4 -f 25
python .\ScreenRecorder.py --out=d:\demp.mp4 --fps=25
录屏程序启动后,界面如下图所示。现在可以使用热键配合鼠标,尽情体验这个新玩具了。
细心的同学很快就会发现,界面上的参数信息会实时更新,但屏幕却没有滚动。这是怎么实现的呢?有兴趣的同学可以去读一下代码,或者在我的博客首页搜索“必杀技”,就会找到答案。
8
生成桌面快捷方式
先打开一个命令行窗口,再运行命令,还要输入参数(其实不输入参数也可以录屏),有些同学就会觉得很麻烦。没关系,下面我们再搞一个批处理,然后将批处理做成桌面快捷方式,就可以化繁为简一键操作了。
随便打开一个文本编辑器,生成如下的文件,并以ScreenRecorder.bat命名,保存在和ScreenRecorder.py同级的路径下。如果需要改变录屏的默认参数,也可以写在这个文件中。
@echo off
cd /d d:\XufiveGithub\ScreenRecorder
python ScreenRecorder.py
有了bat文件之后,就可以在Windows桌面上生成该文件的快捷方式了。不知道如何生成快捷方式的同学,请自行搜索吧。最后附上一张我录制的全球风场GIF动画图(局部)。
原文链接:
https://blog.csdn.net/xufive/article/details/119191690
往
期
回
顾
新闻
苹果新功能引网友众怒
技术
一个算法“拿下”两个榜单!
技术
AI 新技术,遏制在线骚扰
新闻
程序员因开发速度太慢而遭起诉
分享
点收藏
点点赞
点在看
相关文章:

SMO学习笔记(二)——还原(恢复)篇之完整恢复
SQLSERVER2005恢复介绍: 三种恢复模式(一).简单恢复模式 事务日志被自动截断,不能使用日志文件进行恢复。(二).完整恢复模式 保留所有操作的完整事务日志。(三).大容量日志恢复模式 简要记录大容量操作(索引创建和大容…

linux内核map图
linux内核map图

Linux下tcpdump用法
根据使用者的定义对网络上的数据包进行截获的包分析工具。tcpdump将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供了and、 or、not等逻 辑语句来帮助过滤不必要的信息; 默认情况下&#…

终于有人站出来为程序员说话了
【CSDN 编者按】刘少山博士是《程序员》杂志的作者之一,多年来投稿了大量无人驾驶领域相关的优质内容,《新程序员》上线后,他带着自己多年来对技术行业的思考以及对程序员群体的殷切期望重新回归,希望能对大家有所启迪。作者 | 刘…

给 Windows 驱动程序安装提速
对比各种主流操作系统,在 Windows 上安装驱动程序是最直观最方便的,不仅可以通过设备管理器查看所有硬件的信息并安装驱动,在有新硬件插入时也有人性化的驱动程序安装提示和安装向导,甚至还可以在线安装驱动,这都是其他…

web标准化设计:常用的CSS命名规则
常用的CSS命名规则 头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 左右中:left right center 登录条ÿ…

鲲鹏应用创新大赛山西区域赛圆满落幕,鲲鹏生态助力信创变革
鲲鹏入晋,万里腾飞,8 月 6 日,2021 鲲鹏应用创新大赛山西赛区决赛在太原圆满落幕。今年鲲鹏应用创新大赛区域赛山西赛区是山西省内数字化转型的重要赛事,经过层层选拔,共 35 个队伍进入山西赛区决赛,参加政…

视频分享网站首页:最新视频特效
2019独角兽企业重金招聘Python工程师标准>>> <!DOCTYPE> <html> <head><title></title><style>.newVideo{width:208px;height:116px;border:0px solid #000; position:relative;cursor:pointer;}.newVideoImg{position:relativ…

Metasploit攻击Oracle的环境搭建
Metasploit中关于Oracle的攻击模块默认并不完全,需要自己做一些工作。本文主要记录在搭建环境的中的一些错误(操作系统Backtrack 5)。在默认情况下使用oracle的一些攻击功能会出现类似如下错误:ary module execution completed m…

jQuery / jQuery mvc plugin
jMVC专为 Qt WRT 设计。Qt WRT 将随新版Qt发布,支持 Symbian ^3 和 Meego 设备。jMVC 采用延迟加载设计,代码分布在不同的.js文件中,调用时通过xhr加载。 在web环境中会严重影响性能,所以jMVC不适合开发web site。目前大部分web b…

【转发】什么时候该用委托,为什么要用委托,委托有什么好处
好多人一直在问:什么时候该用委托,为什么要用委托,委托有什么好处.... 看完下面的文章你将茅塞顿开..(看不懂的直接TDDTDS) 概念虽然我不喜欢讲太多 我们直接先来YY 个场景:我很喜欢打游戏,但运气不好每次打游戏都会被主管看到,朱老板不喜欢他的员工在上班的时 间打游戏,所以朱…

一位合格软件工程师应该具备怎样的工程化、交付能力?
大厂待遇高、福利也好相信很多同学都对大厂有着向往,然而现实却是......有的同学成功拿到offer进入大厂,有的同学还在为备考大厂迷茫苦恼着:我之前从未面试过,这次冒险投了字节,几乎是抱着积累经验和技术交流的心态去了…

Flex通信-Java服务端通信实例
Flex与Java通信的方式有很多种,比较常用的有以下方式: WebService:一种跨语言的在线服务,只要用特定语言写好并部署到服务器,其它语言就可以调用 HttpService:通过http请求的形式访问服务器 RmoteObject&am…

jQuery性能优化指南
1,总是从ID选择器开始继承 在jQuery中最快的选择器是ID选择器,因为它直接来自于JavaScript的getElementById()方法。 例如有一段HTML代码: <div id"content"> <form method"post" action"#"> &l…

速度快到飞起 如何跟蜻蜓的大脑学习计算?
编译 | 禾木木 出品 | AI科技大本营(ID:rgznai100) 科学家研究了其中一种大型昆虫蜻蜓的大脑,希望利用这些昆虫的专长来设计计算系统,这些系统针对拦截来袭导弹或跟踪气味羽流等任务进行了优化。通过利用蜻蜓神经系统的速度、简单性和效率,目…

Python、Unicode和中文
python的中文问题一直是困扰新手的头疼问题,这篇文章将给你详细地讲解一下这方面的知识。当然,几乎可以确定的是,在将来的版本中,python会彻底解决此问题,不用我们这么麻烦了。先来看看python的版本:>&g…

提高mysql性能的开源软件
今天发现一个开源软件,看介绍可以提高mysql的性能,这个东西就是Google的开源TCMalloc库,于是拿来装了下看看效果.这个软件下载地址是:http://code.google.com/p/google-perftools/downloads/list,我用的是最新版的google-perftools-1.4.tar.gz.1.安装过程:#tar zxvf google-per…

一款比较实用齐全的jQuery 表单验证插件
一款比较实用,并且验证类型齐全的jQuery表单验证插件.英文版原作者Vanadium,由我做中文整理.E文水平有限,如果翻译的有问题的,请大家指出,在此感谢~可以验证哪些? 文字,日期,邮箱,网址,数字,AJAX用户名验证以及自定义的正则等等几乎所有我们要用到的验证.不多说,看DEMO吧: 点此…

[原]VS2012编译GLEW 1.11
1、到http://glew.sourceforge.net/下载源代码 2、使用vs2012打开build下vc6的glew.dsw ,自动生成2012工程(一路点确定)特别注意:不要使用build下的vc12之类的 本人亲测不好使 坑了我很久 3、直接生成解决方案,会在根目…

长相酷似小强的小米「铁蛋」机器狗,售价 9999 元,打滚唱跳会空翻
整理 | 禾木木 出品 | AI科技大本营(ID:rgznai100) 8月10日晚,雷军年度演讲及小米秋季发布会在线上召开,此次发布会足足讲了三个小时,不仅介绍了小米的目前市场状况,还分享了新品以及小米机器人实验室的第一款产品——机器狗「铁…

java中图片文件的判断
javax.imageio 类 ImageIO BufferedImage bi ImageIO.read(resFile);//resFile --- InputStreamif(bi null){ System.out.println(此文件不为图片文件); }try {//判断是否为图片文件并且返回图片的格式!ImageInputStream iis ImageIO.createImageInputStream(o)…

jQuery中常用的函数方法总结
jQuery中为我们提供了很多有用的方法和属性,自己总结的一些常用的函数,方法。个人认为在www.21kaiyun.com的紫微斗数星座在线排盘开发中会比较常用的,仅供大家学习和参考。 事件处理 ready(fn) 代码:$(document).ready(functi…

使用editcap命令将ERF格式转换为pcap格式
editcap是Wireshark的一个组件,在Windows平台下,只要完成Wireshark的安装,就可以在安装目录中看到editcap.exe。editcap.exe需要在命令行中使用。 对于用Endace DAG捕捉卡捕获的数据包,一般来说,都是erf格式的。ERF格式…

中关村开源创新大赛-达闼赛道如火如荼进行中
导语为庆祝中国共产党成立100周年,中关村软件园携手云端机器人运营商达闼,联合举办了中关村开源创新大赛-达闼赛道,暨“不忘初心 AI创时代”达闼智能服务机器人编舞大赛。在小姜的灵动舞姿下,今天,达闼赛道正式启动&am…

国际版Azure搭建Windows多种类型×××_三.配置SSTP ×××连接服务
安全套接字隧道协议(SSTP)是一种新的***隧道形式,具有允许流量通过阻止PPTP和L2TP / IPsec流量的防火墙的功能。 SSTP提供了一种在HTTPS协议的SSL通道上封装PPP流量的机制。 PPP的使用允许支持强认证方法,如EAP-TLS。 使用HTTPS意…

超强的jquery极品插件--色彩选择器类/ 右键菜单类/ 图片新闻flash展示类
Farbtastic Farbtastic是一个color picker插件。它能够在一个页面中加入多个颜色选择控件,然后每个控件关联到页面中的一个元素比如:文本输入框。FarbtasticjQuery Color Picker 21世纪开运网在线排盘星座就成功运用这些技巧,www.21kaiyun.co…

张口闭口就是焦虑,现在的程序员怎么了?
【CSDN 编者按】在网上,我们经常会看到各类程序员的吐槽,学历焦虑、大厂焦虑充斥着手机屏幕,本文作者从这一角度出发,用质朴的文字告诉年轻一代程序员一个事实:慢慢走好编程每一步,不要害怕更不用着急&…

epoll 的实现原理以及与poll,select 的对比
最近面试的时候 被问到epoll的问题,就下来查一查,看到有篇文章不错,就记录下来,供大家参考学习。 以一个生活中的例子来解释. 假设你在大学中读书,要等待一个朋友来访,而这个朋友只知道你在A号楼,但是不知道你具体住在哪里,于是你…

js 字符串转换成数字的 三种方法
在js读取文本框或者其它表单数据的时候获得的值是字符串类型的,例如两个文本框a和b,如果获得a的value值为11,b的value值为9 ,那么a.value要小于b.value,因为他们都是字符串形式的.在网上找了一下js字符串转数字的文章,这个比较全方法主要有三种 转换函数、强制类型转换、利用js…

Web 开发与设计之 Google 兵器谱
Google 的使命是 Web,在 Google 眼中,未来的一切应用都将 Web 化,一直以来,Google 为 Web 开发与设计者推出了大量免费工具,让他们更好地创建,维护,改善他们的 Web 站点,这些工具包含…