本来想用Python模拟请求,但是!!经过抓包分析,它的请求里面有两个参数eid和fp是用javaScript动态生成的。顺藤摸瓜,找到javaScript代码,结果!!我看不懂……不仅看不懂,人家是专门做了混淆的…算了,就酱吧,还是乖乖用Selenium操作。
JDLogin:
时间着实有限,所以只拿了自己的帐号(有多页豆豆明细数据的)和一个空白帐号(豆豆数量为0,没有豆豆交易明细数据)做测试,结果都是通过的。如下所示:
JDLoginTest:
JDLogin Code:
package pkg_JDLogin;
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.interactions.Actions;
import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
/**
* Created by Sophie on 03/20/2016
*/
public class JDLogin {
private WebDriver dr;
private String url;
private String account;
private String pwd;
private String myJDXPATH;
private String myBeanXPATH;
private String datesXPATH;
private String transacDetailsXPATH;
private String transacNameXPATH;
private String pageNextXPATH;
private String total;
private List dateDetail;
private List transacDetail;
private List transacName;
public List retrieveJDBeanDatesDetails(){
return dateDetail;
}
public List retrieveJDBeanTransacDetail(){
return transacDetail;
}
public List retrieveJDBeanTransacName(){
return transacName;
}
public JDLogin(String url, String account, String pwd,String myJDXPATH, String myBeanXPATH,
String datesXPATH, String transacDetailsXPATH, String transacNameXPATH, String pageNextXPATH){
this.url = url;
this.dr = new FirefoxDriver();
this.dr.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
this.account = account;
this.pwd = pwd;
this.myJDXPATH = myJDXPATH;
this.myBeanXPATH = myBeanXPATH;
this.datesXPATH = datesXPATH;
this.transacDetailsXPATH = transacDetailsXPATH;
this.transacNameXPATH = transacNameXPATH;
this.pageNextXPATH = pageNextXPATH;
}
public WebDriver login() throws Exception{
dr.get(url);
dr.findElement(By.id("loginname")).clear();
dr.findElement(By.id("loginname")).sendKeys(account);
dr.findElement(By.id("nloginpwd")).clear();
dr.findElement(By.id("nloginpwd")).sendKeys(pwd);
dr.findElement(By.id("loginsubmit")).click();
//System.out.println(dr.getPageSource());
Thread.sleep(2000);
return dr;
}
public WebDriver JDBeanPage(){
WebElement dropDown = dr.findElement(By.xpath(myJDXPATH));
Actions act = new Actions(dr);
act.click(dropDown).perform();
dr.get(dr.findElement(By.xpath(myBeanXPATH)).getAttribute("href"));
return dr;
}
public List getDatesDetail(WebDriver dr){
List e = dr.findElements(By.xpath(datesXPATH));
List result = new ArrayList();
for (int i = 0; i < e.size(); i ++){
result.add(e.get(i).getText());
}
return result;
}
public List getTransacDetail(WebDriver dr){
List e = dr.findElements(By.xpath(transacDetailsXPATH));
List result = new ArrayList();
for (int i = 0; i < e.size(); i ++){
result.add(e.get(i).getText());
}
return result;
}
public List getTransacName(WebDriver dr){
List e = dr.findElements(By.xpath(transacNameXPATH));
List result = new ArrayList();
for (int i = 0; i < e.size(); i ++){
result.add(e.get(i).getText());
}
return result;
}
public void getJDBeanDetails(){
total = dr.findElement(By.cssSelector("strong.ftx01.num")).getText();
//dates that have transactions
dateDetail = getDatesDetail(dr);
//gain or lost JDBean
transacDetail = getTransacDetail(dr);
//name of transac
transacName = getTransacName(dr);
Actions act = new Actions(dr);
//get pages size
List pageHref = dr.findElements(By.xpath("//div[@class='pagin fr']/a[not(@class) and @href]"));
if(pageHref.size() != 0) {
//该用户京豆交易明细至多只有一页的情况
act.moveToElement(pageHref.get(0));
act.click().perform();
}
//System.out.print(dr.getPageSource());
for (int i = 1; i < pageHref.size(); i ++) {
WebElement pageIcon = dr.findElement(By.xpath(pageNextXPATH));
act.moveToElement(pageIcon);
act.click().perform();
//date
dateDetail.addAll(getDatesDetail(dr));
//gain or lost
transacDetail.addAll(getTransacDetail(dr));
//name of transac
transacName.addAll(getTransacName(dr));
}
maskItemNumber(transacName);
System.out.println("共有京豆:" + total + ",明细如下:\n==============================================================================");
for(int i = 0; i < transacName.size(); i ++){
System.out.println(dateDetail.get(i)+"\t\t\t\t\t\t"+transacDetail.get(i)+"\t\t\t\t\t\t"+transacName.get(i));
}
}
public void maskItemNumber(List transacName){
StringBuffer s ;
for (int i = 0; i < transacName.size(); i ++){
if(transacName.get(i).toString().contains("商品")){
s = new StringBuffer(transacName.get(i).toString());
for(int j = 0; j < s.length(); j ++){
if (Character.isDigit(s.charAt(j)))
s.setCharAt(j,'*');
}
transacName.set(i,s.toString());
}
}
}
public void tearDown() throws Exception{
dr.quit();
}
public static void main(String[] args) throws Exception {
String url = "https://passport.jd.com/uc/login?ltype=logout";
Scanner s = new Scanner(System.in);
System.out.println("请输入帐号:");
String account = s.nextLine();
System.out.println("请输入密码:");
String pwd = s.nextLine();
String myJDXPATH = "//li[@id='ttbar-myjd']/div[1]/i[@class='ci-right']/s";
String myBeanXPATH = "//li[@id='ttbar-myjd']/div[2]/div[@class='otherlist']/div[@class='fore2']/div[2]/a";
String datesXPATH = "//span[@class='ftx03']";
String transacDetailsXPATH = "//table[@class='tb-void']/tbody/tr/td[2]/span";
String transacNameXPATH = "//table[@class='tb-void']/tbody/tr/td[3]";
String pageNextXPATH = "//div[@class='pagin fr']/a[@class='current']/following-sibling::a[1]";
JDLogin jd = new JDLogin(url, account, pwd, myJDXPATH, myBeanXPATH, datesXPATH, transacDetailsXPATH, transacNameXPATH, pageNextXPATH);
jd.login();
jd.JDBeanPage();
jd.getJDBeanDetails();
jd.tearDown();
}
}
JUnit测试代码:
package pkg_JDLogin;
import org.junit.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import static org.junit.Assert.*;
import java.util.Scanner;
import static org.hamcrest.Matchers.*;
import java.util.List;
/**
* Created by Sophie on 16/3/20.
*/
public class JDLoginTest {
private JDLogin jd;
private WebDriver dr;
@Before
public void setUpBefore(){
String url = "https://passport.jd.com/uc/login?ltype=logout";
//Scanner s = new Scanner(System.in);
//System.out.println("请输入帐号:");
String pwd = "***";
//System.out.println("请输入密码:");
String account = "***";
String myJDXPATH = "//li[@id='ttbar-myjd']/div[1]/i[@class='ci-right']/s";
String myBeanXPATH = "//li[@id='ttbar-myjd']/div[2]/div[@class='otherlist']/div[@class='fore2']/div[2]/a";
String datesXPATH = "//span[@class='ftx03']";
String transacDetailsXPATH = "//table[@class='tb-void']/tbody/tr/td[2]/span";
String transacNameXPATH = "//table[@class='tb-void']/tbody/tr/td[3]";
String pageNextXPATH = "//div[@class='pagin fr']/a[@class='current']/following-sibling::a[1]";
jd = new JDLogin(url, account, pwd, myJDXPATH, myBeanXPATH, datesXPATH, transacDetailsXPATH, transacNameXPATH, pageNextXPATH);
}
@Test
public void test() throws Exception {
//login
dr = jd.login();
org.junit.Assert.assertThat( dr.getPageSource(),containsString("我的京东"));
//JD bean page
dr = jd.JDBeanPage();
org.junit.Assert.assertThat(dr.getPageSource(), containsString("可用京豆"));
//JD bean details
jd.getJDBeanDetails();
List dates= jd.retrieveJDBeanDatesDetails();
List transacDetails = jd.retrieveJDBeanTransacDetail();
List transacName = jd.retrieveJDBeanTransacName();
//System.out.println("Dates Size: "+dates.size() + "TransacName Size: "+ transacName.size() + "Transac Details Size: "+ transacDetails.size() );
org.junit.Assert.assertEquals("抓取京豆明细异常:数据条数不匹配", dates.size(),transacDetails.size());
org.junit.Assert.assertEquals("抓取京豆明细异常:数据条数不匹配", dates.size(),transacName.size());
for(int i = 0; i < transacName.size(); i ++){
for (int j = 0; j < transacName.get(i).length(); j ++){
org.junit.Assert.assertFalse("敏感信息未隐藏: 第 " + i+1 + "条数据", Character.isDigit(transacName.get(i).charAt(j)));
}
}
}
@After
public void testTearDown() throws Exception {
jd.tearDown();
}
}