Java—— 网络爬虫

案例要求

复制代码
https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0
http://www.haoming8.cn/baobao/10881.html
http://www.haoming8.cn/baobao/7641.html

上面三个网址分别表示百家姓,男生名字,女生名字,如图:

要求:

获取上述网址中的内容,利用正则表达式爬取姓氏和名字信息,并生成不重复的10个男生的姓名和10个女生的姓名 ,将生成的姓名保存到本模块下的a.txt文件中。

关于网络的方法

URL网址对象

|-------------------------|---------------------|
| 构造方法 | 说明 |
| public URL(String spec) | 利用记录网址的字符串创建一个网址的对象 |

|---------------------------------------|------------------------------------|
| 成员方法 | 说明 |
| public URLConnection openConnection() | 网址对象调用该方法让程序连接网址,返回程序和URL之间的通信链接对象 |

URLConnection通信链接对象

|-------------------------------------|--------------|
| 成员方法 | 说明 |
| public InputStream getInputStream() | 得到连接网址的字节输入流 |

关于爬虫的方法

Pattern正则表达式对象

|---------------------------------------------|----------------------------|
| 构造方法 | 说明 |
| public static Pattern compile(String regex) | 获取正则表达式的对象,传递的是表示正则表达式的字符串 |

|------------------------------------|--------------------------------------|
| 成员方法 | 说明 |
| public Matcher matcher(String str) | 正则表达式对象调用该方法获取文本匹配器的对象,传递的是需要进行查找的大串 |

Matcher文本匹配器对象

|-----------------------|------------------------------------------------------------------------------|
| 成员方法 | 说明 |
| public boolean find() | 让文本匹配器从头开始读取大串,寻找是否有满足正则表达式的子串。如果没有,方法返回false,如果有,返回true。在底层记录子串的起始索引和结束索引+1 |
| public String group() | 方法底层会根据find()方法记录的索引进行字符串的截取,返回截取的小串,该小串就是符合正则表达式要求的子串 |

代码实现

