抓取微博数据:使用HtmlUnitDriver实现模拟登陆
前言
作为小白的我而言,对于各种网络数据抓取也不少了,但是在抓取过程之中坑点也不少的,这里就分享一下对于需要登陆的网页的处理,我们整体思路是这样的,我们通过对该网站的登录之后拿到该网站的Cookie,然后拿着获取到的Cookie再去我们想要爬取的地址进行数据爬取.
Selenium简介
Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。
而我用到的HtmlUnitDriver是Selenium众多工具中一个基于HtmlUnit的无界面实现,即使用HtmlUnit时并不会打开真实的浏览器,而是在内存中执行代码,因此运行速度很快,但是对JavaScript的支持不够好,当页面上有复杂的JavaScript元素时,经常捕捉不到。
当我们需要Selenium的时候,我们可以添加Maven依赖.如下所示.
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.4.0</version>
</dependency>
HtmlUnitDriver的鼠标和键盘事件
我们平常在普通一个网站登录的时候都会使用到我们的键盘和鼠标来进行一系列的用户交互操作.那么我们在HtmlUnitDriver该如何实现键盘的输入和鼠标的点击呢?在其实现的接口类WebDeriver中有一个专门的类来负责实现这些测试场景,那就是 Actions 类,在使用该类的过程中会配合使用到 Keys 枚举以及 Mouse、 Keyboard、CompositeAction 等类。下面我就分别简单介绍鼠标事件和键盘事件的实现.
鼠标事件
- 鼠标左键点击
Actions action = new Actions(driver);
action.click();// 鼠标左键在当前停留的位置做单击操作
action.click(driver.findElement(By.name(element)))// 鼠标左键点击指定的元素
- 鼠标右键点击
Actions action = new Actions(driver);
action.contextClick();// 鼠标右键在当前停留的位置做单击操作
action.contextClick(driver.findElement(By.name(element)))// 鼠标右键点击指定的元素
- 鼠标双击操作
Actions action = new Actions(driver);
action.doubleClick();// 鼠标在当前停留的位置做双击操作
action.doubleClick(driver.findElement(By.name(element)))// 鼠标双击指定的元素
- 鼠标拖拽动作
Actions action = new Actions(driver);
// 鼠标拖拽动作,将 source 元素拖放到 target 元素的位置。
action.dragAndDrop(source,target);
// 鼠标拖拽动作,将 source 元素拖放到 (xOffset, yOffset) 位置,其中 xOffset 为横坐标,yOffset 为纵坐标。
action.dragAndDrop(source,xOffset,yOffset);
- 释放鼠标
Actions action = new Actions(driver);
action.release();// 释放鼠标
键盘事件
对于键盘的模拟操作,Actions 类中有提供 keyUp(theKey)、keyDown(theKey)、sendKeys(keysToSend) 等方法来实现。键盘的操作有普通键盘和修饰键盘(Modifier Keys, 下面的章节将讲到修饰键的概念)两种 :
- 普通键盘模拟 sendKeys(keysToSend)
Actions action = new Actions(driver);
action.sendKeys(Keys.TAB);// 模拟按下并释放 TAB 键
action.sendKeys(Keys.SPACE);// 模拟按下并释放空格键
/***
针对某个元素发出某个键盘的按键操作,或者是输入操作,
比如在 input 框中输入某个字符也可以使用这个方法。这个方法也可以拆分成:
action.click(element).sendKeys(keysToSend)。
*/
action.sendKeys(element,keysToSend);
- 对于修饰键(Modifier keys),一般都是跟普通键组合使用的。比如 Ctrl+a、Alt+F4、 Shift+Ctrl+F 等等。
Actions action = new Actions(driver);
action.keyDown(Keys.CONTROL);// 按下 Ctrl 键
action.keyDown(Keys.SHIFT);// 按下 Shift 键
action.keyDown(Key.ALT);// 按下 Alt 键
action.keyUp(Keys.CONTROL);// 释放 Ctrl 键
action.keyUp(Keys.SHIFT);// 释放 Shift 键
action.keyUp(Keys.ALT);// 释放 Alt 键
示例:通过 Alt+F4 来关闭当前的活动窗口,可以通过下面语句来实现.
action.keyDown(Keys.ALT).keyDown(Keys.F4).keyUp(Keys.ALT).perform();`
使用 HtmlUnitDriver 模拟登录微博账号(基于Selenium:3.4.0实现)
上面我们对HtmlUnitDriver的使用有了初步的了解,下面我们就要模拟登录微博账号.由于数据抓取是通过www.weibo.cn而不是www.weibo.com.所以我们要通过https://passport.weibo.cn/signin/login这个登录地址来登录.我们首先要打开这个网站地址,分析这个网站有什么是我们需要.网站上的元素很少.我们需要账号输入框、密码输入框和登录按钮的点击事件.
然后我们通过控制台来获取这个三个元素.如下所示.(因为我先前登陆过,所以Cookie里面会有我的信息)
好了,准备工作已经做完了,那么接下来我们就需要搞我们的代码了.代码比较简单,这里就不过多解释了.
//初始化一个HtmlUnitDriver对象
HtmlUnitDriver driver = new HtmlUnitDriver(BrowserVersion.FIREFOX_52);
driver.setJavascriptEnabled(true);//允许JS操作
driver.get("https://passport.weibo.cn/signin/login");
driver.executeScript("document.getElementById('loginWrapper').style.display = 'block'");//隐藏新浪微博登录的验证码
//找到账号输入框,输入用户账号
WebElement mobile = driver.findElementByCssSelector("input#loginName");
mobile.sendKeys(username);
//找到密码输入框,输入用户密码
WebElement pass = driver.findElementByCssSelector("input#loginPassword");
pass.sendKeys(password);
//输入完成之后,点击登录按钮
WebElement submit = driver.findElementByCssSelector("a#loginAction");
submit.click();
driver.close();//关闭浏览器
那么我们该如何拿到Cookie字符串呢?这里登录完成之后,HtmlUnitDriver就存储了Cookie信息,我们直接拿出来就行,代码如下所示.
Set<Cookie> cookieSet = driver.manage().getCookies();
StringBuilder sb = new StringBuilder();
for (Cookie cookie : cookieSet) {
sb.append(cookie.getName() + "=" + cookie.getValue() + ";");
}
String result = sb.toString();//拼接好的Cookie信息
整体代码如下所示.
public static String getSinaCookie(String username, String password) throws Exception {
//初始化一个HtmlUnitDriver对象
HtmlUnitDriver driver = new HtmlUnitDriver(BrowserVersion.FIREFOX_52);
driver.setJavascriptEnabled(true);//允许JS操作
driver.get("https://passport.weibo.cn/signin/login");
driver.executeScript("document.getElementById('loginWrapper').style.display = 'block'");//隐藏新浪微博登录的验证码
//找到账号输入框,输入用户账号
WebElement mobile = driver.findElementByCssSelector("input#loginName");
mobile.sendKeys(username);
//找到密码输入框,输入用户密码
WebElement pass = driver.findElementByCssSelector("input#loginPassword");
pass.sendKeys(password);
//输入完成之后,点击登录按钮
WebElement submit = driver.findElementByCssSelector("a#loginAction");
submit.click();
String result = concatCookie(driver);
System.out.println("Get Cookie: " + result);
driver.close();//关闭浏览器
if (result.contains("SUB")) {
return result;
} else {
throw new Exception("weibo login failed");
}
}
public static String concatCookie(HtmlUnitDriver driver) {
Set<Cookie> cookieSet = driver.manage().getCookies();
StringBuilder sb = new StringBuilder();
for (Cookie cookie : cookieSet) {
sb.append(cookie.getName() + "=" + cookie.getValue() + ";");
}
String result = sb.toString();
return result;
}
通过控制台的打印,我们就能获得我们所需要的Cookie字符串了.如下所示.
总结
这篇博客写到这就到了尾声了,有一点要注意,那就是使用HtmlUnitDriver时候,可能会链接失败,现在未找到原因,希望有知道的大佬能提点下.文章很多点都可能模糊不清,所以如果有错误,欢迎指导批评,非常感谢各位大佬.
本文参考文章:
Selenium WebDriver 中鼠标和键盘事件分析及扩展
Java开源爬虫框架WebCollector教程——爬取新浪微博