【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 使用爬虫获取随机姓名

外部链接:

百家姓:百家姓_诗词_百度汉语 (baidu.com)

男生名字:男生有诗意的名字推荐(龙年男孩起名) (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)

URL与URI,有联系有区别? - 知乎 (zhihu.com)

URL、URI、URN:有什么区别? - 掘金 (juejin.cn)

posted @ 2024-01-28 00:39  Zebt  阅读(88)  评论(0)    收藏  举报