爬虫实战--模拟登陆

2019-12-23  本文已影响0人  郭彦超

并不是所有网站信息都可直接访问,有相当一部分的数据是需要用户授权登陆后才可以拿到的,比如某某网站开通vip会员才能进行下载操作

背景

获取尚德个人主页的课程列表

分析

http://aaaa/list.do?token=bbb

每次只需要在对应的url后面拼接对应的token就可以了,当token失效时根据认证接口再次获取就可以了,这种数据API因为走的是http协议,所以具备很强的跨平台优势,一般多用于无页面的数据服务之间的互相请求

认证登陆一般也分两种,一种是需要验证码认证的(之后讲),一种不需要验证码,后者相对比较简单,做法和上面比较类似,不同的是这种是把认证存储到cookie信息里而且需要通过selenium模拟登陆方式获取授权后的cookie信息

代码演示

public class RobotLogin {
    public static void main(String[] args) throws IOException, InterruptedException  {
        //geckodriver配置
        FirefoxBinary firefoxBinary = new FirefoxBinary();
        firefoxBinary.addCommandLineOptions("--headless");
        System.setProperty("webdriver.gecko.driver", "target/classes/drivers/geckodriver.exe");
        //声明使用的是火狐浏览器
        FirefoxOptions firefoxOptions = new FirefoxOptions();
        firefoxOptions.setBinary(firefoxBinary);
        FirefoxDriver driver = new FirefoxDriver(firefoxOptions);
        //使用火狐浏览器打开尚德个人主页
        String url = "http://yi.sunlands.com/ent-portal-war/new_pt_uc/my_lesson/lessonHome.action?auth=true&ticket=ST-417335-WD7Vp4cViOIaCiW6uHxd-cas";
        driver.get(url);
        //元素定位,提交用户名以及密码
        driver.findElementByName("username").clear();  //清空后输入
        driver.findElementByName("username").sendKeys("bbb");
        driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        driver.findElementById("password").clear(); //清空后输入
        driver.findElementById("password").sendKeys("***");
        //元素定位,点击登陆按钮
        driver.findElementById("msgBtn").click();
        Thread.sleep(5*1000);  //休息一段时间,使得网页充分加载。注意这里非常有必要
        Set<Cookie> cookies = driver.manage().getCookies();
        //获取登陆的cookies
        String cookieStr = "";
        for (Cookie cookie : cookies) {
            cookieStr += cookie.getName() + "=" + cookie.getValue() + "; ";
        }
        System.out.println(cookieStr);
        //基于Jsoup,使用cookies请求个人信息页面
        Document doc = Jsoup   //添加一些header信息
                .connect(url)
                .header("Host", "yi.sunlands.com")
                .header("Connection", "keep-alive")
                .header("Cache-Control", "max-age=0")
                .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3")
//                .header("Origin", "http://www.******.com")
                .header("Referer", "http://yi.sunlands.com/")
                .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0")
                .header("Content-Type", "application/x-www-form-urlencoded")
                .header("Accept-Encoding", "gzip, deflate, br")
                .header("Upgrade-Insecure-Requests", "1")
                .cookie("Cookie", cookieStr)
                .get();
        System.out.println(doc.html());
        //解析数据
        org.jsoup.select.Elements elements = doc.select("div[class=side-nav]")
                .select("ul[class=classify]");
        for (Element element : elements) {
             System.out.println(element.select("a").text());
        }
        driver.quit();  // 关闭浏览器
    }
}

改进

使用selenium实现的,为了减少依赖和保障后期的爬取效率我们也可以不用

这里需要主要的是尚德为了防止别人刷登录页面在这里加了一个登录验证,lt是虽登录页面固定返回的一个隐藏字段(在上面截图可以看到),每次刷新这个字段的值都会不一样,所以需要先爬取登录页面获取lt对应的述职字符串

public static void testSDLogin() throws IOException {
        Map<String, String> data = new HashMap<>();
        data.put("execution","e1s1");
        data.put("_eventId","submit");
        data.put("username","aaa");
        data.put("password","**");
        data.put("sign","");
        data.put("isgw","");

        Map<String,String> headerMap = new HashMap<String, String>();
        headerMap.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36");
        headerMap.put("Content-Type", "application/json; charset=utf-8");


        Document doc = Jsoup.connect("http://passport.sunlands.com/login")
                .headers(headerMap).ignoreContentType(true)
                .timeout(5000).get() ;

        String lt = doc.select("div[id=loginUserDiv]").select("input[name=lt]").attr("value");
        System.out.println(lt);
        data.put("lt",lt);

        Document doc2 = Jsoup.connect("http://yi.sunlands.com/ent-portal-war/new_pt_uc/my_lesson/lessonHome.action?auth=true&ticket=ST-611339-ftbcmMbB5x41xTJnrnDc-cas")
                .headers(headerMap).ignoreContentType(true)
                .data(data)
                .method(Connection.Method.POST)
                .timeout(5000).post() ;
        System.out.println(doc2.html() );
         
    }

小结

以上例子仅供学习参考,转发请注明出处

上一篇 下一篇

猜你喜欢

热点阅读