Selenium 是 ThroughtWorks 一个强大的基于浏览器的开源自动化测试工具,它通常用来编写 Web 应用的自动化测试。随着 Selenium 团队发布 Selenium 2(又名 WebDriver)之后,本应该退役的 Selenium 1 却还在为很多人应用,这究竟是什么原因呢?Webdriver 又有什么优势可以击败 Selenium 1 并让大家选择它呢?

  • 内容

追踪溯源,WebDriver 和 Selenium 本是两个独立的项目,实现机制也是不同的。那 Selenium 团队为什么会在 Selenium 2 中将两者合并,这究竟有什么用意呢?WebDriver 比 Selenium 又有什么优势呢?我们该如何选择使用 Selenium 还是 WebDriver 呢?别着急,您将在本文中找到答案,并将了解一些 WebDriver 的基本知识和使用方法。     为方便表述,在本文中,我们称 Selenium 2 为 WebDirver,Selenium 为 Selenium 1.x(因为 Selenium1.x 时通常指的是 Selenium RC,所以 Selenium 也指 Selenium RC)。

WebDriver 是… …?

Selenium 2,又名 WebDriver,它的主要新功能是集成了 Selenium 1.0 以及 WebDriver​(WebDriver 曾经是 Selenium 的竞争对手)。也就是说 Selenium 2 是 Selenium 和 WebDriver 两个项目的合并,即 Selenium 2 兼容 Selenium,它既支持 Selenium API 也支持 WebDriver API。     那 Selenium 团队为什么会将两个项目合并呢?我们通常认为其中部分原因是 WebDriver 解决了 Selenium 存在的缺点(比如,能够绕过 JS 沙箱),部分原因是 Selenium 解决了 WebDriver 存在的问题(比如,支持更广泛的浏览器和编程语言),不论真正的原因是什么两个项目的合并为用户提供了一个优秀的自动化测试框架。     现在让我们看看两个工具有什么具体的不同。在开始之前,我们首先看一下用 Selenium 和用 Webdriver 构建出来的测试工程是什么样的,后文会在这个基础上阐述 Webdriver 和 Selenium 的异同。

说明:因为现在 WebDriver 还在改进和优化过程中,所以我们以下的举例和说明都是基于版本 selenium-2.28.0 的基础上。

构建一个 Selenium 测试工程

Selenium API 则支持更多的编程语言,这里我们还是以 Java 为例。

图 1. Selenium 测试工程

清单 1. 使用 Selenium API 的脚本 - 登录 SmartCloud iNotes
package demo;

import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium; public class SeleniumDemo { public static void main(String[] args) throws InterruptedException {
// 创建一个 Selenium 实例 Selenium selenium = new DefaultSelenium("localhost", 4444, \
"*firefox", "https://apps.na.collabserv.com/"); // 启动 selenium session
selenium.start();
// 打开测试网页
selenium.open("https://apps.lotuslive.com/");
// 输入用户名,密码
selenium.type("//input[@id='username']", \
"autouser01@e3yunmail.mail.lotuslive.com");
selenium.type("//input[@id='password']", "test");
// 登录
selenium.click("//input[@id='submit_form']");
// 等待直到页面出现 Mail 链接
int count = 60;
while(count > 0){
if(selenium.isElementPresent("//a[contains(text(),'Mail')]")){
break;
}else{
Thread.sleep(1000);
count--;
} }
// 登出
selenium.click("//a[contains(text(),'Log Out')]");
// 测试结束后,终止 selenium session
selenium.stop();
}
}

构建一个 WebDriver 测试工程

WebDriver API 可以通过 Python、Ruby、Java 和 C#访问,支持开发人员使用他们偏爱的编程语言来创建测试。这里我们以 Java 为例。首先需要准备好自己的 Eclipse 环境,并在 selenium 的官方网站下载 Selenium 2 的 Jar 包。

