【Java 网络编程】6 - 2 使用 URL 访问网络资源
§6-2 使用 URL 访问网络资源
6-2.1 URL 和 URI 简介
统一资源定位符(URL, Uniform Resource Locator)是一个给定的独特资源在 Web 上的地址。每一个有效 URL 理论上都指向 Web 中唯一的资源。URL 是浏览器用于检索 Web 上公布的任何资源的机制。
URL 由协议(protocol)、主机标识符(host identifier)、端口号(port number)、路径(path)组成。有时,URL 中还会含有查询(query)部分、参数(parameter)、锚点定位(anchor)。以下是一个 URL 格式示例:
protocol://host/path // 最常使用
protocol://host:port/path // 需要端口号时使用
protocol://host:port/path/.../;url-params?query-string#anchor
http://localhost:8080/zebt/helloworld/index.jsp?username=zebt&password=admin123
https://developer.mozilla.org
https://developer.mozilla.org/zh-CN/docs/Learn/
https://developer.mozilla.org/zh-CN/docs/search?q=URL
常用的协议有超文本传输协议(HyperText Transfer Protocol)、超文本传输安全协议(HyperText Transfer Protocol Secure)、文件传输协议(File Transfer Protocol)、简单邮件传输协议(Simple Mail Transfer Protocol)、安全壳(Secure Shell)、终端网络(TELNET, TErminaL NETwork)等。
URL 不仅标识了资源,并为该资源指明了其方向(定位)。
域名需要经过域名解析服务(DNS, Domain Name Service)得到对应的 IP 地址后才能访问。
统一资源标识符(URI, Uniform Resource Identifier)是一个字符串表示的抽象或物理资源。Web 上的各种可用资源都可由 URI 定位,URI 是 URL 更高层次的抽象,是 URL 的超集。
URI 的格式也由三部分组成:访问资源的命名机制、存放资源的主机名、由路径表示的资源自身名称。URI 指示标识了资源,并没有指明资源的定位。
6-2.2 在 Java 中使用 URL 访问网络资源
java.net.URL 允许通过 URL 访问 Web 上的资源。但自 Java 20 起,URL 的构造方法被弃用。若要构造 URL 对象,则需要先构造对应地 java.net.URI 对象,再调用 URI.toURL() 获取 URL 对象。
URI 构造方法:
| 构造方法 | 描述 |
|---|---|
URI(String str) |
解析给定字符串,构造一个 URI |
URI(String scheme, String ssp, String fragment) |
从给定的部分构造一个 URI |
URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)URI(String scheme, String host, String path, String fragement)URI(String scheme, String authority, String path, String query, String fragment) |
从给定的部分构造一个具有层级的 URI |
也可用 URI 的一个静态工厂方法获取 URI 对象:
| 静态方法 | 描述 |
|---|---|
URI create(String str) |
解析所给字符串,创建一个 URI |
URI 常用方法:
| 方法 | 描述 |
|---|---|
String getAuthority() |
返回解码后的 authority 部分 |
String getHost() |
返回主机部分 |
String getPath() |
返回路径部分 |
int getPort() |
返回端口号部分 |
String getQuery() |
返回查询部分 |
String getScheme() |
返回协议部分 |
String getRawAuthority() |
返回原始 authority 部分 |
String getRawPath() |
返回原始路径部分 |
String getRawQuery() |
返回原始查询部分 |
String getRawScheme() |
返回原始协议部分 |
URL toURL() |
从当前 URI 构建一个 URL |
获取到 URL 对象后,可开启连接并通过流的方式访问资源。
URL 常用方法:
| 方法 | 描述 |
|---|---|
String getFile() |
获取文件部分 |
int getDefaultPort() |
获取默认端口号 |
String getProtocol() |
获取协议部分 |
URLConnection openConnection() |
开启连接并返回表示该连接的 URLConnection 对象 |
URLConnection openConnection(Proxy proxy) |
行为同 openConnection(),但连接经过指定代理 |
final InputStream openStream() |
开启连接并返回读取该连接的流 |
6-2.3 使用爬虫获取随机姓名
外部链接:
男生名字:男生有诗意的名字推荐(龙年男孩起名) (haoming8.cn)
女生名字:2024年清新有诗意女孩名字取名(龙年女孩名字) (haoming8.cn)
获取前端页面代码:
// 获取前端页面代码
public static String netCrawler(String uri) throws IOException, URISyntaxException {
// 创建 URL
URL url = new URI(uri).toURL();
// 链接 URL
URLConnection conn = url.openConnection();
// 爬取前端数据
StringBuilder sb = new StringBuilder();
// 获取链接的字节输入流,但要读取文本,应当使用字符流
// 综上,使用转换流
InputStreamReader isr = new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8);
char[] chars = new char[1024];
int len;
while ((len = isr.read(chars)) != -1) {
sb.append(chars, 0 ,len);
}
isr.close();
return sb.toString();
}
过滤获得姓氏:
// 获取姓氏
public static String filterFamilyNames(String rawData) {
Matcher matcher = Pattern.compile("(.{4})(?=,|。)").matcher(rawData);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
sb.append(matcher.group());
}
return sb.toString();
}
过滤获得男生姓名:
// 正则表达式初步过滤,再对数据进一步处理,去重去掉不满足条件的项
public static ArrayList<String> filterBoyNames(String rawData) {
Matcher matcher = Pattern.compile("([\\u4E00-\\u9FA5]{2})(?=、|。)").matcher(rawData);
ArrayList<String> names = new ArrayList<>();
int i = 0;
while (matcher.find()) {
// 开始
if (i < 6) {
i++;
continue;
}
String capture = matcher.group();
// 结束
if (capture.equals("吉利")) {
break;
}
names.add(capture);
}
return names;
}
过滤获得女生姓名:
public static ArrayList<String> filterGirlNames(String rawData) {
Matcher matcher = Pattern.compile("([\\u4E00-\\u9FA5]{2} ){4}[\\u4E00-\\u9FA5]{2}").matcher(rawData);
ArrayList<String> names = new ArrayList<>();
while (matcher.find()) {
Collections.addAll(names, matcher.group().split(" "));
}
return names;
}
生成假数据:
// 生成假数据
public static ArrayList<String> generate(ArrayList<String> boyNames, ArrayList<String> girlNames, String familyNames, int boyNum, int girlNum) {
Random rnd = new Random();
HashSet<String> boys = new HashSet<>();
for (int i = 0; i < boyNum; i++) {
// 年龄 18 - 27
boys.add(familyNames.charAt(rnd.nextInt(familyNames.length())) + boyNames.get(rnd.nextInt(boyNames.size())) + "-男-" + (rnd.nextInt(10) + 18));
}
HashSet<String> girls = new HashSet<>();
for (int i = 0; i < girlNum; i++) {
// 年龄 18 - 25
girls.add(familyNames.charAt(rnd.nextInt(familyNames.length())) + girlNames.get(rnd.nextInt(girlNames.size())) + "-女-" + (rnd.nextInt(8) + 18));
}
return (ArrayList<String>) Stream.concat(boys.stream(), girls.stream()).collect(Collectors.toList());
}
主方法:
public static void main(String[] args) throws IOException, ClassNotFoundException, URISyntaxException {
// 爬取姓氏和名字,利用正则表达式过滤,再进一步处理
String familyNames = netCrawler("https:// hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0");
familyNames = filterFamilyNames(familyNames);
ArrayList<String> boyNames = filterBoyNames(netCrawler("http:// www.haoming8.cn/baobao/10881.html"));
ArrayList<String> girlNames = filterGirlNames(netCrawler("http:// www.haoming8.cn/baobao/7641.html"));
// 拼接数据
ArrayList<String> data = generate(boyNames, girlNames, familyNames, 10, 10);
System.out.println(data);
// 序列化到文件中
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("JavaSE\\files\\aaa\\fakeNames.txt"));
oos.writeObject(data);
oos.close();
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("JavaSE\\files\\aaa\\fakeNames.txt"));
ArrayList<String> res = (ArrayList<String>) ois.readObject();
System.out.println(res);
}
6-2.4 使用 URL 下载 Web 资源
JDK 21(Windows)下载地址:https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe
JDK 21(x64 MacOS)下载地址:https://download.oracle.com/java/21/latest/jdk-21_macos-x64_bin.dmg
JDK 21(ARM MacOS)下载地址:https://download.oracle.com/java/21/latest/jdk-21_macos-aarch64_bin.dmg
JDK 21(ARM64 Linux)下载地址:https://download.oracle.com/java/21/latest/jdk-21_linux-aarch64_bin.rpm
JDK 21(x64 Debian)下载地址:https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.deb
JDK 21(x64 RPM)下载地址:https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.rpm
public static void main(String[] args) throws URISyntaxException, IOException {
URL url = new URI("https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe").toURL();
String[] split = url.getFile().split("\\/");
URLConnection connection = url.openConnection();
BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("JavaSE\\files\\downloads\\" + split[split.length - 1])));
byte[] buffer = new byte[1024];
int len = 0;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
bis.close();
}
6-2.X 参考资料
什么是 URL? - 学习 Web 开发 | MDN (mozilla.org)
浙公网安备 33010602011771号