cookie
前面我们学习 Okhttp3
库可以调用API
、抓取网页、下载文件。但是这些操作都是不要求登录的,如果 API
、网页、文件等内容要求登录才能访问,就需要学习新的 cookie 相关的知识了。
下面以豆瓣为例,使用 Java
程序读取“我的豆瓣”页面内容,在此过程中熟悉运用 cookie
。
所谓 cookie ,是存储在客户端浏览器中的一段文本内容。以 key=value
(数据名称、数据值)的格式存储一条数据;多条数据之间用分号 ; (英文半角)分开。由于各种浏览器都对 cookie 大小和数量有限制,所以 cookie 目前的核心功能是存储登录数据;额外可以存储一些小数据,比如 是否登录=true;昵称=张三
这样的内容不大的数据。
InternetExplorer 限制 cookie 为每个域名 50 个,上限 4095 个字节。Firefox 每个域名 cookie 限制为 50 个,上限 4097 个字节。每种浏览器略有异同,但肯定都有限制。
1.前期准备
在浏览器输入 https://www.douban.com/mine
打开“我的豆瓣”页面。这个页面是必须登录的。
登录完成以后,可以正确看到“我的豆瓣”页面了。
注意:登录信息是存放在
cookie
里的
所以,必须先找到登录后的 cookie
,这是完成 Java
程序的重要的前提条件。
2.找到 cookie
打开谷歌浏览器的开发者工具(使用谷歌浏览器),切换到 Network 菜单项,如下图所示第一步:
对谷歌开发者工具不熟悉的,可以点击查看 使用教程
如果没有 mine ,就选第一个跟浏览器地址栏相同的 URL 请求
按照图中所示的四个步骤,把 cookie
的值(Cookie:
后的内容哦,不包括 Cookie:
)拷贝下来,放入一个 cookie.txt
文件中。
cookie 的内容很长,而且看不懂。因为 cookie 中除了登录信息,还能放其它信息,大多是加密过的。但没关系,这些信息是给计算机看的。
我们需要编码把 cookie
信息字符串转换为 Map
类型的数据。
3.编码实现
实际上,程序我们前面练习过,就是使用 Okhttp3
库完成 get
请求而已。
会用到前面的知识,特别是第 4 章第 1、2 节的内容,不熟悉的同学复习一下。
上图中可以看到,浏览器在发送请求的时候,自动带上了 Host
、User-Agent
内容哦。
这样,所需的数据都已识别完毕,我们先看一下演示程序。系统提供了一个工具类,用于从 cookie.txt
文件读取内容。
代码演示
大家可以看到,Cookie
也是存放在 header
中的哦。
session
上节课使用了谷歌浏览器的开发者工具抓取到了登录的 cookie
,然后使用程序完成登录。
但 cookie
的弊端是,cookie
是存放在客户端浏览器的,而且是临时的,登录后还想以登录状态与服务器通讯,就比较麻烦。
这就需要在程序中使用 Session
对象来解决这个问题。下面我们通过模拟登录时光网来学会如何应用 Session
对象。
1.时光网登录
浏览器中输入http://www.mtime.com/
打开时光网,点击右上角的登录按钮;
如果没有看到输入框,可以点击角落电脑图标切换:
弹出登录对话框。
或者直接 点此打开注册与登录页面,并点击“会员登录”
如果没有注册的,先注册,再退出登录,并重复此步骤。
如果遇到电脑无法注册时光网的情况,麻烦下载时光网APP,进行注册。
2.收集信息
然后打开谷歌浏览器的开发者工具,如图所示,Preserve log 必须勾选。
对谷歌开发者工具不熟悉的,可以点击查看 使用教程
关键点
输入用户名和密码后,在右侧抓取到的网络请求中,找到登录请求 API :
https://front-gateway.mtime.com/user/user/login.api
新版浏览器可能有一点不同
在“标头”后面多了一个“载荷”(Payload)的小菜单。
切换到小菜单可以看到密码:
时光网改版了,所以谷歌浏览器的开发者工具里,输入框输入login进行过滤哦。
由于改版,视频中有些细节是旧的,例如登录页面是旧版的。但是没关系,操作过程是一样的。
需要收集的关键信息包括:
- 登录地址
- 执行方式(GET/POST)
- HOST
- Referer
- User-Agent
- 表单数据,数据名称和数据值
由于每个网站登录相关的信息都不一样,所以必须在手动登录的过程中收集信息。大家学会这个方法,就可以模拟其它网站登录。
3.编码实现
提醒
// 用 CookieJar 实现 cookie 的存储,便于登录后请求其它 URL 可以复用
private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put("mtime.com", cookies);
System.out.println("[saveFromResponse]url.host()=" + url.host());
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
System.out.println("[loadForRequest]url.host()=" + url.host());
List<Cookie> cookies = cookieStore.get("mtime.com");
return cookies != null ? cookies : new ArrayList<>();
}
})
.build();
-
CookieJar
是接口(interface
),而 不是 类(class
)。演示代码中:new CookieJar() {......}
是匿名类。关于匿名类,匿名类的概念感兴趣可以阅读匿名类知识点
-
对表单提交不熟悉的同学,需要复习本课程的第二章第三节。
HashMap
cookieStore 的类型是 HashMap ,相当于一个登录信息的 集合 、 容器 ,可以用来不存 不同域名 的 登录信息(cookie) 。
程序具备扩展性
HashMap 是用法,在前面的《Java 基础强化》课程已经讲过,大家可以复习一下。
cookieStore.put("mtime.com", cookies);
就是把当前爬取到的时光网的登录信息存储起来。cookieStore.get("mtime.com");
就是把当前爬取到的时光网的登录信息从容器中拿出来。
当然这个容器是临时的,本质上是存入计算机内存,当前程序关闭掉,信息就消失了
复用session
上节课我们完成了模拟登录。模拟登录的目的,还是为了能够调用必须登录的API、或请求必须登录的网页等。
其实,为我们只需要在上节课登录成功的基础上,使用 session
对象再次发出请求即可完成这些必须登录的请求。
我们先来看案例演示:
请求“个人设置”页面(http://my.mtime.com/personal/personInfo
):
实现
不知道大家注意没有,在上一节中,我们把 OkHttpClient
对象进行重构,不再定义为 postContent()
方法的变量。
而是改为类变量:private static final OkHttpClient okHttpClient
,目的就是在整个类中,使用同一个 okHttpClient
执行 HTTP
请求,提升效率。重构在本节课就派上用场了。
分析执行两次请求的过程,实际上过程是类似的,区别是 Request
不同,所以,又做了一次重构,把真正执行的过程封装成一个方法:doExcute
,被其它 postContent()
和 getContent()
方法调用。
这么做就是抽象的过程,目的是减少重复代码,提高可阅读性和可维护性。重构会伴随我们整个编程的生涯。请大家认真体会这个过程,还可以动手试一下,如果不重构,代码会是什么样的?
小知识点
static
表示类变量,意味着无论new
出多少个PageLoginer
对象,PageLoginer.okHttpClient
都只有一个。final
表示okHttpClient
一旦第一次new
出对象后,不能再次new
新对象。