图 2. WebDriver 测试工程

清单 2. 使用 WebDriver API 的脚本 - 登录 SmartCoud iNotes
package demo;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait; public class WebDriverDemo {
public static void main(String[] args) {
//创建一个 firefox driver 实例
WebDriver driver = new FirefoxDriver();
//打开测试网址
driver.get("https://apps.na.collabserv.com/");
//定义用户名和密码文本框
WebElement username=driver.findElement(By.id("username"));
WebElement password=driver.findElement(By.id("password"));
//输入用户名和密码
username.sendKeys("autouser01@e3yunmail.mail.lotuslive.com");
password.sendKeys("test");
//点击 login 登录
WebElement login=driver.findElement(By.id("submit_form"));
login.click();
//设置页面等待直到出现 Mail 链接
(new WebDriverWait(driver, 500)).until(new ExpectedCondition<WebElement>(){
public WebElement apply(WebDriver dr) {
return dr.findElement(By.linkText("Mail"));
}
});
//登出
WebElement logout=driver.findElement(By.linkText("Log Out"));
logout.click();
//关闭浏览器
driver.quit();
}
}

Selenium vs WebDriver

从上述用 Selenium 和 WebDriver 构建的两个测试工程来看,WebDriver 工程在构建之后不需要其他的配置我们便可以直接使用,这一点和 Selenium 是截然不同的。因为 Selenium 还需要安装并启动 Selenium Server 才能运行测试程序。

