WebMagic虽然使用方便,但奈何针对性太强,而且模拟请求的方法很容易被发现以及被反爬,所以在多次因网站更新而被迫跟新爬虫的教训下,决定使用selenium来模拟点击获取内容。
这是依赖:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
?因为本身selenium就是用于自动化测试的,更像是一个脚本,所以相比于WebMagic更灵活,也更不容易被反爬
public class BaiduTest {
public static void main(String[] args) {
String url = "https://index.baidu.com/v2/index.html#/";
runTest(url);
}
private static void runTest(String url) {
//需要下载浏览器驱动,来模拟浏览器,这里用的是火狐,下载地址:https://github.com/mozilla/geckodriver/releases
System.setProperty("webdriver.gecko.driver", "D:\\workspace\\MyWorkTools\\geckodriver.exe");
//创建驱动器
FirefoxDriver driver = new FirefoxDriver();
//导入初始URL
driver.get(url);
try {
//直接识别页面的html标签,也可以使用xpath,如果要爬取的网站不需要登录,则直接忽略这一段
WebElement selector = driver.findElementByCssSelector("登录按钮的标签");
//添加点击事件
selector.click();
//缓一缓,避免页面没有刷新出来导致报错
Thread.sleep(3000);
//如果需要登录,则获取登录框的html标签
WebElement selector1 = driver.findElementByCssSelector("登录框的html标签");
//在标签中添加用户名
selector1.sendKeys("用户账号");
Thread.sleep(1000);
//获取用户密码输入框的标签
WebElement selector2 = driver.findElementByCssSelector("用户密码输入框的标签");
selector2.sendKeys("用户密码");
Thread.sleep(2000);
//点击登录
driver.findElementByCssSelector("登录按钮的HTMl标签").click();
Thread.sleep(3000);
//遇到滑动框验证
WebElement ele = driver.findElementByCssSelector("滑动框html标签");
//获取滑动框高度,可以不加
int y = ele.getSize().getHeight();
//为了通过滑块验证,创建一个随机数,随机拉动滑块长度,知道正好对上(纯看运气,但你要相信,总归会对上的)
//当然也可以记录正确滑块的长度,然后自己写一个随机池
while (true){
WebElement sour = driver.findElementByCssSelector("滑块的标签");
Random rand = new Random();//创建一个随机数,也就是滑块的距离
int x = rand.nextInt(160)+50;//限制滑块距离的范围
Actions action = new Actions(driver);//创建一个动作
action.dragAndDropBy(sour, x,y).perform();//动作为按住并拖动到指定长度x轴和高度y轴
Thread.sleep(2000);
//如果滑块验证通过(抓不到验证窗口的元素了,就说明过了),则滑块窗口就无法抓取到,跳出while循环
boolean b = ElementExist(driver,"滑块窗口的html标签");
if (!b){
break;
}
}
Thread.sleep(3000);
//判断是否弹出短信验证码的窗口
boolean b = ElementExist(driver,"短信验证窗口html标签");
//如果存在短信验证码窗口,则进入短信验证
if (b){
Thread.sleep(1000);
//先点击发送短信验证码
WebElement Testelement = driver.findElementByCssSelector("发送短信验证码按钮的标签");
Testelement.click();
Thread.sleep(1000);
//需要控制台输入收到的验证码
String Test=new Scanner(System.in).nextLine();
//将验证码输入到框内
driver.findElementByCssSelector("验证码输入框的标签").sendKeys(Test);
Thread.sleep(3000);
//点击确定
driver.findElementByCssSelector("确定按钮的标签").click();
Thread.sleep(3000);
}
//一个输入动作,要搜索的内容
driver.findElementByCssSelector("搜索框的标签").sendKeys("要搜索的内容");
Thread.sleep(1000);
//点击搜索
driver.findElementByCssSelector("搜索按钮的标签").click();
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
try {
//这下面是对于 鼠标悬浮才能触发的标签 进行信息获取
//获取折线图对象,每次光标右移39xp,则显示下个指数
WebElement mb30 = driver.findElementByCssSelector("div.mb30 div.index-trend-chart div:nth-child(2)");
Thread.sleep(1000);
//创建一个鼠标动作
Actions actions = new Actions(driver);
Thread.sleep(1000);
for (int i = 0; i < 30; i++) {//因为是按照最近三十天来算,其他天数需要另算距离
//这是一个鼠标移动并悬停的动作
actions.moveToElement(driver.findElement(By.cssSelector("div.mb30 div.content-wrapper")),(i*39)-550,100).perform();
//获得日期
String text1 = mb30.findElement(By.cssSelector("div:nth-child(1)")).getText().replaceAll("[([^(0-9)(^\\-)])*]","");
//获得指数
String text2 = mb30.findElement(By.cssSelector("div:nth-child(2)>div:nth-child(2)>div:nth-child(2)")).getText();
System.out.println("日期:"+text1+" 指数:"+text2);
//每次获取指数后鼠标悬停1秒
Thread.sleep(1000);
}
} catch (Exception e) {
System.out.println("==============完成============");
}
}
//判断元素是否存在,因为selenium本身没有判断,没找到元素直接就抛出错误,所以得自定义一个判断
public static boolean ElementExist(WebDriver driver,String locator)
{
try {
driver.findElement(By.cssSelector(locator));
return true;
} catch (Exception e) {
return false;
}
}
}
|