API
爬虫
练习
本地爬虫和网络爬虫
(1)本地爬虫
有如下文本,请按照要求爬取数据。
Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台
要求:找出里面所有的JavaXX
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class RegexDemo04 {public static void main(String[] args) {/*有如下文本,请按照要求爬取数据。Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台要求:找出里面所有的JavaXX*/String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,"+"因为这两个是长期支持版本,下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台";//method1(str);//1.获取正则表达式的对象Pattern p = Pattern.compile("Java\\d{0,2}");//2.获取文本匹配器的对象//拿着m去读取str,找符合p规则的子串Matcher m = p.matcher(str);//3.利用循环获取while(m.find()) {String s = m.group();System.out.println(s);}}private static void method1(String str) {//Pattern:表示正则表达式//Matcher:文本匹配器,作用按照正则表达式的规则去读取字符串,从头开始读取。// 在大串中去找符合规则的子串。//获取正则表达式的对象Pattern p = Pattern.compile("Java\\d{0,2}");//获取文本匹配器的对象//m:文本匹配器的对象//str:大串//p:规则//m要在str中找符合p规则的小串Matcher m = p.matcher(str);//拿着文本匹配器从头开始读取,寻找是否有满足规则的子串//如果没有,方法返回false//如果有,返回true。在底层记录字串的起始索引和结束索引+1//0,4boolean b = m.find();//方法底层会根据find方法记录的索引进行字符串的截取//subString(起始索引,结束索引);包头不包尾//(0,4)但是不包含4索引//会把截取的小串进行返回String s1 = m.group();System.out.println(s1);//Java//第二次在调用find的时候,会继续读取后面的内容//读取到第二个满足要求的子串,方法会继续返回true//并把第二个字串的起始索引和结束索引+1,进行记录b = m.find();//第二次调用group方法的时候,会根据find方法记录的索引再次截取子串String s2 = m.group();System.out.println(s2);}
}
(2)网络爬虫
public class RegexDemo05 {public static void main(String[] args) {/* 扩展需求2:把链接:https://m.sengzan.com/jiaoyu/29104.html?ivk_sa=1025883i中所有的身份证号码都爬取出来*///创建一个URL对象URL url = null;try {url = new URL("https://m.sengzan.com/jiaoyu/29104.html?ivk_sa=1025883i");} catch (MalformedURLException e) {throw new RuntimeException(e);}//连接上这个网址//细节:保证网络畅通URLConnection conn;try {conn = url.openConnection();} catch (IOException e) {throw new RuntimeException(e);}//创建一个对象去读取网络中的数据BufferedReader br;try {br = new BufferedReader(new InputStreamReader(conn.getInputStream()));} catch (IOException e) {throw new RuntimeException(e);}String line;//获取正则表达式的对象 patternString regex = "[1-9]\\d{17}";Pattern pattern = Pattern.compile(regex);//在读取的时候每次读一整行while (true) {try {if (!((line = br.readLine()) != null)) break;} catch (IOException e) {throw new RuntimeException(e);}//拿着文本匹配器的对象matcher按照pattern的规则去读取当前的这一行信息Matcher matcher = pattern.matcher(line);while(matcher.find()) {System.out.println(matcher.group());}}try {br.close();} catch (IOException e) {throw new RuntimeException(e);}}
}
(3)需求:把下面文本中的电话,邮箱,手机号,热线都爬取出来。
来黑马程序员学习Java,
电话:18512516758,18512508907
或者联系邮箱:boniu@itcast.cn,
座机电话:01036517895,010-98951256
邮箱:bozai@itcast.cn,
热线电话:400-618-9090,400-618-4000,4006184000,4006189090
public class RegexDemo06 {public static void main(String[] args) {/* 需求:把下面文本中的电话,邮箱,手机号,热线都爬取出来。来黑马程序员学习Java,电话:18512516758,18512508907或者联系邮箱:boniu@itcast.cn,座机电话:01036517895,010-98951256邮箱:bozai@itcast.cn,热线电话:400-618-9090,400-618-4000,4006184000,4006189090手机号的正则表达式:1[3-9]\d{9}邮箱的正则表达式:\w+@[\w&&[^_]]{2,6}(\.[a-zA-Z]{2,3}){1,2}座机电话的正则表达式:0\d{2,3}-?[1-9]\d{4,9}热线电话的正则表达式:400-?[1-9]\\d{2}-?[1-9]\\d{3}*/String s = "来黑马程序员学习Java,"+"电话:18512516758,18512508907"+"或者联系邮箱:boniu@itcast.cn,"+"座机电话:01036517895,010-98951256"+"邮箱:bozai@itcast.cn,"+"热线电话:400-618-9090,400-618-4000,4006184000,4006189090";System.out.println("400-618-9090".matches("400-?[1-9]\\d{2}-?[1-9]\\d{3}"));//trueSystem.out.println("400-618-4000".matches("400-?[1-9]\\d{2}-?[1-9]\\d{3}"));//trueSystem.out.println("4006184000".matches("400-?[1-9]\\d{2}-?[1-9]\\d{3}"));//trueSystem.out.println("4006189090".matches("400-?[1-9]\\d{2}-?[1-9]\\d{3}"));//trueString regex = "(1[3-9]\\d{9})" +"|(\\w+@[\\w&&[^_]]{2,6}(\\.[a-zA-Z]{2,3}){1,2})" +"|(0\\d{2,3}-?[1-9]\\d{4,9})" +"|(400-?[1-9]\\d{2}-?[1-9]\\d{3})";//1.获取正则表达式的对象Pattern p = Pattern.compile(regex);//2.获取文本匹配器的对象//利用m去读取s,会按照p的规则找里面的小串Matcher m = p.matcher(s);//3.利用循环获取每一个数据while(m.find()) {String str = m.group();System.out.println(str);}}
}
(4)有条件的爬取数据
有如下文本,请按照要求爬取数据。
Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台
需求1:爬取版本号为8,11,17的Java文本,但是只要Java,不显示版本号。
需求2:爬取版本号为8,11,17的Java文本。正确爬取结果为:Java8 Java11 Java17 Java17
需求3:爬取除了版本号为8,11,17的Java文本。
public class RegexDemo07 {public static void main(String[] args) {/* 有如下文本,请按照要求爬取数据。Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台需求1:爬取版本号为8,11,17的Java文本,但是只要Java,不显示版本号。需求2:爬取版本号为8,11,17的Java文本。正确爬取结果为:Java8 Java11 Java17 Java17需求3:爬取除了版本号为8,11,17的Java文本。*/String s = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本," +"下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台";//1.定义正则表达式//?理解为前面的数据Java//=表示在Java后面要跟随的数据//但是在获取的时候,只获取前半部分//需求1:String regex1 = "Java(?=8|11|17)";//需求2:String regex2 = "Java(8|11|17)";//String regex2 = "Java(?:8|11|17)";//需求3:String regex3 = "Java(?!8|11|17)";Pattern p = Pattern.compile(regex3);Matcher m = p.matcher(s);while(m.find()) {System.out.println(m.group());}}
}
(5)贪婪爬取和非贪婪爬取
有如下文本,请按照要求爬取数据。
Java自从95年问世以来,abbbbbbbbbbbaaaaaaaaaaaaaaaaa经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台
需求1:按照ab+的方式爬取ab,b尽可能多获取
需求2:按照ab+的方式爬取ab,b尽可能少获取
public class RegexDemo08 {public static void main(String[] args) {/* 有如下文本,请按照要求爬取数据。Java自从95年问世以来,abbbbbbbbbbbaaaaaaaaaaaaaaaaa经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台需求1:按照ab+的方式爬取ab,b尽可能多获取需求2:按照ab+的方式爬取ab,b尽可能少获取只写+和*表示贪婪匹配+? 非贪婪匹配*? 非贪婪匹配贪婪爬取:在爬取数据的时候尽可能多的获取数据非贪婪爬取:在爬取数据的时候尽可能少的获取数据ab+:贪婪爬取:abbbbbbbbbbb非贪婪爬取:abJava当中,默认的就是贪婪爬取如果我们在数量词+ * 的后面加上问号,那么此时就是非贪婪爬取*/String s = "Java自从95年问世以来,abbbbbbbbbbbaaaaaaaaaaaaaaaaa经历了很多版本," +"目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本," +"下一个长期支持版本时Java17,相信在未来不久Java17也会逐渐登上历史舞台";String regex = "ab+?";Pattern p = Pattern.compile(regex);Matcher m = p.matcher(s);while(m.find()) {System.out.println(m.group());}}
}
(6)正则表达式在字符串方法中的使用
方法名 | 说明 |
---|---|
public String[] matches(String regex) | 判断字符串是否满足正则表达式的规则 |
public String replaceAll(String regex,String newStr) | 按照正则表达式的规则进行替换 |
public String[] split(String regex) | 按照正则表达式的规则切割字符串 |
public class RegexDemo09 {public static void main(String[] args) {//public String replaceAll(String regex,String newStr) 按照正则表达式的规则进行替换//public String[] split(String regex) 按照正则表达式的规则切割字符串/*有一段字符串:小诗诗djifndjniw34小丹丹sachbauqw87小惠惠要求1:把字符串中三个名字之间的字母替换为vs要求2:把字符串中的三个名字切割出来*/String s = "小诗诗djifndjniw34小丹丹sachbauqw87小惠惠";//细节://方法在底层跟之前一样也会创建文本解析器的对象//然后从头开始去读取字符串中的内容,只要有满足的的,那么就用第二个参数去替换//String result1 = s.replaceAll("[\\w&&[^_]]+", "vs");//System.out.println(result1);//小诗诗vs小丹丹vs小惠惠String[] arr = s.split("[\\w&&[^_]]+");for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);}}
}
捕获分组和非捕获分组
分组
分组就是一个小括号
每组是有组号的,也就是序号。
规则1:从1开始,连续不间断。
规则2:以左括号为基准,最左边的是第一组,其次为第二组,以此类推。
练习
捕获分组的联系
捕获分组就是把这一组的数据捕获出来,再用一次。
需求1:判断一个字符串的开始字符和结束字符是否一致?只考虑一个字符
举例:a123a b456b 17891 &abc&
需求2:判断一个字符串的开始部分和结束部分是否一致?可以有多个字符
举例:abc123abc b456b 123789123 &!@abc&!@
需求3:判断一个字符串的开始字符和结束字符是否一致?开始部分内部每个字符也需要一致
举例:aaa123aaa bbb456bbb 111789111 &&abc&&
public class RegexDemo10 {public static void main(String[] args) {/*需求1:判断一个字符串的开始字符和结束字符是否一致?只考虑一个字符举例:a123a b456b 17891 &abc& a123b(false)需求2:判断一个字符串的开始部分和结束部分是否一致?可以有多个字符举例:abc123abc b456b 123789123 &!@abc&!@ abc123abd(false)需求3:判断一个字符串的开始字符和结束字符是否一致?开始部分内部每个字符也需要一致举例:aaa123aaa bbb456bbb 111789111 &&abc&&*///需求1:// \\组号:表示把第X组的内容再拿出来用一次String regex1 = "(.).+\\1";System.out.println("a123a".matches(regex1));System.out.println("b456b".matches(regex1));System.out.println("17891".matches(regex1));System.out.println("&abc&".matches(regex1));System.out.println("a123b".matches(regex1));System.out.println("---------------------");//需求2:String regex2 = "(.+).+\\1";System.out.println("abc123abc".matches(regex2));System.out.println("b456b".matches(regex2));System.out.println("123789123".matches(regex2));System.out.println("&!@abc&!@".matches(regex2));System.out.println("abc123abd".matches(regex2));System.out.println("---------------------");//需求3://(.):把首字母看作一组// \\2:把首字母拿出来再次使用// *:作用于\\2,表示后面重复的内容出现0次或多次String regex3 = "((.)\\2*).+\\1";System.out.println("aaa123aaa".matches(regex3));System.out.println("bbb456bbb".matches(regex3));System.out.println("111789111".matches(regex3));System.out.println("&&abc&&".matches(regex3));System.out.println("1a12".matches(regex3));System.out.println("---------------------");}
}
口吃替换
需求:
将字符串:我要学学编编编编程程程程程程
替换为:我要学编程
public class Regex11 {public static void main(String[] args) {/*将字符串:我要学学编编编编程程程程程程替换为:我要学编程*/String str = "我要学学编编编编程程程程程程";//需求:把重复的内容 替换为 单个的//学学 学//编编编编 编//程程程程程程 程//(.) 表示把重复内容的第一个字符看作一组// \\1表示第一组字符再次出现//+ 至少一次//$1 表示把正则表达式中第一组的内容,再拿出来用String result = str.replaceAll("(.)\\1+", "$1");System.out.println(result);}
}
总结:
捕获分组:后续还要继续使用本组的数据
正则内部使用:\\组号
正则外部使用:$组号
非捕获分组:分组之后不需要再用本组数据,仅仅是把数据括起来。(不占用组号)
符号 | 含义 | 举例 |
---|---|---|
(?:正则) | 获取所有 | Java(?:8|11|17) |
(?= 正则) | 获取前面部分 | Java(?=8|11|17) |
(?! 正则) | 获取不是指定内容的前面部分 | Java(?!8|11|17) |
说明:
以上笔记学习是学习b站黑马程序员时记下的笔记,仅限于帮助理解学习,不做任何其他商业用途。
黑马程序员