另外,我们可以看出 WebDriver 是基于面向对象的 API,它更多的是从用户角度出发。反之 Selenium 提供的是基于字典的 API,用户可以很方便的看到所以支持的方法。毋庸置疑的是,WebDriver 提供的 API 更为简洁,对用户更加的友好。但从另一个角度来看,就是用户不能很直观的看到 WebDriver 提供了哪些 API,可能需要通过官网提供的 JavaDoc(来源:http://selenium.googlecode.com/svn/trunk/docs/api/java /index.html)的协助来找寻一些方法。

下面我们看下 WebDriver 支持的浏览器类型,以及一些基本操作的使用方法。

支持的浏览器

Selenium 是由一堆 JavaScript  实现的,所以只要支持 JavaScript  的浏览器 Selenium 都可以做到很好的支持,理论上来讲它比 WebDriver 能支持更多的浏览器而且不需要做额外的开发。但是因为每个浏览器对于 JavaScript   的执行有着不同程序的安全限制,以防止用户被恶意攻击,所以 Selenium 存在一些不能处理的情况,例如本机的鼠标和键盘事件,弹出框等等。WebDriver 则通过不同的方法来解决 Selenium 面临的一些问题,不单单使用 JavaScript ,WebDriver 会使用任何一种合适的机制来操作浏览器。WebDriver 提供了FirefoxDriverInternetExplorerDriverOperaDriverChromeDriver、SafariDriver、HtmlUnitDriver,以及 RemoteWebDriver 来支持不同的浏览器。另外为了支持移动设备它提供了 AndroidDriverIPhoneDriver。 其中很特别的是 HtmlUnitDriver,它的无界面实现不会实际打开浏览器,运行速度很快,所以用户可以使用它来做一些单元测试。对于用 FireFox 或 Internet Explorer 等浏览器来做测试的自动化测试用例,运行速度通常很慢,HtmlUnit Driver 无疑是可以很好地解决这个问题。

那么既然 Selenium 和 WebDriver 支持的浏览器差不多,我们究竟应该选择 Selenium 还是 WebDriver 呢?虽然现在 WebDriver 还在处在开发和测试当中,有些功能还存在一些缺陷,但随着 Webdriver 的不断完善,它替代 Selenium 终将是大势所趋。所以笔者还是建议选择使用 WebDriver,如果确实 WebDriver 还不能支持你的测试工作,用 Selenium 来做一个过渡也是可以的。当然选用不同的测试工具可能对代码维护有一定的挑战,毕竟 Selenium 和 WebDriver 的 API 是不同的,幸好 WebDriver 还提供了另外一种方法。例如在笔者现在的项目中要支持 Safari,但是使用 SafariDriver 测试时非常的不稳定以致测试不能顺利的进行。所以使用了 SeleneseCommandExecutor,这种方法也可以让 WebDriver 支持更多的浏览器并还是使用 WebDriver API,这样也会降低维护代码的工作量。需要注意的是,这种方法需要安装并启动 Selenium Server。

清单 3. 使用 SelenseCommandExecutor 使 WebDriver 支持更多的浏览器
Capabilities capabilities = new DesiredCapabilities()
capabilities.setBrowserName( "safari" );
CommandExecutor executor = new SeleneseCommandExecutor( "http:localhost:4444/",/
"http://WebDriver driver = new RemoteWebDriver(executor, capabilities);

定位页面元素

Selenium 对元素的处理是基于 Action,Object(操作,对象)的方式,使用 id、name,或是 XPath 来定位页面元素。当使用的是 XPath 时在某种程度上对 Internet Explorer 的测试速度有很大的影响,因为 IE 浏览器没有内置对 XPath 的支持,所以在 IE 上测试时会特别慢,当然现在已经有办法解决这个问题了,虽然比不上 Firefox 的测试速度但也是有了相当大的提高。

WebDriver 则使用 findElement 方法来查找到页面元素,它定位页面元素可以通过 id、name、xpath、className、link text、CSS 等等查找。

表 1. WebDriver 查找页面元素
查找方式 描述 举例 (Java)
By.id 以元素的 id 属性来定位页面元素 By.id(“username”)
By.name 以元素的 name 属性来定位页面元素 By.name(“username”)
By.xpath 以 XPath 来定位页面元素 By.xpath(“//*[@id="username"])
By.className 以元素的 class 属性来定位页面元素 By.className(“even-table-row”)
By.cssSelector 基于 CSS 选择器引擎定位页面元素 By.cssSelector(“#username”)
By.LinkText
By.partialLinkText
查找包含链接字串的页面元素 By.linkText(“Click Me!”)
By.partialLinkText(“ck M”)
By.TagName 以元素的标签名称查找页面元素 By.tagName(“td”)

有人研究过,By CSS 方式是最快的查找方式,所以在做测试时,我们可以尽量使用 By.cssSelector 的方式。(来源:http://sauceio.com/index.php/2011/05/why-css-locators-are-the-way-to-go-vs-xpath/

页面等待

在 Web UI 的自动化测试中,一种常见的不稳定是页面上的元素加载时间不固定,比如在 Ajax,或者 JS 延迟加载等情况下,页面元素出现的时间短的几毫秒,长的几秒钟。这个时候在读取页面元素就会一些麻烦。等得时间短了话找不到页面元素,测试 fail;但等得时间过长,又会增加测试的时间造成效率低下。

在 Selenium 中,用户只能估算一个时间使用 Selenium.waitForPageToLoad()或者 Thread.sleep()的方式来等待页面加载时间,要不就是使用自己写的 Wait 方法,比如:

清单 4. 使用 Selenium API 的脚本 – 等待页面元素加载
public static void WaitForElementPresent(String elementName)
{
int maxTry = 60;
if(selenium.isElementPresent(elementName))return;
for (int second = 0; second < maxTry; second++)
{
if (selenium.isElementPresent(elementName)) break;
Thread.sleep(1000); //等待一秒钟
}

但在 Webdriver 中,它提供了 Explicit and Implicit Waits 方法,使得等待的方法更加灵便使用,在下面的例子就是一个封装好的等待页面加载的方法,在 20 秒钟内等待页面元素出现,如果超过 20 秒就会抛出超时异常:

清单 5. 使用 WebDriver API 的脚本 – 等待页面元素加载
public boolean waitForElementDisplayed(WebElement el, boolean shouldBeDisplayed) {
boolean displayed = false;
if (shouldBeDisplayed) {
try {
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(visibilityOfElementLocated(el));
displayed = true;
} catch (Exception e) {
displayed = false;
}
} else {
try {
displayed = el.isDisplayed();
} catch (NoSuchElementException e) {
displayed = false;
}
}
return displayed;
}

更多关于 Explicit and Implicit Waits 的内容,请参考 http://seleniumhq.org/docs/04_webdriver_advanced.jsp#implicit-waits

并行测试支持

在 Web UI 自动化测试中,执行效率是非常重要的,尤其是在测试脚本比较多的情况下。所以我们有必要支持并行化测试,并行化测试需要两个条件:

  1. 在运行测试用例端,需要支持并行运行。例如,写一个多线程来支持同时运行多个测试用例
  2. 测试用例之间,需要减除在并行运行时的依赖关系。例如,使用不同的用户,以免发生测试冲突
  3. 在 Selenium Server 端,要能够同时打开多个浏览器窗口,并使得各个浏览器窗口之间的测试不受干扰,各自运行

对于条件 1,我们可以自己写一个多线程来支持并行运行,支持并行的自动化测试,或者使用 JUnit 或者 TestNG;

对于条件 2,我们在编测试用户脚本的时候,需要考虑到在在并行测试的时候可能存在的测试冲突,比如写日志,测试用户等等,可以参考文章(用 STAF+Selenium 实现并行的测试化框架,来源:http://www.ibm.com/developerworks/cn/java/j-lo-parallelautotest/index.html);

而对于条件 3,我们需要借助 Selenium Grid。利用 Selenium Grid,我们可以很方便的同时在多台测试机器上和异构环境中并行地运行多个测试实例以加快 Web-app 的测试。

Selenium RC 的并行测试支持

在 Selenium 时代,我们使用的 Selenium Grid 是一个单独的项目(http://selenium-grid.seleniumhq.org/)。 Selenium Grid 的机制是启动一个 hub,然后启动多个 Selenium RC 注册到 hub 上,当测试请求到 hub 时,hub 会将测试分发给 Selenium RC, Selenium RC 会实际的启动一个浏览器完成测试。在这笔者们对它的使用不再做过多的描述,只是想分享一个之前在测试项目中遇到的问题。我们知道,有些情况下一些软件缺陷 可能发生在同一个浏览器的不同操作系统环境上,或者是测试需要在特定的浏览器版本上进行,那我们在使用 Selenium Grid 的情况下,如何能够确认测试是运行在什么指定的环境上呢?在我们的项目里面是通过更改配置文件 grid_configuration.xml 来实现的,例如我们有 Win7、WinXP 以及 Linux,上面分别装有 Firefox17 或者 Firefox18,那我们可以使用下面的配置信息:

清单 6. 自定制的 Selenium Grid 配置文件
hub:
port: 4444
remoteControlPollingIntervalInSeconds: 180
sessionMaxIdleTimeInSeconds: 300
environments:
- name: "Firefox 17 on Win7"
browser: "*firefox"
- name: "Firefox 17 on WinXP"
browser: "*firefox"
- name: "Firefox 18 on Linux"
browser: "*firefox"

这样我们在三台需要注册 Selenium RC 的机器上运行下列命令并指定相应的参数:

ant -Dport=<port> -Dhost=<hostname> -DhubURL=<hub url>\
-Denvironment="Firefox 17 on Win7" launch-remote-control

其 中,-Dport 是指定 Selenium RC 的端口号,-DHost 指定 Selenium RC 所在的机器的主机名,-DhubURL 指定 hub 的 URL,-Denvironment 表示注册的 Selenium RC 的浏览器,在这里我们可以替换成相应的浏览器、版本已经操作系统类型。完成注册之后,在 Selenium Grid 的控制台中可以看到可用的 Selenium RC:

图 3. 使用自定制配置文件的 Selenium Grid 控制台

最后,我们在代码中指定要测试的环境,hub 就可以将测试转发到相应的环境上去运行,这样我们就可以灵活的按照测试需要在预期的环境上面完成测试。

WebDriver 的并行测试支持

在 Selenium 2 中,Selenium Grid 被集成到了 Selenium Server 中,即是包含在 selenium-server-standalone-x-x-x.jar 包中,好处就是更简洁更方便了!Selenium Grid 包含有两种角色,hub 和 node,其中 hub 是用来接收所有的请求,并将请求分发给不同的 node;node 指的便是实际执行测试的节点,它包含 Selenium 和 WebDriver 两种类型,其中 Selenium 是兼容 Selenium 1 中的 Selenium RC。下面我们看下如何启动 hub 和 node:

启动 Selenium Grid hub:

#启动 Selenium Grid 的 hub,指定端口号 4444,最多运行 40 个测试 session
java -jar selenium-server-standalone-2.28.0.jar -role hub -maxSession 40 -port 4444

挂载 node,在缺省情况下,会分别为 Selenium 和 Webdriver 的测试引擎启动 5 个 firefox,5 个 googlechrome,和 1 个 internet explorer。但也可以通过参数的方式来定制启动 node 所支持的浏览器,例如:

#挂载 node,支持启动 20 个 session 的版本号为 17.0.1 的 firefox 浏览器,指定端口号为 5555,指定启动 firefox 时使用的 profile
java -jar selenium-server-standalone-2.28.0.jar -role node \
-hub http://{grid_server}:4444/grid/register -port 5555 \
-firefoxProfileTemplate llinotes.profile -maxSession 20 \
-browser "browserName=firefox,version=17,platform=WINDOWS,maxInstances=20"

客户端的调用,在客户端向 Selenium Grid 的 hub 来提交一个测试请求时,对于申请 Selenium 的 node 是和使用 Selenium 1 的方法是一样的,直接使用 DefaultSelenium 就可以了:

Selenium selenium = new DefaultSelenium(“{grid_server}”, \
4444, “*firefox”, “https://apps.na.collabserv.com/”);

对于 WebDriver 的 node 的话,我们需要使用 RemoteDWebriver 和 DesiredCapabilities 来定义你想向 Selenium Grid 申请的浏览器的类型,版本号等等,例如下面的 capability 就可以匹配到browserName=firefox,version=17,platform=WINDOWS的浏览器:

DesiredCapabilities capability = DesiredCapabilities.firefox();
capability.setBrowserName(“firefox” );
capability.setPlatform(“WINDOWS”);
capability.setVersion(“17.0.1”); WebDriver driver = new RemoteWebDriver(\
new URL("http://{grid_driver}:4444/wd/hub"), capability);

其实,除了将 Selenium Grid 合并到 Selenium 2 中以及加入对 WebDriver 的支持之外,没有太大的改变,Selenium Grid 的使用方面没有太大的区别,可以参考官方网站获得更多信息:http://code.google.com/p/selenium/wiki/Grid2

小结

WebDriver 有更简洁的 API,它针对各个浏览器而开发,取代了嵌入到被测 Web 应用中的 JavaScript。它与浏览器的紧密集成支持创建更高级的测试,避免了 JavaScript 安全模型导致的限制。除了来自浏览器厂商的支持之外,WebDriver 还可以利用操作系统级的调用模拟用户输入,例如鼠标和键盘操作,这些都是 Selenium 所不能比拟的。

而 Selenium 可以使用任何支持 HTTP 的编程语言,它基于 Javasript 并支持多数浏览器,但它也不是完美的,由于浏览器对于 Javascript 的安全策略的加强导致某些情况下不能使用 Selenium。而且随着 WebDriver 的逐步完善,Selenium 可能将完全不受支持,所以选择 WebDriver 必将成为一个必然趋势。但毋庸置疑的是两个项目的将为用户提供了一个更为通用的强大的 Web 测试框架。

 

从 Selenium RC 迁移到 WebDriver

步骤

在 Selenium 2 发布之前,很多测试团队已经开始使用 Selenium 的 Selenium RC 并构建了成熟的测试框架,那么重构并将原有的测试脚本迁移到 Selenium 2 上无疑是一项非常巨大的工作。幸好 Selenium 2 提供了相应的 WebDriver 做为支持。

WebDriverBackendSelenium 为用户提供 Selenium 的实现,即是,我们已经使用 Selenium API 编写的测试脚本,可以在 WebDriver 下面使用。比如我们要在 Firefox 上面进行测试,在创建 selenium 实例的时候,可以修改为:

WebDriver driver = new FirefoxDriver();
Selenium selenium = new WebDriverBackedSelenium(driver, "https://apps.na.collabserv.com/");

编译并运行测试,会发现还会存在一些 fail 的地方,这意味着你需要重新调试代码,使已有的测试脚本完全的支持 WebDriver。下面是笔者在做移植的时候遇到的一些问题:

  • waitForPageToLoad():在移植到 WebDriver 后,会 fail 到测试脚本,所以需要重写来支持页面等待
  • fireEvent():例如实现 mouseover 的功能,在移植后可以使用 Action 类来实现,它给用户提供了一些模拟用户交互的方法,比如 mouse_to 等
  • keyUp,keyDown,KeyPress:在原来的 Selenium 的代码中大量应用了这几个方法,在移植后统一用 sendKeys()来代替了,这也正正说明了 WebDriver 有着更为简洁的 API

在移植的时候不同的自动化测试项目遇到的问题可能是不同的,但基本都是可以在 WebDriver 中找到相应的解决方法。事实上,单单完成上面的步骤是非常容易使原有使用 Selenium 的代码运行在 WebDriver 上面,但完成移植还有重要的一步就是重写代码使它使用 WebDriver API,这个就比较依赖于原来的代码的设计,如果调用 Selenium API 的方法遍布于 testcase、task 层等等,那么可能就需要比较长的时间来完全使用 WebDriver API 了。所以一个自动化测试项目的设计也是非常重要的。

使测试脚本兼容 Selenium 和 WebDriver

既然现在 Selenium 和 WebDriver 还各有优势,我们可以灵活设计自己的自动化测试项目,使其能够根据测试需求来选择测试工具。比如,测试 Safari,我们可以选择 Selenium,测试 Firefox,Chrome 等等就选择使用 WebDriver。这样的话,就需要抽象出更加灵活的自动化测试框架,比如,我们可以根据页面测试元素类型来抽象出不同的 widgets,例如 WebLink,WebText 等等,对这个元素的操作都封装在 widget 之内,那么在编写测试脚本的时候可以很大程度的使测试脚本和测试工具相分离,不仅可以使得测试脚本能够支持不同的测试工具,也使得在移植测试脚本的时候可 以最大限度的降低工作量。

Selenium VS Webdriver的更多相关文章

  1. 【转】selenium及webdriver的原理

    主要内容转自:http://blog.csdn.net/ant_ren/article/details/7968582和http://blog.csdn.net/ant_ren/article/det ...

  2. selenium及webdriver的原理

    主要内容转自:http://blog.csdn.net/ant_ren/article/details/7968582和http://blog.csdn.net/ant_ren/article/det ...

  3. selenium和webdriver区别

    接触selenium大概半年时间了.从开始的预研,简单的写个流程到后期的自动化框架的开发,因为本人不属于代码方面的大牛,一直的边研究边做.逐步深入学习.近期发现自己对本身selenium的发展还存在困 ...

  4. Selenium的webdriver的常用方法,鼠标事件

    就来认识 WebDriver 中最常用的几个方法: get():跳转到的地址clear(): 清除文本. send_keys (value): 模拟按键输入. click(): 单击元素. 示例: f ...

  5. selenium调用webdriver异常

    使用selenium调用webdriver的时候报错. from selenium import webdriver browser = webdriver.Chrome() browser.get( ...

  6. Selenium:WebDriver简介及元素定位

    参考内容:官方API文档,下载链接:http://download.csdn.net/detail/kwgkwg001/4004500 虫师:<selenium2自动化测试实战-基于python ...

  7. selenium及webdriver的原理【转】

    selenium与webdriver整合后,形成的新的测试工具叫做selenium2.x.在selenium1时间,selenium使用javascript来达到测试自动化的目标. 1. seleni ...

  8. 第五种方式,python使用组合来添加类方法和属性(二),以selenium的webdriver为例

    组合优点多,但经常比继承需要额外的代码. 上一篇是 介绍装饰器.继承.元类.mixin,四种給类动态添加类属性和方法的四种方式. 此篇介绍直接把被组合的类的属性直接加入到类里面,前面的四个例子很简单, ...

  9. Python+Selenium(webdriver常用API)

    总结了Python+selenium常用的一些方法函数,以后有新增再随时更新: 加载浏览器驱动: webdriver.Firefox() 打开页面:get() 关闭浏览器:quit() 最大化窗口:  ...

  10. How to set Selenium Python WebDriver default timeout?

    Trying to find a good way to set a maximum time limit for command execution latency in Selenium Pyth ...

随机推荐

  1. centos 安装 jdk PostgreSQL

    1.下载: anzhuang  jDK http://blog.csdn.net/youzhouliu/article/details/51183115 ----------------------- ...

  2. 计算机网络协议层次(转发:http://blog.csdn.net/gavin_john/article/details/53186570)

    计算机网络学习的核心内容就是网络协议的学习.网络协议是为计算机网络中进行数据交换而建立的规则.标准或者说是约定的集合.计算机网络协议同我们的语言一样,多种多样. 为了给网络协议的设计提供一个结构,网络 ...

  3. linux 基础2-null,cut,wc,head,tail

    一. 特殊文件: /dev/null和/dev/tty Linux系统提供了两个对Shell编程非常有用的特殊文件,/dev/null和/dev/tty.其中/dev/null将会丢掉所有写入它的数据 ...

  4. Spark Mllib源码分析

    1. Param Spark ML使用一个自定义的Map(ParmaMap类型),其实该类内部使用了mutable.Map容器来存储数据. 如下所示其定义: Class ParamMap privat ...

  5. 3D卡片折叠动画自定义下拉框

    在线演示 本地下载

  6. 使用Pydoc生成文档

    Python中本身带有很多实用的工具,如pydoc.pydoc模块主要用来从Python模块中提取信息并生成文档. 使用方法 在Windows和Linux下的使用方法有些区别. Windows pyt ...

  7. stack-铁轨问题

    每辆火车都从A方向驶入车站,再从B方向驶出车站,同时它的车厢可以进行某种形式的重新组合.假设从A方向驶来的火车有n节车厢(n<1000),分别按顺序编号为1,2,...,n.假定在进入车站之前每 ...

  8. linux ps aux 结果解释

    # ps aux | moreUSER       PID  %CPU   %MEM   VSZ    RSS    TTY                   STAT       START    ...

  9. 在Treeview中节点的data属性中保存记录类型及其消除的办法

    一.保存记录类型在data指针中: procedure TForm1.getheaditems(pp:TfrxBand;hnode:THeadTreeNode;var i:Integer;var j: ...

  10. 表达式语句(EL)

    EL的基本语法 ${expression} Expression:制定要输出的变了或字符串.或EL运算符组成的表达式. 禁用EL表达式: 1. 使用“\”符号禁用. \${expression} 2. ...