详解HttpURLConnection_清箫的博客-CSDN博客_httpurlconnection
一个是URL,一个是HeepURLConnection:
任何网络连接都需要经过socket才能连接,HttpURLConnection不需要设置socket,所以,HttpURLConnection并不是底层的连接,而是在底层连接上的一个请求。这就是为什么HttpURLConneciton只是一个抽象类,自身不能被实例化的原因。HttpURLConnection只能通过URL.openConnection()方法创建具体的实例。
这里请求头的话有Get 、Post,
GET请求和POST请求详述_bear*6的博客-CSDN博客_get请求和post的用法
GET 请求和 POST 请求的区别与使用示例 - 隔壁汪书 - 博客园
爬虫在setRequestProperty传入的:
User-Agent(用户代理)是什么_睿科知识云的博客-CSDN博客_user-agent
正则:
正则表达式中关于 \ 的用法,例如\. \(_懶好人vest的博客-CSDN博客_正则表达式\
正则 ?= 用法_风神修罗使的博客-CSDN博客_?= 正则
正则表达式中?=和?:和?!的理解_这个昵称没有被占用吧的博客-CSDN博客_正则表达式?!
接口和实现类
接口 对象 = new 实现类 与 实现类 对象= new 实现类_代码敲上天.的博客-CSDN博客_new 实现类
Set set=new HashSet();的意义是什么呢_谜的博客的博客-CSDN博客
Collection extends E>解释:
1.实现了Collection接口
2.类型一定是E的子类
?是“任意类”的意思,extends继承不多说,E是指定类型,是泛型;
通常出现在将一个集合赋值给另一个集合的情景中,
如:public LinkedList(Collection extends E> c )、addAll(Collection extends E> c);
addAll方法——向Set集合添加另一个集合的所有内容_xk_一步一步来的博客-CSDN博客_addall方法
- public class UrlCrawBoke {
-
- static String userId = "";
-
- public static void main(String urlstr[]) throws IOException, InterruptedException {
-
- //set是接口,hashset是它的实现类
- //接口 对象 = new 实现类,见笔记,主要是为了实现多态,虽然这里不需要多态,但是这是良好的代码习惯
- Set urls = new HashSet();
-
- // ----------------------------------------------遍历每一页 获取文章链接----------------------------------------------
- //该引用为常量,该值无法修改
- final String homeUrl = "https://blog.csdn.net/" + userId + "/article/list/";// 后面加pageNum即可
- //统计页数
- int totalPage = 0;
- //接受从网页爬取的内容
- InputStream is;
- //把网页内容转为string
- String pageStr;
- //网站地址索引
- StringBuilder curUrl = null;
-
- for (int i = 1; i < 50; i++) {
- //暂停1秒
- Thread.sleep(1000);
- //找页数,如果写的文章多,那就有两页三页......
- System.out.println("finding page " + i);
- //初始化网站地址索引
- curUrl = new StringBuilder(homeUrl);
- //完善地址,加上页码
- curUrl.append(i);
- System.out.println(curUrl);
- //爬取网站内容
- is = doGet(curUrl.toString());
- //转成string
- pageStr = inputStreamToString(is, "UTF-8");// 一整页的html源码
- //正则表达式,这里是来获取每一篇博客的网址,按照规律来,detaiLs后面会跟8-9个数字,
- //又因为在博客目录下,要访问具体博客,我们鼠标点的是图标文字,但是实际上点的是超链接,也就是这个网页的静态资源里面html文本中必然是有href
- //所以(?<=href=\")表示匹配以href="开头的字符串,并且捕获(存储)到分组中,\"写在正则里面就是表示",\是引用符
- //而最后面的(?=\")表示匹配以"结尾的字符串,并且捕获(存储)到分组中,这样就把具体博客的网址拿下来了
- List list = getMatherSubstrs(pageStr, "(?<=href=\")https://blog.csdn.net/" + userId + "/article/details/[0-9]{8,9}(?=\")");
- //把网址加进去
- /*这里的addall,有点东西的
- 首先首先,集合collection是最上层滴接口
- 然后set是collection的子接口
- 再然后Hashset是set其中一个实现类
- 然后按道理应该addall方法要在hashset中实现
- 但是呢,hashset不仅实现set还继承了abstractset这个抽象类
- 然后abstractset这个抽象类继承AbstractCollection(当然也实现了set)
- 所以最后最后呢,addall这个玩意是在AbstractCollection这个抽象类里面实现的,这也是为什么我们查找实现查到AbstractCollection去了
- */
- //addall就是把list的内容全部添加到urls里去
- urls.addAll(list);
- //总页数
- totalPage = i;
- //如果pagestr里面没有空空如也这四个字,那就返回-1,至于空空如也是因为csdn里面如果没有博客那就会出现这里空空如也
- //但是这网页有时候也脑抽的,不一定每次都吃
- if (pageStr.lastIndexOf("空空如也") != -1) {
- System.out.println("已经到最后一页!");
- break;
- } else {
- System.out.println("Success~");
- }
-
- }
- System.out.println("总页数为: " + totalPage);
-
- // ---------------------------------------------------打印每个链接---------------------------------------------------
- System.out.println("打印每个链接");
- for (Object s:urls) {
- System.out.println(s);
- }
- System.out.println("打印每个链接完毕");
-
- // ---------------------------------------------------访问每个链接---------------------------------------------------
- int i=0;
- for (Object s:urls) {
- //传入网址进行访问
- doGet(s.toString());
- System.out.println("成功访问第" + (++i) + "个链接,共" + urls.size() + "个:" + s);
- }
-
- // ---------------------------------------------------程序结束---------------------------------------------------
- System.out.println("运行完毕,成功增加访问数:" + urls.size());
- }
-
- public static InputStream doGet(String urlstr) throws IOException {
- //初始化URL
- URL url = new URL(urlstr);
- //打开URL链接,获得HttpURLConnection对象,下面的括号转化是有原理的,看看笔记
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- //对链接进行设置(设置请求头或响应头)
- //setRequestProperty(key,value),后面只能跟一个value
- //setRequestProperty会覆盖已经存在的key的所有values,有清零重新赋值的作用
- //User-Agent(用户代理),详情看笔记
- conn.setRequestProperty("User-Agent",
- "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
- //建立HttpURLConnection链接
- conn.connect();
- //读取网页内容(字符串流)(请求)(实际上也会隐式调用connect())
- InputStream inputStream = conn.getInputStream();
- //返回
- return inputStream;
- }
-
- //charset代表的是编码
- public static String inputStreamToString(InputStream is, String charset) throws IOException {
- //缓冲区
- byte[] bytes = new byte[1024];
- //长度
- int byteLength = 0;
- StringBuffer sb = new StringBuffer();
- //常见的读取操作
- while ((byteLength = is.read(bytes)) != -1) {
- //函数里面长度可以不写
- //这个string()源码很有意思,虽然看起来吃力,但是值得一看
- sb.append(new String(bytes, 0, byteLength, charset));
- }
- return sb.toString();
- }
-
- // 正则匹配
- public static List getMatherSubstrs(String str, String regex) {
- //获取链表
- List list = new ArrayList();
- //获取正则表达式对象
- Pattern p = Pattern.compile(regex);
- //获取文本匹配器m,拿着m,按p的规则去匹配str
- Matcher m = p.matcher(str);
- while (m.find()) {
- //循环获取
- list.add(m.group());
- }
- return list;
- }
- }