第一章 Http协议原理
1.1 协议
网络协议:通信计算机双方必须遵守的一组约定
http https
端口 80 443
数据传输 明文传输 加密传输
真假网站识别 很容易被复制 使用证书,很难被复制
浏览器显示区别 浏览器显示问号, 浏览器显示小锁,提示安全
提示不安全。
门槛 不需要证书 需要gworg机构发布证书,需要一定的成本
安全性 很容易被劫持, 加密安全,很难劫持,交易数据加密
跳转到其他网站
1.2 url
https://www.douban.com/gallery/topic/116390/?from=hot_topic_note&sort=new
//地址栏输入的地址 url 统一资源定位符Uniform Resource Locator
https:// 协议类型
www.douban.com 域名
/gallery/topic/ 路径
?from=hot_topic_note&sort=new 参数 路径与参数之间用?分割 参数与参数之间用&
路径的两种情况
相对路径:相对于某个基准目录的路径 ./代表当前目录 …/代表上一级目录
绝对路径:文件或者目录在硬盘上的真正路径 例如 C:\xyz\test.txt
第二章 简单的Api调用
###2.1 Get请求-无参数
安装依赖库:Okhttp3 这是一个非常流行的http库,可以简单的快速的实现http调用
在pom.xml文件中添加依赖
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency> //每一个dependency标签代表一个依赖库
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.1.0</version>
</dependency>
使用Okhttp3完成页面请求的三个步骤 固定写法
1 实例化OkHttpClient OkHttpClient okHttpClient = new OkHttpClient();
2 执行调用
一.实例化Request 对象,作用是定义请求的各种参数,
Request request = new Request.Builder().url(url).build();
二.构建调用对象 Call call = okHttpClient.newCall(request);
三执行调用 如果出现异常则抛出异常 执行调用的代码call.execute(
3 call.execute() 返回的其实是一个执行的结果对象,调用对象的方法即可获取返回的字符串内容:call.execute().body().string()
例子:获取(https://www.ustc.edu.cn/)的内容
import java.io.IOException;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class GetPage {
/**
* 根据输入的url,读取页面内容并返回
*/
public String getContent(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder().url(url).build();
// 使用client去请求
Call call = okHttpClient.newCall(request);
// 返回结果字符串
String result = null;
try {
// 获得返回结果
result = call.execute().body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
GetPage getPage = new GetPage();
String url = "https://www.ustc.edu.cn/";
String content = getPage.getContent(url);
System.out.println("call " + url + " , content=" + content);
}
}
call.execute().body().string(); // 这一行代码可以服务器返回的具体内容,需要注意一下
API:应用程序接口,通过api可以快速调用某个程序
api本质上还是一个url,只不过返回的数据没有大量多余的字符
2.2 Get请求- 有参数
其实有参数和无参数的区别不大,我们只需要在传入url的地方将有参数的url完整的传入就可以了
例子 获取url为(http://ip-api.com/json/?lang=zh-CN)的内容
import java.io.IOException;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class ApiAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public String getContent(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder().url(url).build();
// 使用client去请求
Call call = okHttpClient.newCall(request);
// 返回结果字符串
String result = null;
try {
// 获得返回结果
result = call.execute().body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "http://ip-api.com/json/?lang=zh-CN"; //将url传入
ApiAsker asker = new ApiAsker(); //实例化当前类
String content = asker.getContent(url);
System.out.println("API调用结果");
System.out.println(content);
}
}
2.3 post表单数据
post操作:提交数据到服务端进行添加,修改,删除等操作
post()方法:
我们前面学习了Okhttp3的get操作,现在我们来看看Okhttp3的post操作,post操作时,数据是放在表单中提交的。
固定写法:
Builder builder = new FormBody.Builder();
// 设置数据,第一个参数是数据名,第二个参数是数据值
builder.add("", "");
FormBody formBody = builder.build();
Request request = new Request.Builder().url(url).post(formBody).build();
例子:向指定的url(https://gitee.com/login)提交数据
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.FormBody;
import okhttp3.FormBody.Builder;
public class FormPoster {
/**
* 向指定的 url 提交数据
*/
public String postContent(String url, Map<String, String> formData) { //把发送数据的过程封装为一个postContent方法
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
//post方式提交的数据
Builder builder = new FormBody.Builder();
// 放入表单数据
for (String key : formData.keySet()) {
builder.add(key, formData.get(key));
}
// 构建 FormBody 对象
FormBody formBody = builder.build();
// 指定 post 方式提交FormBody
Request request = new Request.Builder().url(url).post(formBody).build();
// 使用client去请求
Call call = okHttpClient.newCall(request);
// 返回结果字符串
String result = null;
try {
// 获得返回结果
result = call.execute().body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "https://gitee.com/login";
Map<String, String> formData = new HashMap();
formData.put("user[login]", "17177466748");
FormPoster poster = new FormPoster();
String content = poster.postContent(url, formData);
System.out.println("API调用结果");
System.out.println(content);
}
}
2.4 post json数据
在日常开发中,我们不止会提交表单数据,也会提交json数据。它们都使用post()方法,但是表单的参数为FormBody
对象,而json的参数为RequestBody对象
使用json提交数据的步骤:
1将数据转化为JSON格式 调用JSON.toJSONString()方法即可
2创建RequestBody 实例,注意需要指定提交的类型是 application/json; charset=utf-8
utf-8 是 API 规定的编码格式。此例子中,API 规定数据传输的编码格式是 utf-8
3构建Request 实例对象时,调用 .post(requestBody) 即表示使用 JSON的方式提交数据
例子 提交json数据 注册一个新用户 张飞 翼德
import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody; //注意这些引入
public class JsonPoster {
// 定义提交数据的类型
public static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");
/**
* 向指定的 url 提交数据,以 json 的方式
*/
public String postContent(String url, Map<String, String> datas) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 数据对象转换成 json 格式字符串
String param = JSON.toJSONString(datas);
//post方式提交的数据
RequestBody requestBody = RequestBody.create(JSON_TYPE, param);
Request request = new Request.Builder().url(url).post(requestBody).build();
// 使用client去请求
Call call = okHttpClient.newCall(request);
// 返回结果字符串
String result = null;
try {
// 获得返回结果
result = call.execute().body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "https://www.fastmock.site/mock/3d95acf3f26358ef032d8a23bfdead99/api/posts";
Map<String, String> datas = new HashMap();
datas.put("name", "张飞");
datas.put("secondName", "翼德");
JsonPoster poster = new JsonPoster();
String content = poster.postContent(url, datas);
System.out.println("API调用结果");
System.out.println(content);
}
}
第三章 request response对象
3.1 response网页
使用一条语句执行调用请求并返回结果字符串
call.execute().body().string()
http状态码:用一个数字反应本次请求的状况 200表示成功 404表示出错了,服务端没有要请求的内容
可以使用这条语句获取状态码
call.execute().code()
通常我们既需要读取相应内容,又需要读取状态码,但不能请求两次,我们可以优化使用以下代码
import okhttp3.Response;
// 执行请求
Response rep = call.execute();
// 获取响应状态码
int code = rep.code();
// 获取响应内容
String content = rep.body().string();
例子 :
import java.io.IOException;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class GetPage {
/**
* 根据输入的url,读取页面内容并返回
*/
public String getContent(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder().url(url).build();
// 使用client去请求
Call call = okHttpClient.newCall(request);
// 返回结果字符串
String result = null;
try {
// 执行请求
Response rep = call.execute();
// 获取响应状态码
int code = rep.code();
System.out.println("状态码:" + code);
// 获取响应内容
result = rep.body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "https://www.ustc.edu.cn/";
GetPage getPage = new GetPage();
String content = getPage.getContent(url);
System.out.println("请求结果字符串长度:" + content.length());
}
}
3.2 response-非文本文件
Okhttp3不仅可以请求网页 api 也能请求图片 execl等各种文件
我们知道图片的内容不是可以直接阅读的字符文本,而是二进制编码,所以我们需要软件解析图片的二进制编码数据,才能还原成图像显示
我们可以使用以下语句,它可以返回获取的二进制编码内容
response.body().bytes();
例子:获取url为(https://style.youkeda.com/img/ham/course/py2/douban.png)的二进制编码内容
import java.io.IOException;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ImageAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public void getImage(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder().url(url).build();
try {
// 执行请求
Response response = okHttpClient.newCall(request).execute();
byte[] bytes = response.body().bytes();
System.out.println("图片大小为:" + bytes.length + " 字节");
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
}
public static void main(String[] args) {
String url = "https://style.youkeda.com/img/ham/course/py2/douban.png";
ImageAsker asker = new ImageAsker();
asker.getImage(url);
}
}
3.3 response-json
json是一段难以解析的文本,我们必须把它们转换为java对象
我们之前学习了使用fastjson库把数据转化为json格式
JSON.toJSONString()
现在我们学习使用fastjson库把json格式转化为java对象
JSON.parseObject()
例子:
import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ApiAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public String getContent(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder().url(url).build();
// 使用client去请求
Call call = okHttpClient.newCall(request);
// 返回结果字符串
String result = null;
try {
// 执行请求
Response response = call.execute();
// 获取响应内容
result = response.body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "http://ip-api.com/json/";
ApiAsker asker = new ApiAsker();
String content = asker.getContent(url);
System.out.println("查询结果文本:" + content);
Map contentObj = JSON.parseObject(content, Map.class);
System.out.println("JSON 格式字符串转换为 Map 对象");
}
}
3.4解析json对象
当我们遇到多层嵌套结构的json时,我们可以多次取出嵌套的map对象
map可以储存任何对象,所以从Map 中 get() 到的对象必须指定其实际的类型:(Map)、(String)
Map contentObj = JSON.parseObject(content, Map.class);
Map dataObj = (Map)contentObj.get("data");
String city = (String)dataObj.get("city");
第四章 headers
###4.1 user-agent
有些大型网站出于对安全的考虑,对于不是不是浏览器发出的请求会直接拒绝,例如java程序请求。
网站是如何判断请求是否来自一个真实的浏览器?
从消息头(headers)取得信息(user-agent)后判断
http header
HTTP 消息头 Headers 是 HTTP 协议的一项重要内容,作用是在发起请求的时候,除了请求参数外,可以附加更多的信息。
headers信息并不是写在url中,它属于隐藏的信息,不能直接被看到。
user-agent
User-Agent 是存放在 Headers 中的一种数据信息。作用是,在指定 URL 发送请求的时候,告诉服务端当前用户的浏览器类型
、版本,甚至操作系统、CPU等非隐私的技术信息。
如果服务器从headers中的user-agent获取到浏览器的版本类型信息之后,就会认为发出请求的是一个真实的浏览器
我们来模拟一个win7 + chrome 的环境
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1
使用模拟环境的办法发出请求
Okhttp3已经可以支持headers了,我们可以在构建request对象的时候,调用addHeader()方法
Request request = new Request.Builder()
.url(url)
.addHeader("User-Agent", "")
.build();
例子
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ApiAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public String getContent(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder()
.url(url)
// 添加一个 header 信息
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1")
.build();
// 返回结果字符串
String result = null;
try {
// 执行请求
Response response = okHttpClient.newCall(request).execute();
// 获取响应内容
result = response.body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "https://www.fastmock.site/mock/3d95acf3f26358ef032d8a23bfdead99/api/service/getIpInfo.php?ip=117.89.35.58&format=json";
ApiAsker asker = new ApiAsker();
String content = asker.getContent(url);
System.out.println("查询结果文本:" + content);
}
}
4.2 referer
图片防盗链:这是一个更严格的审查,让其他的网站无法访问该图片
referer:表示请求的来源
可以直接访问图片的办法:将referer信息设置为原始使用图片的网站
例子:
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ImageAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public void getContent(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder()
.url(url)
.addHeader("Referer", "https://unreach.yuque.com") //修改referer信息
.build();
try {
// 执行请求
Response response = okHttpClient.newCall(request).execute();
int code = response.code();
System.out.println("状态码:" + code);
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
}
public static void main(String[] args) {
String url = "https://cdn.nlark.com/yuque/0/2019/png/93870/1571386626984-2462f7f9-d397-4e50-91e4-e4b688dd3410.png";
ImageAsker asker = new ImageAsker();
asker.getContent(url);
}
}
4.3 host
Host 表示当前请求的域名。虽然这个域名已经存在于 URL 中,但遇到复杂的场景,
例如使用代理服务器、或者 URL 中不写域名而是写 IP 地址进行请求等,设置 Host 就非常有用了。
host user-agent 和referer 都是headers数据的字段
host的值一定是一个不带协议头的域名
Request request = new Request.Builder()
.url(url)
.addHeader("Host", "www.douban.com")
.build();
现在我们把headers的三个字段汇总一下,平时写程序时,三个字段都需要写全
Request request = new Request.Builder()
.url(url)
.addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36")
.addHeader("Referer", "https://www.douban.com/")
.addHeader("Host", "www.douban.com")
.build();
第五章 下载文件和图片
5.1下载文件
如文件 图片 excel这类二进制文件是无法在控制台(console)中查看的,我们需要把请求结果写入文件中
在java中写入文件必须经历三个步骤
1 创建文件对象
2 写入内容
3 关闭写入操作 //打开和关闭的步骤,是为了确保一个文件只能同时被一个程序写入,防止内容错乱
写入文本文件
import java.io.File; //文件类
import java.io.FileWriter; //给文件写入内容的类
// 文件对象
File file = new File("foo.txt");
// 写入内容
FileWriter fileWritter = new FileWriter(file.getName());
fileWritter.write(content);
// 关闭
fileWritter.close(); //一定要关闭
完整的例子
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) {
try {
String content = "Hello World";
File file = new File("foo.txt");
FileWriter fileWritter = new FileWriter(file.getName());
fileWritter.write(content);
fileWritter.close();
System.out.println("finish");
} catch (IOException e) {
e.printStackTrace();
}
}
}
写入二进制文件
假设写入文件的变量是byte[] data,那么写入本地的代码
import java.io.File;
import java.io.FileOutputStream;
// 文件对象
File file = new File("china-city-list.xlsx");
// 写文件
FileOutputStream fos = new FileOutputStream(file);
fos.write(data);
// 必须刷新并关闭
fos.flush(); //刷新
fos.close(); // 关闭
5.2下载图片
图片都是二进制文件,所以和上一节的写入二进制文件是一样的
例子:下载e270-iknhexh8551480.jpg图片
import java.io.IOException;
import java.io.File;
import java.io.FileOutputStream;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ImageAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public byte[] getImage(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder().url(url).build();
byte[] bytes = null;
try {
// 执行请求
Response response = okHttpClient.newCall(request).execute();
bytes = response.body().bytes();
System.out.println("图片大小为: " + bytes.length + " 字节");
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return bytes;
}
public static void main(String[] args) {
String url = "https://n.sinaimg.cn/news/1_img/dfic/72f96829/125/w1024h701/20191209/e270-iknhexh8551480.jpg";
ImageAsker asker = new ImageAsker();
byte[] data = asker.getImage(url);
try {
File file = new File("e270-iknhexh8551480.jpg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(data);
fos.flush();
fos.close();
System.out.println("下载成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
###5.3 解析execl
依赖库
easyexcel是阿里巴巴推出的快速简单操作execl的库,使用前需添加好依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.6</version>
</dependency>
调用库 : excel文件有许多sheet,每个sheet实际上就是一个表格,每个表格有很多行和列
所以解析数据的路径一定是:sheet->行->列 (0,0,0)表示第一个sheet,第一行第一列
例子:解析xzq_201907.xlsx文件
import com.alibaba.excel.EasyExcel;
import java.util.Map;
import java.util.List;
// 读取第一个sheet
List<Map<Integer, String>> sheetDatas = EasyExcel.read("xzq_201907.xlsx").sheet(0).doReadSync();
// EasyExcel.read()方法读取文件内容 sheet()方法传入参数 doReadSync()表示同步方式读取文件内容,返回到一个读取到的
内容集合list中
// List 中每个元素表示一行
for (Map<Integer, String> rowData : sheetDatas) {
// Map 中用序号指代每一列
for (Integer index : rowData.keySet()) {
// 列值
String columnValue = rowData.get(index);
}
}
完整示列 解析xzq_201907.xlsx文件
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ExcelAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public byte[] getFile(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder().url(url).build();
byte[] bytes = null;
try {
// 执行请求
Response response = okHttpClient.newCall(request).execute();
bytes = response.body().bytes();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return bytes;
}
public static void main(String[] args) {
String url = "https://style.youkeda.com/img/ham/course/py2/xzq_201907.xlsx";
ExcelAsker asker = new ExcelAsker();
byte[] data = asker.getFile(url);
try {
File file = new File("xzq_201907.xlsx");
FileOutputStream fos = new FileOutputStream(file);
fos.write(data);
fos.flush();
fos.close();
System.out.println("下载成功");
} catch (IOException e) {
e.printStackTrace();
}
List<Map<Integer, String>> sheetDatas = EasyExcel.read("xzq_201907.xlsx").sheet(0).doReadSync();
for (Map<Integer, String> rowData : sheetDatas) {
for (Integer index : rowData.keySet()) {
System.out.print("列号:" + index + ",列值:" + rowData.get(index) + "。");
}
System.out.println("");
}
}
}
注意点:System.out.print()输出后不自动换行
自动转换为类
当excel文件的列的意义不明或者列经常变化时,我们使用map表示每一列的数据,但如果我们知道每一列的意义,我们就可以使用自定义类
import com.alibaba.excel.EasyExcel;
import java.util.List;
// 读取第一个sheet
List<DemoData> sheetDatas = EasyExcel.read("xzq_201907.xlsx").head(DemoData.class).sheet(0).doReadSync();
//.head(DemoData.class) DemoData就是自定义的类 List<DemoData>表示把每一行都转换为DemoData实例对象,放入集合list中
第六章cookie和session
###6.1 cookie
如果有些内容需要登录之后才能获取,那么我们就需要学习headers 中的cookie的内容了
找到cookie
1登录前按f12打开开发者工具,选择network headers
2登录 在开发者工具中找到mine文件 或其他与浏览器地址相同的url请求
3 找到cookie copy下来 放入文件cookie.txt中
例子:将cookie信息字符串转化为map类型
首先需要一个工具类
import java.io.FileReader;
import java.io.IOException;
/**
* 读文件工具类
*/
public class ReadFileTool {
/**
* 读取指定文件的内容
*/
public static String readContent(String fileName) {
FileReader fr = null;
StringBuilder strBuilder = new StringBuilder();
try {
fr = new FileReader(fileName);
int ch = 0;
while ((ch = fr.read()) != -1) {
strBuilder.append((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return strBuilder.toString();
}
}
然后解析cookie字符串
import java.io.IOException;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class PageAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public String getContent(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder()
.url(url)
.addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36")
.addHeader("Referer", "https://www.douban.com")
.addHeader("Host", "www.douban.com")
.addHeader("Cookie", ReadFileTool.readContent("cookie.txt"))
.build();
// 返回结果字符串
String result = null;
try {
// 执行请求
Response response = okHttpClient.newCall(request).execute();
result = response.body().string();
} catch (IOException e) {
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "https://www.douban.com/mine";
PageAsker asker = new PageAsker();
String content = asker.getContent(url);
System.out.println(content);
}
}
6.2 session
cookie的弊端:cookie字符串是放在客户端浏览器的,且是临时的。登录以后还想以登录状态与服务器通信会比较麻烦
session对象可以很好的解决这个问题
收集信息
1 登陆前打开开发者工具 勾选preserve log选项 选择network headers
2 登录 选择登录时最开始出现的文件
3 收集到以下信息 :登录方式Request URL:
执行方式(get 或post)
host
referer
user agent
表单数据 数据名称和数据值 form data
代码示例
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.FormBody.Builder;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class PageLoginer {
// 用 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();
public String postContent(String url, Map<String, String> formData) {
//post方式提交的数据
Builder builder = new FormBody.Builder();
// 放入表单数据
for (String key : formData.keySet()) {
builder.add(key, formData.get(key));
}
// 构建 FormBody 对象
FormBody formBody = builder.build();
// 指定 post 方式提交FormBody
Request request = new Request.Builder()
.url(url)
.post(formBody)
.addHeader("User-Agent",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36")
.addHeader("Referer",
"https://passport.mtime.com/member/signin/?redirectUrl=http%3A%2F%2Fwww.mtime.com%2F")
.addHeader("Host", "passport.mtime.com")
.build();
// 返回结果字符串
String result = null;
try {
result = okHttpClient.newCall(request).execute().body().string();
} catch (IOException e) {
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
// 登录页面 url
String url = "https://passport.mtime.com/member/signinLogin";
// 登录表单数据
Map<String, String> formData = new HashMap();
formData.put("loginEmailText", "13777467803");
formData.put("loginPasswordText", "aa787bc9cc97ba5d27cc042ecffe1489");
formData.put("isvcode", "true");
formData.put("isAutoSign", "false");
PageLoginer asker = new PageLoginer();
String content = asker.postContent(url, formData);
System.out.println(content);
}
}
6.3复用session
我们在6.2完成了模拟登录,模拟登录的目的是为了调用必须登录的api,或请求必须登录的网站
同时,我们将原来的 OkHttpClient对象进行了重构,重构为类变量private static final OkHttpClient okHttpClient,目的是
使用同一个OkHttpClient执行http请求
知识点:static 表示类变量,意味着无论 new 出多少个 PageLoginer 对象,PageLoginer.okHttpClient 都只有一个。
final 表示 okHttpClient 一旦第一次 new 出对象后,不能再次 new 新对象
第七章 实战SMTP与邮件
7.1 SMTP
编写一个定时定期发送邮件的程序
SMTP(simple mail transfer protocol)协议
它是一个简单的基于文本的邮件传输协议,通过这个协议我们可以指定一条邮件消息和一个或者多个邮件接收者,然后进行邮件传输
类似于https协议 https+网络地址 组成一个访问方式 (https//www.baidu.com)
smtp+网络地址也可以组成一个邮件访问方式
邮件服务商都有自己的邮件服务器地址 例如 smtp.qq.com
smtp.163.com
7.2 java mail 邮件发送
这节课我们学习如何用代码使邮箱发送邮件 以QQ邮箱为例,我们开启smtp支持
1打开qq邮箱,点设置 点账户
2往下翻 找到与smtp有关的服务,打开
3经过验证之后获得授权码
代码示例
1 先添加相关的依赖
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
2 编写代码 固定格式 只需要更改一些传入的信息即可
import java.security.Security;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import com.sun.net.ssl.internal.ssl.Provider;
public class Mail {
public static void main(String[] args) {
try {
// 设置SSL连接、邮件环境
Security.addProvider(new Provider());
final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties props = System.getProperties();
props.setProperty("mail.smtp.host", "smtp.qq.com");
props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.port", "");
props.setProperty("mail.smtp.socketFactory.port", "");
props.setProperty("mail.smtp.auth", "true");
// 建立邮件会话
Session session = Session.getDefaultInstance(props, new Authenticator() {
// 身份认证
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("", ""); // 账户 授权码
}
});
// 建立邮件对象
MimeMessage message = new MimeMessage(session);
// 设置邮件的发件人、收件人、主题
// 附带发件人名字
message.setFrom(new InternetAddress(""));
message.setRecipients(Message.RecipientType.TO, "");
// 文本部分
message.setContent("", "text/html;charset=UTF-8");
message.saveChanges();
// 发送邮件
Transport.send(message);
// 打印成功信息
System.out.println("发送成功");
} catch (Exception e) {
e.printStackTrace();
}
}
}