java 复制代码
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test1 {
    public static void main(String[] args) throws IOException {

        //记录网址
        String familyNameWeb = "https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0";
        String boyNameweb = "http://www.haoming8.cn/baobao/10881.html";
        String girlNameweb = "http://www.haoming8.cn/baobao/7641.html";

        //调用方法网络爬取网址内容并以字符串形式返回
        String familyNameStr = webCrawler(familyNameWeb);
        String boyNameStr = webCrawler(boyNameweb);
        String girlNamewebStr = webCrawler(girlNameweb);


        //利用正则表达式获取网址中的姓氏和名字
        //按照所需数据在网址内容中的布局不同设置不同的正则表达式

        //百家姓网址中所需的百家姓数据都是4个中文一组后面跟逗号或句号,且只获取符合前的内容
        //中文的正则表达式为[\u4E00-\u9FA5]
        ArrayList<String> familyNameTempList = getData(familyNameStr, "([\\u4E00-\\u9FA5]){4}(?=,|。)");

        //男生名字网址中所需的名字数据都是2个中文一组后面跟顿号或句号,且只获取符合前的内容
        ArrayList<String> boyNameTempList = getData(boyNameStr, "([\\u4E00-\\u9FA5]){2}(?=、|。)");

        //女生名字网址中所需的名字数据都是2个中文加1个空格4组后面跟2个中文,都获取
        ArrayList<String> girlNameTempList = getData(girlNamewebStr,
                "(([\\u4E00-\\u9FA5]){2} ){4}[\\u4E00-\\u9FA5]{2}");


        //得到了初始数据集合,将其优化方便使用

        //System.out.println(familyNameTempList);
        //[赵钱孙李, 周吴郑王, 冯陈褚卫, 蒋沈韩杨,......
        //修改百家姓集合为:只保留前410个单姓,并且每一个姓氏占一个索引
        ArrayList<String> familyNameTemp2List = new ArrayList<>();
        ArrayList<String> familyNameList = new ArrayList<>();
        for (String s : familyNameTempList) {
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                familyNameTemp2List.add(c + "");
            }
        }
        //只保留前410个单姓
        for (int i = 0; i < 410; i++) {
            familyNameList.add(familyNameTemp2List.get(i));
        }
        //System.out.println(familyNameList);
        //[赵, 钱, 孙, 李, 周, 吴, 郑, 王,......

        //System.out.println(boyNameTempList);
        //[大气, 美好, 特色, 大气, 美好, 特色, 月星, 弘城, 雨国, 思明,.....
        //修改男生名字集合为:去除重复,每一个名字占一个索引
        ArrayList<String> boyNameList = new ArrayList<>();
        for (String s : boyNameTempList) {
            if (!boyNameList.contains(s)) {
                boyNameList.add(s);
            }
        }
        //System.out.println(boyNameList);
        //[大气, 美好, 特色, 月星, 弘城, 雨国, 思明, ......

        //System.out.println(girlNameTempList);
        //[彤舞 芊静 艾丝 惠蕙 语月, 依莹 瑶馨 曼珍 逸云 微婉,.....
        //修改女生名字集合为:去除重复,每一个名字占一个索引
        ArrayList<String> girlNameList = new ArrayList<>();
        for (String s : girlNameTempList) {
            String[] arr = s.split(" ");
            for (int i = 0; i < arr.length; i++) {
                girlNameList.add(arr[i]);
            }
        }
        //System.out.println(girlNameList);
        //[彤舞, 芊静, 艾丝, 惠蕙, 语月, 依莹, ......


        //调用方法根据准备好的数据分别获取不重复的10个男生名字和女生名字
        //参数为坐标的数据和男女要生成名字的数量
        ArrayList<String> nameList = getName(familyNameList, boyNameList, girlNameList, 10, 10);

        //利用缓冲字符输出流写到本模块下的a.txt文件中
        BufferedWriter bw = new BufferedWriter(new FileWriter("day05\\a.txt"));
        for (String s : nameList) {
            bw.write(s);
            bw.newLine();
        }
        bw.close();

    }

    private static ArrayList<String> getName(ArrayList<String> familyNameList, ArrayList<String> boyNameList,
                                             ArrayList<String> girlNameList, int bCount, int gCount) {

        //定义集合存储生成的不重复的男生名字
        HashSet<String> boyList = new HashSet<>();

        //生成男生名字
        while (true) {
            //存够数量跳出
            if (boyList.size() == bCount) {
                break;
            }
            //打乱集合中的内容
            Collections.shuffle(familyNameList);
            Collections.shuffle(boyNameList);
            //将打乱后的集合的0索引位置的姓和名拼接并标注男生,添加到男生名字集合中
            boyList.add(familyNameList.get(0) + boyNameList.get(0) + "-男");
        }

        //定义集合存储生成的不重复的女生名字
        HashSet<String> girlList = new HashSet<>();
        while (true) {
            //存够数量跳出
            if (girlList.size() == gCount) {
                break;
            }
            //打乱集合中的内容
            Collections.shuffle(familyNameList);
            Collections.shuffle(girlNameList);
            //将打乱后的集合的0索引位置的姓和名拼接并标注女生,添加到女生名字集合中
            girlList.add(familyNameList.get(0) + girlNameList.get(0) + "-女");
        }

        //定义集合存储生成的名字
        ArrayList<String> nameList = new ArrayList<>();
        //将男女名字集合中的数据放到一个集合中,方便返回
        for (String s : boyList) {
            nameList.add(s);
        }
        for (String s : girlList) {
            nameList.add(s);
        }

        return nameList;
    }


    //正则表达式
    private static ArrayList<String> getData(String str, String regex) {
        //定义集合存储符合正则表达式的数据
        ArrayList<String> list = new ArrayList<>();

        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(str);
        while (m.find()) {
            String s = m.group();
            list.add(s);
        }

        return list;

    }


    //网络爬取
    private static String webCrawler(String web) throws IOException {

        //获取网址对象
        URL url = new URL(web);
        //让程序连接网址
        URLConnection uc = url.openConnection();
        //读取网址内的数据:
        //得到得到连接网址的字节输入流
        InputStream is = uc.getInputStream();
        //利用转换流将字节流转换为字符流方便读中文
        InputStreamReader isr = new InputStreamReader(is);
        //定义StringBuilder用于拼接读到的数据
        StringBuilder sb = new StringBuilder();
        //开始读
        int b;
        while ((b = isr.read()) != -1) {
            sb.append((char) b);
        }
        //读完关流
        isr.close();
        //返回读到的数据
        return sb.toString();
    }
}
相关推荐
熊猫钓鱼>_>4 分钟前
Python小工具开发实战:从零构建自动化文件管理器的心得与体悟
开发语言·python·自动化
lb291713 分钟前
关于golang热加载安装,实时响应
开发语言·后端·golang·热加载
A227416 分钟前
自定义线程池 4.0
java·线程池
陈奕迅本讯19 分钟前
并发编程-Synchronized
开发语言·c#
康小庄20 分钟前
AQS独占模式——资源获取和释放源码分析
java·开发语言·jvm·spring boot·spring·spring cloud·nio
阿昌喜欢吃黄桃26 分钟前
mac安装mvnd结合idea
java·maven·idea·编译·打包·mvnd·编译打包
草明27 分钟前
macOS 查看当前命令行的ruby的安装目录
开发语言·macos·ruby
汤姆yu34 分钟前
基于python大数据的nba球员可视化分析系统
大数据·开发语言·python
feifeigo12342 分钟前
python从环境变量和配置文件中获取配置参数
开发语言·python·adb
轩宇^_^42 分钟前
C语言结构体与联合体详解
c语言·开发语言