文章目录
前言
学习这个爬虫前,先复习一下前面的正则表达式。参考博客
爬虫其实并不难,学习爬虫的最好例子就是直接上实际例子练习。
一、网络爬虫
案例一(先看这一个入门):
1 需求
现在我们需要测试一个随机点名系统,但是现在又一个难题就是我们没有姓名名单。所以我们的任务就是获取一份假的姓名名单将其保存在一个txt中。如果是少量姓名数据,人为写进txt中也是可以的。但是我们这里采用一种比较高端的方式–爬虫。
下面我们就会爬取这三个网站上的信息来构造我们的点名系统名册。
2 爬取整个html
我们先来爬取整个网址看看是爬取下来的什么东西!
package cn.hjblogs.demo2;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class Test {
public static void main(String[] args) throws IOException {
/*
* 制造假数据
* 获取姓:https://hanyu.baidu.com/shici/detail?from=aladdin&pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d
* 获取男生名字: http://www.haoming8.cn/baobao/10881.html
* 获取女生名字: http://www.haoming8.cn/baobao/7641.html
*/
// 1. 定义变量记录网址
String familyNameNet = "https://hanyu.baidu.com/shici/detail?from=aladdin&pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d";
String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";
String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";
// 2 爬取数据,由于这里是爬取姓名,我们将所有数据拼接成一个字符串即可
String familyNameData = webCrawler(familyNameNet);
System.out.println(familyNameData);
}
/*
* 作用:从网络中爬取数据,把数据拼接成字符串返回
* 形参: 网址
* 返回值:爬取到的所有数据
* */
public static String webCrawler(String net) throws IOException {
StringBuilder sb = new StringBuilder();
// 1 创建一个URL对象
URL url = new URL(net);
// 2 连接上这个网络,细节:保证网络是畅通的,在浏览器中能访问
URLConnection conn = url.openConnection();
// 3 读取数据 conn.getInputStream() 返回的是一个字节流,我们需要转换成字符流才能处理中文,所以转换流在某些场景下还是有用的
InputStreamReader isr = new InputStreamReader(conn.getInputStream());
int ch;
while ((ch = isr.read()) != -1) {
sb.append((char) ch);
}
isr.close();
return sb.toString();
}
}
看看我们直接爬取爬取下来了什么东西:
可以看到爬取了整个网页的html。但是整个html不是我们想要的,我们想从html中获取我们想要的内容就要使用正则表达式了。因此我们还需要写一个方法利用正则表达式从html中获取我们想要数据的方法。
3 使用正则表达式从html中获取想要内容
package cn.hjblogs.demo2;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) throws IOException {
/*
* 制造假数据
* 获取姓:https://hanyu.baidu.com/shici/detail?from=aladdin&pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d
* 获取男生名字: http://www.haoming8.cn/baobao/10881.html
* 获取女生名字: http://www.haoming8.cn/baobao/7641.html
*/
// 1. 定义变量记录网址
String familyNameNet = "https://hanyu.baidu.com/shici/detail?from=aladdin&pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d";
String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";
String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";
// 2 爬取数据,由于这里是爬取姓名,我们将所有数据拼接成一个字符串即可
// (1)爬取姓
String familyNameData = webCrawler(familyNameNet);
// System.out.println(familyNameData);
String regex1 = "(<div class=\"text\">)(.{1})(</div>)"; // 正则表达式,这里对其分一个组,我们只需要第二个组的数据
ArrayList<String> familyName_lst = getData(familyNameData, regex1, 2);
System.out.println(familyName_lst); // [赵,钱,...]
// (2)爬取男生名字
String boyNameData = webCrawler(boyNameNet);
// System.out.println(boyNameData);
String regex2 = "([\\u4E00-\\u9FA5]{2})(、|。)"; // [\u4E00-\u9FA5] 表示一个中文字符
ArrayList<String> boyName_lst = getData(boyNameData, regex2, 1);
System.out.println(boyName_lst); // [月星、弘城、雨国、...]
// (3)爬取女生名字
String girlNameData = webCrawler(girlNameNet);
// System.out.println(girlNameData);
String regex3 = "<p>((.. ){4}..)</p>";
ArrayList<String> girlName_lst = getData(girlNameData, regex3, 1);
System.out.println(girlName_lst); // [彤舞 芊静 艾丝 惠蕙 语月, 依莹 瑶馨 曼珍 逸云 微婉, ...] 需要注意的是,这个一个元素中有多个名字,还需要进一步处理
// 注意上述正则匹配还比较粗糙,可以根据实际情况进行调整,但是这里差不多可以够我们使用了
// 下面这里就可以进一步处理,爬虫到这里就结束了。
}
/*
* 作用:从网络中爬取数据,把数据拼接成字符串返回
* 形参: 网址
* 返回值:爬取到的所有数据
* */
public static String webCrawler(String net) throws IOException {
StringBuilder sb = new StringBuilder();
// 1 创建一个URL对象
URL url = new URL(net);
// 2 连接上这个网络,细节:保证网络是畅通的,在浏览器中能访问
URLConnection conn = url.openConnection();
// 3 读取数据 conn.getInputStream() 返回的是一个字节流,我们需要转换成字符流才能处理中文,所以转换流在某些场景下还是有用的
InputStreamReader isr = new InputStreamReader(conn.getInputStream());
int ch;
while ((ch = isr.read()) != -1) {
sb.append((char) ch);
}
isr.close();
return sb.toString();
}
/*
* 作用:从爬取的html中利用正则表达式获取数据
* 参数一:html_str 爬取的html(str)
* 参数二:regex 正则表达式
* 参数三:group 正则表达式中的组,我们只要从匹配结果中获取我们想要的组的数据
* 返回值:返回一个集合,集合中存储了我们想要的数据
* */
public static ArrayList<String> getData(String html_str, String regex, int group){
// 1. 定义一个集合,用来存储数据
ArrayList<String> list = new ArrayList<>();
// 2. 按照正则表达式是规则,去获取数据
Pattern pattern = Pattern.compile(regex);
// 3 按照pattern的规则,去匹配html_str中的数据
Matcher matcher = pattern.matcher(html_str);
// 4. 遍历matcher,获取数据
while (matcher.find()) {
String s = matcher.group(group); // 获取正则表达式中的第group组的数据
list.add(s);
// System.out.println(s);
}
return list;
}
}
【注】:爬取的过程中药根据html不断调整合适的正则表达式,这点可以将上面的System.out.println(s);这行注释取消,String s = matcher.group();中不要传入参数看看匹配的是不是我们想要的来进一步调整,或者直接在html中CTRL+F使用正则查找功能。
while (matcher.find()) {
String s = matcher.group();
list.add(s);
System.out.println(s