java操作selenium(二)-微博自动登录后回复
简单介绍下逻辑
步骤:
1.登录
先判断是否有cookie,有cookie直接登录,cookie失效使用账号密码登录,开始尝试登录,登录时会判断是否需要验证码(我用的是云打码平台,百度一下就知道了,这里就不做阐述,代码关于打码平台的没放出来,需要的去网上百度下)
2.回复 ps:这些id都是微博的,爬虫可以拿到
url就不用说了,我们肯定要到这个微博页面,自然需要微博的链接
content就是要回复的内容
comm_id和pid如果都为空,那就是对话题的回复
comm_id不为空,pid为空就是对以及评论的回复
comm_id和pid都不为空,就是对二级评论的回复,pid对应一级评论id
3.对话题的回复结果
成功,返回我们回复的这条评论的id
失败
无法回复(用户设置,不让评论)
对一级评论的回复结果
成功,返回我们回复的这条评论的id
失败
对二级评论的回复结果
成功,返回我们回复的这条评论的id
失败
public static void main(String[] args) throws InterruptedException {
try {
SeleniumDriver instance = SeleniumDriver.getInstance();
// String url = "https://weibo.com/6349791448/H6HN8vdb4?type=comment#_rnd1546914289648";
String url = "https://weibo.com/1640016932/HaItFxbA1?ref=feedsdk&type=comment#_rnd1546917218511";
String content = "ee";
String comm_id = "4325613483241748";
String pid = "4325542939353552";
String res = instance.reply("https://weibo.com/1843911585/HaxHv0BXA?refer_flag=1001030103_&type=comment", content, null, null);
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
}
}
话不多说,上代码
import com.alibaba.fastjson.JSON;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;
import javax.imageio.ImageIO;
import com.lucky.tancms.tancms.util.ConstantUtil;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import org.codehaus.plexus.util.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by rui on 2018/11/24.
*/
public class SeleniumDriver {
private static final Logger logger = LoggerFactory.getLogger(SeleniumDriver.class);
private static WebDriver driver = null;
private int login_time = 0; // 登录次数
private SeleniumDriver() {
logger.info("初始化SeleniumDriver");
System.setProperty("webdriver.chrome.driver","C:\\Users\\admin\\Downloads\\chromedriver.exe");
try {
/*Map<String, Object> contentSettings = new HashMap<String, Object>();
contentSettings.put("images", 2);
Map<String, Object> preferences = new HashMap<String, Object>();
preferences.put("profile.default_content_setting_values", contentSettings);
*/
ChromeOptions options = new ChromeOptions();
//--headless
options.addArguments("--test-type --no-sandbox --disable-dev-shm-usage --disable-gpu --disable-infobars");
options.addArguments("--enable-strict-powerful-feature-restrictions");
//options.setExperimentalOption("prefs", preferences);
DesiredCapabilities caps = DesiredCapabilities.chrome();
caps.setCapability(ChromeOptions.CAPABILITY, options);
driver = new ChromeDriver(caps);
driver.manage().window().maximize();
login();
} catch (Exception e) {
logger.error("driver初始化失败" + e.toString() + "\n" + Arrays.toString(e.getStackTrace()));
e.printStackTrace();
}
}
private void login() throws Exception {
logger.info("driver初始化完成,准备跳转到登录页面");
driver.get("https://weibo.com/");
// logger.info(MyLog.getInfo() + " 登录页面");
Thread.sleep(15000);
driver.manage().deleteAllCookies();
// 1、通过cookie登录
String path = SeleniumDriver.class.getResource("").getPath();
String cookie_path = path + "cookies.txt";
try {
Map<String, String> cookies = loadCookies(cookie_path);
for (Map.Entry<String, String> cookie : cookies.entrySet()) {
driver.manage().addCookie(new Cookie(cookie.getKey(), cookie.getValue()));
}
Thread.sleep(1000);
driver.navigate().refresh();
Thread.sleep(20000);
// 2、判断通过cookie是否登录成功
int loop_num = 0;
while (loop_num < 3) {
boolean login_status = getLoginStatus();
if (login_status) {
break;
} else {
// 等待5秒,再次判断
loop_num ++;
Thread.sleep(5000);
}
}
} catch (Exception e) {
System.out.println("加载cookie失败。。。");
}
boolean login_status = getLoginStatus();
// 如果还未登录成功,则重新登录
if (login_status) {
return;
} else {
try {
// 登录
WebElement login_name = driver.findElement(By.xpath("//*[@id=\"loginname\"]"));
JavascriptExecutor js = (JavascriptExecutor) driver;
if (login_name != null) {
js.executeScript("arguments[0].click();", login_name);
js.executeScript("arguments[0].value = '';", login_name);
for (String str : "18911976770".split("")) {
js.executeScript("arguments[0].value +='" + str + "';", login_name);
Thread.sleep(600);
}
}
WebElement password = driver.findElement(By.xpath("//div[@node-type='normal_form']/div[@class='info_list password']"
+ "/div[@class='input_wrap']/input[@type='password']"));
if (password != null) {
js.executeScript("arguments[0].click();", password);
js.executeScript("arguments[0].value = '';", password);
// password.sendKeys("hht525252");
for (String str : "miao...123".split("")) {
js.executeScript("arguments[0].value +='" + str + "';", password);
Thread.sleep(600);
}
}
// 判断是否需要输入验证码
try {
WebElement login_btn = driver.findElement(By.xpath("//div[@node-type='normal_form']/div[@class='info_list login_btn']/a[@node-type='submitBtn']"));
if (login_btn != null) {
js.executeScript("arguments[0].click();", login_btn);
}
Thread.sleep(3000);
WebElement verifycode_div = driver.findElement(By.xpath("//div[@node-type='verifycode_box']"));
if (verifycode_div.isDisplayed()) {
// 请求云打码平台,获得验证码
String captcha_path = path + "captcha.png";
String code = getVerifyCode(captcha_path);
WebElement verifycode_input = driver.findElement(By.xpath("//input[@name='verifycode']"));
for(String str : code.split("")) {
verifycode_input.sendKeys(str);
Thread.sleep(300);
}
} else {
System.out.println("***** 不需要输入验证码 *****");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("***** 不需要输入验证码 *****");
}
WebElement login_btn = driver.findElement(By.xpath("//div[@node-type='normal_form']/div[@class='info_list login_btn']/a[@node-type='submitBtn']"));
if (login_btn != null) {
js.executeScript("arguments[0].click();", login_btn);
}
Thread.sleep(30000);
} catch (Exception e) {
e.printStackTrace();
}
// 判断是否登录成功
login_status = getLoginStatus();
if (login_status) {
// 保存cookie
saveCookies(cookie_path);
} else {
if (login_time < 3) {
// 未登录成功,重新登录
login();
} else {
throw new Exception(" ***** 登录失败 *****");
}
}
}
Thread.sleep(10000);
}
/**
* 获得验证码
* @return
*/
private String getVerifyCode(String captchaPath) throws Exception {
// 1、获得验证码图片
File file = new File(captchaPath);
if (file.exists()) {
file.delete();
}
getCaptchaImage(captchaPath);
// 2、请求,获得验证码
String verifyCode = CYDM.getVerifyCode(captchaPath);
return verifyCode;
}
private void getCaptchaImage(String fileName) throws Exception {
// 1、获取验证码图片位置
Map<String, Integer> pos = getVerifycodeImagePos();
int top = pos.get("top").intValue();
int left = pos.get("left").intValue();
int height = pos.get("height").intValue();
int width = pos.get("width").intValue();
File screen = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
BufferedImage screen_img = ImageIO.read(screen);
BufferedImage captcha_img = screen_img.getSubimage(left, top, width, height);
ImageIO.write(captcha_img, "png", screen);
// 2、保存
FileUtils.copyFile(screen, new File(fileName));
}
/**
* 获得验证码图片位置
* @return
*/
private Map<String, Integer> getVerifycodeImagePos() throws Exception {
try {
WebElement verifycode_image = new WebDriverWait(driver, 10).until(new ExpectedCondition<WebElement>() {
@Override
public WebElement apply(@NullableDecl WebDriver webDriver) {
return webDriver.findElement(By.xpath("//img[@node-type='verifycode_image']"));
}
});
int width = verifycode_image.getSize().getWidth();
int height = verifycode_image.getSize().getHeight();
// 得到元素坐标
Point p = verifycode_image.getLocation();
Map<String, Integer> map = new HashMap<>();
map.put("top", p.getY());
map.put("left", p.getX());
map.put("height", height);
map.put("width", width);
return map;
} catch (Exception e) {
throw new Exception("***** 获取验证码图片失败 *****");
}
}
/**
* 加载cookie
**/
private Map<String, String> loadCookies(String path) throws Exception {
File file = new File(path);
if (!file.exists()) {
throw new Exception("***** not found cookies file");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
Map<String, String> cookies = new HashMap<>();
String content = null;
while ((content = reader.readLine()) != null) {
String[] cookie = content.split(";");
for (String str : cookie) {
String[] tmp = str.split(":");
cookies.put(tmp[0], tmp[1]);
}
}
reader.close();
return cookies;
}
/**
* 保存cookie
**/
private void saveCookies(String path) throws Exception {
Set<Cookie> cookies = driver.manage().getCookies();
StringBuilder data = new StringBuilder();
for (Cookie cookie : cookies) {
data.append(cookie.getName()).append(":").append(cookie.getValue()).append(";");
}
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path), "UTF-8"));
writer.write(data.toString());
writer.flush();
writer.close();
}
/**
* 获得登录状态
**/
private boolean getLoginStatus() {
try {
driver.findElement(By.xpath("//div[@class='gn_nav']/ul[@class='gn_nav_list']/li/a[@class='gn_name']"));
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public Cookie getCookie(String s) {
Cookie cookie = null;
Map<String, Object> map = JSON.parseObject(s, Map.class);
String domain = map.get("domain").toString();
Boolean httpOnly = Boolean.parseBoolean(map.get("httpOnly").toString());
String name = map.get("name").toString();
String path = map.get("path").toString();
boolean secure = Boolean.parseBoolean(map.get("secure").toString());
String value = map.get("value").toString();
if (map.containsKey("expiry")) {
String expiry = map.get("expiry").toString();
cookie = new Cookie(name, value, domain, path, null, secure, httpOnly);
} else {
cookie = new Cookie(name, value, domain, path, null, secure, httpOnly);
}
return cookie;
}
private static class SeleniumDriverHolder {
public static final SeleniumDriver SELENIUM_DRIVER = new SeleniumDriver();
}
public static SeleniumDriver getInstance() {
return SeleniumDriverHolder.SELENIUM_DRIVER;
}
public WebDriver getDriver() {
return driver;
}
public String reply(String url, String replyCont, String comm_id, String pid) throws Exception {
WebDriver driver = SeleniumDriver.getInstance().getDriver();
driver.get(url);
boolean is_logined = getLoginStatus();
if (!is_logined) {
System.out.println("***** 未登录 *****");
try {
login();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
Thread.sleep(7000);
JavascriptExecutor js = (JavascriptExecutor) driver;
try {
List<WebElement> comment_list = driver
.findElements(By.xpath(".//div[@class='list_box']/div[@node-type='comment_list']/div"));
if ("-1".equals(pid)) { // 一级评论
String first_comment_id = null;
if (comment_list.size() > 0) {
first_comment_id = comment_list.get(0).getAttribute("comment_id");
}
int parsed_num = 0;
// int total_num = 0;
while (true) {
// total_num += comment_list.size();
for (WebElement commDiv : comment_list) {
try {
String comment_id = commDiv.getAttribute("comment_id");
parsed_num ++;
js.executeScript("arguments[0].scrollIntoView();", commDiv);
if (comm_id.equals(comment_id)) {
// 找到相应的div,点击回复,输入内容
WebElement replay_span = commDiv.findElement(By.xpath(".//a[@action-type='reply']"));
js.executeScript("arguments[0].click();", replay_span);
Thread.sleep(500);
WebElement textarea = commDiv.findElement(By.xpath(".//textarea[@node-type='textEl']"));
textarea.sendKeys(replyCont);
Thread.sleep(800);
// 提交
WebElement do_reply = commDiv.findElement(By.xpath(".//a[@action-type='doReply']"));
js.executeScript("arguments[0].click();", do_reply);
Thread.sleep(500);
// 获得评论id
// String comm_id = null;
// List<WebElement> list_box = commDiv.findElements(By.xpath(".//div[@class='list_box']/div[@node-type='comment_list']/div"));
List<WebElement> list_box = commDiv.findElements(By.xpath(".//div[@class='list_box_in S_bg3']/div[@class='list_ul']/div"));
if (list_box.size() > 0) {
String new_comm_id = list_box.get(0).getAttribute("comment_id");
if (first_comment_id.equals(new_comm_id)) {
// 相同,则评论失败
System.out.println("***** 评论失败");
} else {
return new_comm_id;
}
} else {
return null;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
comment_list.clear();
Thread.sleep(3000);
comment_list = driver
.findElements(By.xpath(".//div[@class='list_box']/div[@node-type='comment_list']/div"));
if (comment_list.size() - parsed_num > 1) {
comment_list = comment_list.subList(parsed_num - 1, comment_list.size() - 1);
continue;
} else {
// 查看更多
try {
WebElement more_comment = driver.findElement(By.xpath(".//a[@action-type='click_more_comment']"));
((JavascriptExecutor) driver).executeScript("arguments[0].click();", more_comment);
} catch (Exception e) {
e.printStackTrace();
}
Thread.sleep(5000);
comment_list = driver
.findElements(By.xpath(".//div[@class='list_box']/div[@node-type='comment_list']/div"));
if (comment_list.size() - parsed_num > 1) {
comment_list = comment_list.subList(parsed_num - 1, comment_list.size() - 1);
continue;
} else {
break;
}
}
}
} else if (pid != null){ // 二级评论
int parsed_num = 0;
while (true) {
for (WebElement commDiv : comment_list) {
try {
String comment_id = commDiv.getAttribute("comment_id");
parsed_num ++;
js.executeScript("arguments[0].scrollIntoView();", commDiv);
if (pid.equals(comment_id)) {
// 找到相应的评论,再找其二级评论
Thread.sleep(2000);
while (true) {
try {
WebElement child_more_comment = commDiv.findElement(By.xpath(".//div[@node-type='more_child_comment']/div[@class='WB_text']/a[@action-type='click_more_child_comment_big']"));
((JavascriptExecutor) driver).executeScript("arguments[0].click();", child_more_comment);
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
break;
}
}
List<WebElement> child_comments = commDiv.findElements(By.xpath(".//div[@node-type='child_comment']"));
child_comments = child_comments.get(1).findElements(By.xpath("./div"));
for (WebElement childCommDiv : child_comments) {
try {
String child_comment_id = childCommDiv.getAttribute("comment_id");
js.executeScript("arguments[0].scrollIntoView();", childCommDiv);
if (comm_id.equals(child_comment_id)) {
// 找到相应的评论,点击“回复”,输入回复内容,提交
WebElement reply_a = childCommDiv
.findElement(By.xpath(".//a[@action-type='reply']"));
js.executeScript("arguments[0].click();", reply_a);
Thread.sleep(1000);
WebElement textarea = childCommDiv
.findElement(By.xpath(".//textarea[@node-type='textEl']"));
textarea.sendKeys(replyCont);
Thread.sleep(800);
WebElement reply_btn = childCommDiv.findElement(By.xpath(".//a[@action-type='doReply']"));
js.executeScript("arguments[0].click();", reply_btn);
Thread.sleep(2000);
// 获得comment_id
// String comm_id = null;
List<WebElement> list_box = commDiv
.findElements(By.xpath(".//div[@class='list_box_in S_bg3']"));
if (list_box.size() > 1) {
// 评论成功,有两个“list_box_in S_bg3”div
// 取第一个,即为刚刚增加的评论
WebElement new_comm = list_box.get(0);
WebElement new_comm_div = new_comm.findElement(By.xpath(
".//div[@node-type='child_comment']/div[@class='list_li S_line1 clearfix']"));
comm_id = new_comm_div.getAttribute("comment_id");
return comm_id;
} else {
// 评论失败
System.out.println("评论失败");
return null;
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("对二级评论回复失败");
}
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println(String.format("对评论()回复失败"));
}
}
comment_list.clear();
Thread.sleep(3000);
comment_list = driver
.findElements(By.xpath(".//div[@class='list_box']/div[@node-type='comment_list']/div"));
if (comment_list.size() - parsed_num > 1) {
comment_list = comment_list.subList(parsed_num - 1, comment_list.size() - 1);
continue;
} else {
try {
// 查看是否有“查看更多”
WebElement more_comment = driver.findElement(By.xpath(".//a[@action-type='click_more_comment']"));
((JavascriptExecutor) driver).executeScript("arguments[0].click();", more_comment);
} catch (Exception e) {
e.printStackTrace();
System.out.println("***** 没有更多 *****");
}
Thread.sleep(5000);
comment_list = driver
.findElements(By.xpath(".//div[@class='list_box']/div[@node-type='comment_list']/div"));
if (comment_list.size() - parsed_num > 1) {
comment_list = comment_list.subList(parsed_num - 1, comment_list.size() - 1);
continue;
} else {
break;
}
}
}
} else {
try{
WebElement comm_div = driver.findElement(By.xpath("//div[@class=\"WB_feed_publish clearfix\"]"));
Thread.sleep(1000);
logger.info("获取定位的唯一div");
WebElement reply = comm_div.findElement(By.xpath(".//*/textarea[@node-type=\"textEl\"]"));
js.executeScript("arguments[0].click();", reply);
logger.info("获取输入框并点击");
Thread.sleep(1000);
js.executeScript("arguments[0].value='" + replyCont.replaceAll("'", "\\'") + "';", reply);
Thread.sleep(1000);
logger.info("输入内容");
WebElement submit = comm_div.findElement(By.xpath(".//*/a[@class=\"W_btn_a\"]"));
js.executeScript("arguments[0].click();", submit);
logger.info("提交");
Thread.sleep(15000);
return "";
}catch (Exception e){
e.printStackTrace();
logger.error(MyLog.getInfo() + " " + e.toString() + " 回复失败 url:" + url + " 内容:" + replyCont + "\n" + Arrays.toString(e.getStackTrace()));
try {
Thread.sleep(3000);
driver.findElement(By.xpath("//span[@class=\"W_icon icon_rederrorS\"]"));
logger.error("无法回复");
return "error";
} catch (Exception e1) {
}
return null;
}
}
} catch (Exception e) {
e.printStackTrace();
try {
Thread.sleep(3000);
driver.findElement(By.xpath("//span[@class=\"W_icon icon_rederrorS\"]"));
logger.error("无法回复");
return "error";
} catch (Exception e1) {
}
return null;
}
return null;
}
public void quik() throws InterruptedException {
Thread.sleep(1000);
driver.quit();
logger.info("关闭浏览器");
}
public static void main(String[] args) throws InterruptedException {
try {
SeleniumDriver instance = SeleniumDriver.getInstance();
// String url = "https://weibo.com/6349791448/H6HN8vdb4?type=comment#_rnd1546914289648";
String url = "https://weibo.com/1640016932/HaItFxbA1?ref=feedsdk&type=comment#_rnd1546917218511";
String content = "ee";
String comm_id = "4325613483241748";
String pid = "4325542939353552";
String res = instance.reply("https://weibo.com/1843911585/HaxHv0BXA?refer_flag=1001030103_&type=comment", content, null, null);
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
}
}
}