本人最近在学习爬虫的相关知识,对于很多基本的概念在此做一个梳理,便于课程的复习和巩固,如有写的不准确或错误的地方,欢迎阅读者批评指正。
要聊爬虫主要是从以下几个方面为主线:
- 什么是爬虫?
- 爬虫的价值
- 爬虫的分类
- 爬虫的基本运行原理
- 爬虫的三大模块
- 爬虫协议
1.什么是爬虫?
想到爬虫,很多人的第一印象就是现实世界中到处爬着找食物的虫子,其实在计算机的世界里亦是如此:所谓的爬虫就是程序员写好的一段程序代码,而它们想要找的食物就是存在于互联网上的形形色色的各种数据,但是有一点需要注意的是这些爬虫都是按照它们的缔造者的意图即一定的规则自动爬取数据,然后存储起来加以利用。
2.爬虫的价值
爬虫的价值其实就是数据的价值,在万物互联的互联网社会数据是无价之宝,一切皆为数据,谁拥有了大量有用的数据,谁就拥有了决策的主动权,试想如果电商公司拥有了大量的数据,就可以根据年龄段等做精准的广告推荐,同时还可以做竞品分析等等。
3.爬虫的分类
3.1 通用型的爬虫
通用型爬虫是用来获取互联网当中所有的数据的, 代表性巨无霸爬虫: 百度,谷歌,必应(不知道算不?)等 。
3.2 垂直爬虫
垂直爬虫,有的资料上也称之为聚焦爬虫,主要用来获取某个行业, 某个分类, 某个网站下的某些数据,具有明显的针对性和目的性。在我们实际开发过程中, 大部分同学可能接触到的是垂直爬虫, 做数据的局部爬取,而通用型爬虫的研发和成本太高,一般中小型公司不会轻易去做。
4.爬虫的基本运行原理
爬虫的基本运行原理共分为四步:
1)首先指定爬虫要获取的url;
2)然后根据对应的url去网上爬取对应的数据;
3)初始爬取到的数据多为html或json格式的,故需要进行数据的解析;
4)解析后的数据即是整理好的数据,保存到容器中(MySQL,原生JDBC,MyBatis,DbcpUtils,Spring-jdbc等)。
5.爬虫的三大模块
根据爬虫的基本运行原理不难得到爬虫的三大模块:获取数据,解析数据,保存数据。
5.1 模块一:获取数据
获取数据可以使用原生的JDK(GET/POST),但是这样做既费时又费力,因此我们选择使用Apache提供的专为http请求而生的httpClient工具。
使用httpClient之前需要导包:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>版本号自定义</version>
</dependency>
具体的代码逻辑实现在这里不过多体现,仅把核心的几个步骤罗列出来供理清思路:
- 第一步:指定需要获取的url
- 第二步:创建httpClient对象,指定请求的方式(GET/POST)
- 第三步:发送http请求
- 第四步:获取服务器响应的状态码(判断是否请求成功)
- 第五步:获取响应体中需要的数据并保存
- 第六步:关闭httpClient(释放资源)
注:对于httpClient的post请求,我们还可以在发送请求之前封装一些自定义的内容,但是据我的测试后发现,似乎并没有什么卵用,也可能是我没有GET到这个封装参数的意义何在。
5.2 模块二:解析数据
解析数据是爬虫很重要的一个环节,因为获取到的数据(大多数情况下)可能并不是直接整理好的我们需要的格式或部分,因此就很有必要进行解析数据,将获取到的数据归纳整理出我们需要的部分和格式。
解析数据需要使用到的也是Apache提供的名叫Jsoup的工具,专门用来进行网页数据的解析。同样的,在使用Jsoup之情也需要导包:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>版本自定义</version>
</dependency>
Jsoup当中提供了两套API供程序员使用:
第一套: 采用原生DOM解析的方案获取网页中的数据
@Test
public void indexparse() throws IOException {
// 1.获取document对象
Document document = Jsoup.connect("url").get();
// 2.解析网页
// 2.1 获取当前网页的标题内容
String title = document.title();
System.out.println(title);
// 2.2 通过id获取内容
Element element = document.getElementById("epContentLeft");
// 2.3 通过元素标签获取内容
Elements h1Elements = element.getElementsByTag("h1");
System.out.println(h1Elements.size());
Element element1 = h1Elements.get(0);
String text = element1.text();
System.out.println(text);
}
第二套: 采用是类似CSS的选择器的方案获取网页的数据
首先要清楚常用的选择器种类,在这里我仅列举出来几个有代表性的供参考:
- id选择器:(#)
- 类选择器:(.)
- 标签选择器(标签名称)
- 层级选择器(空格 > + , )
- 属性选择器([属性名=属性值])
关于选择器还有很多好用的,由于时间关系,不在此展示,但是在实际的工作当中,要多参考,多尝试不同的选择器,也许会有意想不到的结果。
@Test
public void indexSelectParse() throws IOException {
// 1.获取document对象
Document document = Jsoup.connect("url").get();
// 2.获取网页的标题
Elements elements = document.select("title");
//System.out.println(elements.get(0).text());
System.out.println(elements.text());
// 3.获取内容的标题
// 注:选择器的写法, 一定要按照规范来
Elements htEl = document.select("#epContentLeft h1");
System.out.println(htEl.text());
}
5.3 模块三:保存数据
对于开篇提到的五种(应该还不止)保存数据的方式,根据实际的应用和需求。
需要注意的是:数据库连接池的配置切不可粗心大意,否则会无法正常存入数据,以下是我练习过的一个简单的网页爬虫的案例用到了上述所讲的知识点,留在这里供以后复习:
public class Spider {
/**
* 需求:*****
*/
public static void main(String[] args) throws IOException {
// 1.指定url
String urlStr = "url";
// 2.获取httpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 3.指定请求方式(get)
HttpGet httpGet = new HttpGet(urlStr);
// 4.执行请求, 获取响应对象
CloseableHttpResponse response = httpClient.execute(httpGet);
// 5.获取HTML页面(获取数据)
String html = EntityUtils.toString(response.getEntity(), "utf-8");
// 6.使用jsoup解析网页
// 6.1 获取document对象
Document document = Jsoup.parse(html);
// 6.2 解析document
Elements elements = document.select("div[class=*]");
Elements lis = elements.select("*");
Elements as = lis.select("a[href*=*****.com]");
as = as.select("[class]");
for (Element a : as) {
String bookUrl = a.attr("href");
// 拼接url
bookUrl = "https:" + bookUrl;
httpClient = HttpClients.createDefault();
httpGet = new HttpGet(bookUrl);
response = httpClient.execute(httpGet);
html = EntityUtils.toString(response.getEntity(), "UTF-8");
document = Jsoup.parse(html);
Elements aBtn = document.select("*");
bookUrl = aBtn.attr("href");
while (true) {
// 拼接新的url
bookUrl = "https:" + bookUrl;
System.out.println(bookUrl);
httpClient = HttpClients.createDefault();
httpGet = new HttpGet(bookUrl);
response = httpClient.execute(httpGet);
html = EntityUtils.toString(response.getEntity(), "UTF-8");
document = Jsoup.parse(html);
// 开始解析内容
Elements title = document.select("*");
// ***的名称
System.out.println(title.text());
// ***的内容
Elements ps = document.select("div[*");
for (Element p : ps) {
System.out.println(p.text());
}
Elements aEl = document.select("#j_chapterNext[href*=*****.com]");
// 判断是否继续爬取
if (aEl.size() == 0) {
System.out.println("爬取完毕,结束");
break;
}
bookUrl = aEl.attr("href");
}
}
}
}
6.爬虫协议
事物本没有对与错之分,所谓的对与错不过是每个人心中不同的准绳。爬虫作为一种技术,更像是一把双刃剑,如果利用得当,会给社会创造更大的价值,惠及四方;但若被别有用心的人加以利用,则可能会遭到社会道德的抵制和谴责。因此才有了公认的爬虫原则:
1、搜索技术应服务于人类,同时尊重信息提供者的意愿,并维护其隐私权;
2、网站有义务保护其使用者的个人信息和隐私不被侵犯。
robots协议:百度百科
爬虫协议,也称为Robots协议,其本身是一个文本文件,当爬虫在互联网上爬取数据时首先要访问的就是这个文件,具体的查看方式(以百度为例):https://www.baidu.com/robots.txt,即可看到该网站的爬虫声明,里面的内容主要是声明本网站是否希望被爬虫爬取以及哪些内容可以/不可以被爬取。