前言

网上有很多模拟登陆 LeetCode 的教程,但是基本都是使用 Python 来实现的。作为一个 Java 语言爱好者,因此想用 Java 来实现下。在实现的过程中,也遇到了一些坑点,故在此作为记录。

过程

根据浏览器F12分析登陆页面



从上图可以看出,LeetCode 生成一个 token ,然后在登陆的时候带上这个信息,因此我们模拟登陆的大致思路:首先获取得到 cookie(包含有token),然后在登陆的时候带上这个 cookie 信息,完成 LeetCode 的验证机制,进行模拟登陆。

但是直接进行模拟带上 login(用户名)、password(密码)、csrfmiddlewaretoken(验证信息)是失败的,提示 Forbidden。思考无果,另开思路。

用 fiddler 进行抓包,未登陆状态,数据如下图(也可用浏览器F12来进行分析):



登陆状态,数据如下图,从图中,我们可以发现,其 Content-Type 字段与我们之前常见的值不一样,其是 multipart/form-data 格式,因此我们在模拟登陆,要将其考虑进来。



创建一个 multipart/form-data 的媒体格式,然后生成我们要的请求体,至于我们要的是哪种请求体,其格式可以从 fiddler 抓包的结果获悉。

在SyntaxView中具体的详情如下:



值得注意的是 Content-Type 中的boundary只有四个“-”,而在请求体中有六个“-”,之前因为忽略了这个,一直被拒绝访问(挺坑爹的

  1. public static final String boundary = "----WebKitFormBoundaryhG2vKxp7y2GAwhPX";
  2. public static final MediaType MULTIPART = MediaType.parse("multipart/form-data; boundary=" + boundary);
  3. String form_data = "--" + boundary + "\r\n"
  4. + "Content-Disposition: form-data; name=\"csrfmiddlewaretoken\"" + "\r\n\r\n"
  5. + csrftoken + "\r\n"
  6. + "--" + boundary + "\r\n"
  7. + "Content-Disposition: form-data; name=\"login\"" + "\r\n\r\n"
  8. + usrname + "\r\n"
  9. + "--" + boundary + "\r\n"
  10. + "Content-Disposition: form-data; name=\"password\"" + "\r\n\r\n"
  11. + passwd + "\r\n"
  12. + "--" + boundary + "\r\n"
  13. + "Content-Disposition: form-data; name=\"next\"" + "\r\n\r\n"
  14. + "/problems" + "\r\n"
  15. + "--" + boundary + "--";
  16. RequestBody requestBody = RequestBody.create(MULTIPART,form_data);

结果

将其返回的报文打印出来,得到如下信息则表示模拟登陆成功



从 fiddler 的抓包结果中也可以证实这点

代码

  1. package LeetCodeLogin;
  2. import okhttp3.*;
  3. import org.jsoup.Connection;
  4. import org.jsoup.Jsoup;
  5. import java.io.IOException;
  6. import java.util.*;
  7. import static java.lang.System.out;
  8. public class Login {
  9. public static final String boundary = "----WebKitFormBoundaryhG2vKxp7y2GAwhPX";
  10. public static final MediaType MULTIPART = MediaType.parse("multipart/form-data; boundary=" + boundary);
  11. public static void main(String... args) throws IOException {
  12. Scanner scanner = new Scanner(System.in);
  13. String url = "https://leetcode.com/accounts/login/";
  14. String usrname = "xxx";
  15. String passwd = "xxx";
  16. Connection.Response response1 = Jsoup.connect(url)
  17. .method(Connection.Method.GET)
  18. .execute();
  19. String csrftoken = response1.cookie("csrftoken");
  20. String __cfduid = response1.cookie("__cfduid");
  21. out.println("csrftoken = " + csrftoken);
  22. out.println("__cfduid = " + __cfduid );
  23. OkHttpClient client = new OkHttpClient().newBuilder()
  24. .followRedirects(false)
  25. .followSslRedirects(false)
  26. .build();
  27. String form_data = "--" + boundary + "\r\n"
  28. + "Content-Disposition: form-data; name=\"csrfmiddlewaretoken\"" + "\r\n\r\n"
  29. + csrftoken + "\r\n"
  30. + "--" + boundary + "\r\n"
  31. + "Content-Disposition: form-data; name=\"login\"" + "\r\n\r\n"
  32. + usrname + "\r\n"
  33. + "--" + boundary + "\r\n"
  34. + "Content-Disposition: form-data; name=\"password\"" + "\r\n\r\n"
  35. + passwd + "\r\n"
  36. + "--" + boundary + "\r\n"
  37. + "Content-Disposition: form-data; name=\"next\"" + "\r\n\r\n"
  38. + "/problems" + "\r\n"
  39. + "--" + boundary + "--";
  40. RequestBody requestBody = RequestBody.create(MULTIPART,form_data);
  41. Request request = new Request.Builder()
  42. .addHeader("Content-Type", "multipart/form-data; boundary=" + boundary)
  43. .addHeader("Connection","keep-alive")
  44. .addHeader("Accept","*/*")
  45. .addHeader("Origin","https://leetcode.com")
  46. .addHeader("Referer",url)
  47. .addHeader("Cookie","__cfduid=" + __cfduid + ";" + "csrftoken=" + csrftoken)
  48. .post(requestBody)
  49. .url(url)
  50. .build();
  51. Response response = client.newCall(request).execute();
  52. out.println(response.message());
  53. out.println(response.headers());
  54. out.println(response.body().string());
  55. }
  56. }

需要注意的是,在上述代码中,我们通过下述代码禁止了重定向,来自己处理重定向请求,可参考使用OkHttp进行重定向拦截处理,若是没有进行重定向拦截,也会使得模拟登陆失败。

  1. .followRedirects(false)
  2. .followSslRedirects(false)

写在最后

本次模拟登陆,虽然代码很简单,但是确实也经历了一些波折,比对过 Python 和 Js 写的模拟登陆的代码,用 Java 来进行模拟似乎多了一些琐碎的细节,对于具体的为何 Python 和 Js 能如此简介的处理的原理还在琢磨中。此次,也得到了朋友 faberry 的帮助,在一些地方给了意见。

使用OkHttp模拟登陆LeetCode的更多相关文章

  1. 使用OKHttp模拟登陆知乎,兼谈OKHttp中Cookie的使用!

    本文主要是想和大家探讨技术,让大家学会Cookie的使用,切勿做违法之事! 很多Android初学者在刚开始学习的时候,或多或少都想自己搞个应用出来,把自己学的十八般武艺全都用在这个APP上,其实这个 ...

  2. Python 爬虫模拟登陆知乎

    在之前写过一篇使用python爬虫爬取电影天堂资源的博客,重点是如何解析页面和提高爬虫的效率.由于电影天堂上的资源获取权限是所有人都一样的,所以不需要进行登录验证操作,写完那篇文章后又花了些时间研究了 ...

  3. Python模拟登陆新浪微博

    上篇介绍了新浪微博的登陆过程,这节使用Python编写一个模拟登陆的程序.讲解与程序如下: 1.主函数(WeiboMain.py): import urllib2 import cookielib i ...

  4. PHP 之 CURL 模拟登陆并获取数据

    1.CURL模拟登陆的流程和步骤 2.tempnam 创建一个临时文件 3.使用CURL模拟登陆到PHP100论坛 <?php $cookie_file = tempnam('./temp',' ...

  5. NetworkComms V3 模拟登陆

    演示NetworkComms V3的用法 例子很简单 界面如下: 服务器端代码: 开始监听: //服务器开始监听客户端的请求 Connection.StartListening(ConnectionT ...

  6. pytho简单爬虫_模拟登陆西电流量查询_实现一键查询自己的校园网流量

    闲来无事,由于校园内网络是限流量的,查询流量很是频繁,于是萌生了写一个本地脚本进行一键查询自己的剩余流量. 整个部分可以分为三个过程进行: 对登陆时http协议进行分析 利用python进行相关的模拟 ...

  7. python模拟登陆知乎并爬取数据

    一些废话 看了一眼上一篇日志的时间 已然是5个月前的事情了 不禁感叹光阴荏苒其实就是我懒 几周前心血来潮想到用爬虫爬些东西 于是先后先重写了以前写过的求绩点代码 爬了草榴贴图,妹子图网,后来想爬婚恋网 ...

  8. php模拟登陆的两种实现方法分析

    php模拟登陆的实现方法分析 本文实例分析了php模拟登陆的实现方法.分享给大家供大家参考.具体分析如下: php模拟登陆的实现方法,这里分别列举两种方法实现模拟登陆人人网.具体实例代码如下: 1)使 ...

  9. python 模拟登陆,请求包含cookie信息

    需求: 1.通过GET方法,访问URL地址一,传入cookie参数 2.根据地址一返回的uuid,通过POST方法,传入cooki参数 实现思路: 1.理解http的GET和POST差别 (网上有很多 ...

随机推荐

  1. 内置的re模块

    re(正则表达式) 字符匹配: 普通字符匹配:re.findall("alex","shfalexjaf"),直接查找符合的字符 元字符:  .  ^ $ * ...

  2. SubwayPlan

    GitHub:https://github.com/wakerh1/subwayBJ 北京地铁图片: 地铁出行路线规划项目需求及实现概要: 1.设计一种文件格式用于存储地铁信息 2.设计启动程序并读取 ...

  3. Flask【第6篇】:Flask中的信号

    补充的flask实例化参数以及信号 一.实例化补充 instance_path和instance_relative_config是配合来用的.这两个参数是用来找配置文件的,当用app.config.f ...

  4. 可决系数R^2和方差膨胀因子VIF

    然而很多时候,被筛选的特征在模型上线的预测效果并不理想,究其原因可能是由于特征筛选的偏差. 但还有一个显著的因素,就是选取特征之间之间可能存在高度的多重共线性,导致模型对测试集预测能力不佳. 为了在筛 ...

  5. man du

    DU(1)                      User Commands/用户命令                     DU(1) NAME/名字         du - estimat ...

  6. Keras MAE和MSE source code

    def mean_squared_error(y_true, y_pred): if not K.is_tensor(y_pred): y_pred = K.constant(y_pred) y_tr ...

  7. Docker(二):Docker入门教程

    前言 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 ...

  8. 前端node面试题之---对比JS和NodeJS的区别

    区别: 1.JS运行在浏览器端,用于用户的交互效果,NodeJS运行在服务器端,用于服务器的操作,例如,Web服务器创建,数据库的操作,文件的操作等 2.JS运行在浏览器端,存在多个JS解释器,存在兼 ...

  9. mysql OR运算符 语法

    mysql OR运算符 语法 作用:在 WHERE 子语句中把两个或多个条件结合起来. 语法:SELECT * FROM 表名 WHERE 字段1 运算符 值 OR 字段2 运算符 值 说明:如果第一 ...

  10. 洛谷p3956 棋盘(NOIP2017 t3)

    在noip考场上本来以为只能骗暴力分,没想到最后A了: 本蒟蒻的做法比较简(zhi)单(zhang):记忆化深搜(考场上本来是想打广搜的,但我深搜稳一点就这样打了): 具体:每个点用一个f数组记录当前 ...