持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情
之前遇到有人问我会不会爬虫,好家伙啊,我真不会,然后就开始叽里咕噜捣鼓一下,发现URLConnection 就可以实现 “获取互联网上的数据” 这一功能。
URLConnection类概述
抽象类 URLConnection 是所有类的超类,它代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源。URLConnection 基于Http协议。通常,创建一个到 URL 的连接需要几个步骤:
- 通过在 URL 上调用 openConnection 方法创建连接对象。
- 处理设置参数和一般请求属性。
- 使用 connect 方法建立到远程对象的实际连接。
- 远程对象变为可用。远程对象的头字段和内容变为可访问。
普通开发者要如何搜集海量数据呢?
在大数据时代,获得数据,最常用方法就是爬虫了,从互联网中爬取数据,典型的代表就是百度、谷歌等搜索引擎了。
在实际做爬虫开发时,通常会使用 HttpClient 、 JSoup 或 WebMagic 等框架进行实现。
但由于我目前所学的知识有限,因此这里使用API 模拟实现一个简单爬虫的功能。
注意:爬虫可以将网络上的资源作为己用,但是那些资源的拥有者是否允许开发者爬取他们的数据呢?
因此在使用爬虫时,稍有不慎,就可能面临法律纠纷,大家在使用爬虫时务必要注意法律问题。
以下列举的一些禁止爬取的场景,但由于非法律专业人员,以下列举场景仅供大家参考,爬虫的禁止场景并不限于此。
在实际工作中,如果有涉及爬虫开发的地方,建议大家务必咨询一下公司的法务人员或者相关法律人士。
- 不要大规模的爬取网络数据,或对对方的服务器造成较大影响。
- 不要将爬虫用于灰色产业、敏感行业,或使用爬虫非法获利。
- 不要使用爬虫获取网站或用户的隐私数据。
- 不要违背 robots 协议或经营者意志。
- 不要使用爬虫进行任何法律、法规或道德禁止的行为。
使用爬虫爬数据
从技术体系而言,爬虫可以分为三个部分:获取海量数据、解析数据和存储数据。
实验:爬取网站html源码
第一步:创建字符串缓冲区,存放爬取的数据 StringBuffer html = new StringBuffer();
第二步:创建 URL 对象 URL url = new URL("网址");
第三步:通过 URL 对象获取 URLConnection 对象 URLConnection urlConnection = url.openConnection();
第四步:建立连接 urlConnection.connect();
第五步:通过 IO 流提取数据信息 BufferedReader reader = null;
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
第六步:把数据存储到缓冲区
String line = null;
while ((line = reader.readLine()) != null) { html.append(line); }
这是掘金home页的html源码:
这个是具体代码:
package 网络编程;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
/**
* 爬虫获取海量数据
*/
public class TestCrawler {
//获取首页的html源码
public static String getResource() {
BufferedReader reader = null;
// 创建字符串缓冲区,存放爬取的数据
StringBuffer html = new StringBuffer();
try {
// 创建 URL 对象
URL url = new URL("https://juejin.cn/creator/home");
// 通过 URL 对象获取 URLConnection 对象
URLConnection urlConnection = url.openConnection();
// 建立连接
urlConnection.connect();
// 通过 IO 流提取数据信息
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
html.append(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 流资源释放
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return html.toString();
}
public static void main(String[] args) {
String html = getResource();
System.out.println("首页的源码如下所示:\n"+html);
}
}
看到上面结果是不是有点蒙
下面就是解析
作为简单的模拟爬虫,我们实现从源码中解析出网站标题,即上述 <meta> 标签中的 content 值。
🤔 那么如何解析呢?
我们知道,源码其实就是字符串,因此完全可以用字符串解析的相关方法进行解析。
假设现在要在 A 字符串中,查找是否含有 B 内容,就可以通过以下形式进行匹配查询:
Pattern pattern = Pattern.compile(A);
Matcher matcher = pattern.matcher(B);
之后再结合 matcher.find() 方法进行正则匹配,如果 matcher.find() 的返回值是 true,就说明 A 中存在符合条件的 B,否则说明不存在。
在爬虫下面添加一个方法
这里我们使用正则表达式来进行匹配
第一步:(.+?) :表示匹配一次符合条件的值,即从网站首页的源码中,寻找以下内容: <meta data-n-head="ssr" data-hid="description" name="description" content=
代码:Pattern pattern = Pattern.compile("meta data-n-head="ssr" data-hid="description" name="description" content="(.+?)"");
第二步:然后开始提取符合pattern约束的字符串
Matcher matcher = pattern.matcher(html);
第三步:提取出全部符合条件的值,即提取出标签中的content属性值并存储
String result = null;
第四步:判断是否存在 符合约束的字符串
if (matcher.find()) {
第五步:提取出全部符合条件的值,即提取出标签中的content属性值
result = matcher.group(0); result = result.substring(result.indexOf("content=") + "content=".length());
修改后代码如下:
package 网络编程;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 爬虫获取海量数据
*/
public class jiexijieguo {
//获取掘金首页的html源码
public static String getResource() {
BufferedReader reader = null;
// 创建字符串缓冲区,存放爬取的数据
StringBuffer html = new StringBuffer();
try {
// 创建 URL 对象
URL url = new URL("https://juejin.cn/creator/home");
// 通过 URL 对象获取 URLConnection 对象
URLConnection urlConnection = url.openConnection();
// 建立连接
urlConnection.connect();
// 通过 IO 流提取数据信息
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
html.append(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 流资源释放
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return html.toString();
}
// 从首页的源码中解析特定的数据
public static String parseResource(String html) {
/*
(.+?) :表示匹配一次符合条件的值,即从源码中,寻找以下内容:
<meta data-n-head="ssr" vmid="description" name="description" content="掘金是一...">
*/
Pattern pattern = Pattern.compile("meta data-n-head="ssr" vmid="description" name="description" content="(.+?)"");
//提取符合pattern约束的字符串
Matcher matcher = pattern.matcher(html);
String result = null;
//判断是否存在 符合约束的字符串
if (matcher.find()) {
//提取出全部符合条件的值,即提取出<meta>标签中的content属性值
result = matcher.group(0);
result = result.substring(result.indexOf("content=") + "content=".length());
}
return result;
}
public static void main(String[] args) {
String html = getResource();
// System.out.println("首页的源码如下所示:\n"+html);
String result = parseResource(html);
System.out.println(result == null ? "爬取失败" : "viewport 的 content 值是:" + result);
}
}
如果匹配失败,注意看看
Pattern pattern = Pattern.compile(A);
Matcher matcher = pattern.matcher(B); 这里的ab是不是正确 a是在html源码里面的部分,对应xx=“xxx”名字,参数要对应
b的参数,就是我们爬取的数据集合