目录
网络是什么?
通讯协议
通信接口
网络分层
数据封装
IP地址(InetAddress)
IP地址分类
特殊的IP
InetAddress
Socket端口(InetSocketAddress)
端口分类
InetSocketAddress
URL统一资源定位器(URL)
URI、URL、URN
URL
使用Java实现简单爬虫
将不同区域的电脑连接到一起,组成局域网、 城域网或广域网。把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成-一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息,共享硬件、软件、数据信息等资源。
计算机网络中实现通信必须有一些约定。即通信协议。对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。
为了使两个结点之间能进行对话,必须在它们之间建立通信工具(即接口),使彼此之间能进行信息交换。接口包括两部分。
由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。
这里又分为理想的OSI七层模型,与实际使用TCP/IP模型。我们的WEB应用属于应用层,而JAVA网络编程则属于传输层
OSI七层模型 | TCP/IP模型 | 协议 |
应用层 | 应用层 | Telnet,FTP,HTTP,DNS,SMTP等 |
表示层 | ||
会话层 | ||
传输层 | 传输层 | TCP,UDP |
网络层 | 网络层 | IP,ARP,RARP,ICMP |
数据链路层 | 网络接口层 | 各种通信网络接口(以太网等) (物理网络) |
物理层 |
Data Encapsulation是指将协议数据单元(PDU)封装在一组协议头和协议尾中的过程。在OSI七层参考模型中,每层主要负责与其它机器上的对等层进行通信。该过程是在协议数据单元(PDU)中实现的,其中每层的PDU一般由本层的协议头、协议尾和数据封装构成。
发送数据处理的方式是从高层到底层,逐层进行数据封装
数据拆封是和数据封装相反的过程
IP地址是用来标识网络中一个通信实体的地址。(类比为快递中,你写的小区地址)。
Java使用InetAddress封装了IP地址
// 根据输入的域名获取IP
InetAddress inetAddress = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress.getHostAddress()); // 获取IP地址
System.out.println(inetAddress.getHostName()); // 获取主机名
// 获取本机的IP
InetAddress inetAddress2 = InetAddress.getLocalHost();
System.out.println(inetAddress2.getHostAddress());
System.out.println(inetAddress2.getHostName());
IP地址用来标识一台电脑,但电脑中又有很多软件,如何找到对应的软件呢,就要用到端口。(类比为小区中的门牌号)
同一协议端口不能冲突,不同协议最好不要冲突。
我们使用端口时最好越大越好,越不容易冲突。
Java使用InetSocketAddress封装了IP+端口号或主机名+端口号
// 通过主机名+端口号创建
InetSocketAddress socketAddress = new InetSocketAddress("www.baidu.com", 80);
System.out.println(socketAddress.getAddress()); // 获取主机名和IP的对应关系
System.out.println(socketAddress.getPort()); // 获取端口
类比为具体的收件人姓名
Java使用URL类封装了URL
// 不会验证url是否存在
URL url = new URL("https://www.baidu.com:80/index.html?a=1&b=2#hello");
System.out.println("协议:" + url.getProtocol());
System.out.println("域名|ip:" + url.getHost());
System.out.println("端口:" + url.getPort());
System.out.println("资源(file):" + url.getFile());
System.out.println("资源(path):" + url.getPath());
System.out.println("参数:" + url.getQuery());
System.out.println("锚点:" + url.getRef());
// 获取URL
URL url = new URL("https://www.jd.com");
// 下载资源
InputStream is = url.openStream(); // 打开字节输入流,将网络资源输入
// 将字节流转换为字符流
BufferedReader br = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
// 上面也可以直接传递"UTF-8",看源码能看到内部也是将传递的字符串拿给了Charset
// 读取,进行分析等操作
while (br.readLine() != null) {
System.out.println(br.readLine());
}
br.close();
当然不是所有的网站都能通过上面的方式爬到资源的,有些网站会拒绝Java的直接访问。比如
这个时候该怎么解决呢?我们发现我们直接通过浏览器也是能够访问的,所以我们就自然的想到,Java是否能模拟浏览器访问?要模仿浏览器的访问,我们可以看到请求头里一个关键的属性叫做,UA(User-Agent),也就是用户代理,它能够让服务器识别客户的操作系统,浏览器类型等信息。UA属性的值可以在浏览器控制台请求头里找到。
// 获取URL,不允许直接读取的
URL url = new URL("http://www.dianping.com");
// 下载资源, 以浏览器访问的方式去读取连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置访问方法
connection.setRequestMethod("GET");
// 设置UA
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0");
InputStream is = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
while (br.readLine() != null) {
System.out.println(br.readLine());
}
br.close();