java爬虫抓取网页数据(什么是网络爬虫从功能上来讲架构的四大组件)
优采云 发布时间: 2022-01-16 08:08java爬虫抓取网页数据(什么是网络爬虫从功能上来讲架构的四大组件)
什么是网络爬虫
从功能上来说,爬虫一般分为数据采集、处理、存储三部分。爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在抓取网页的过程中,它不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。
网络爬虫常用技术的底层实现是HttpClient + Jsoup
HttpClient 是 Apache Jakarta Common 下的一个子项目,用于提供高效、最新、功能丰富的支持 HTTP 协议的客户端编程工具包,支持最新版本和推荐的 HTTP 协议。HttpClient 已经在很多项目中使用,比如 Cactus 和 HTMLUnit,Apache Jakarta 上另外两个知名的开源项目,都使用了 HttpClient。关注了解更多信息。
Jsoup是一个Java HTML解析器,可以直接解析一个URL地址和HTML文本内容。它提供了一个非常省力的 API,用于通过 DOM、CSS 和类似 jQuery 的操作方法获取和操作数据。
HttpClient用于下载网页源代码,Jsoup用于从网页源代码中解析出需要的内容。
Webmagic 框架
webmagic 是一个开源的 Java 爬虫框架,其目标是简化爬虫开发过程,让开发者专注于逻辑功能的开发。webmagic的核心很简单,但是涵盖了爬虫的*敏*感*词*,也是学习爬虫开发的好资料。
爬虫框架Webmagic介绍架构的四大组件
WebMagic 的结构分为四大组件:Downloader、PageProcessor、Scheduler 和 Pipeline,它们由 Spider 组织。这四个组件分别对应了爬虫生命周期中的下载、处理、管理和持久化的功能。Spider 组织这些组件,以便它们可以相互交互并处理执行。可以认为Spider是一个大容器,也是WebMagic逻辑的核心。
简单说明:Downloader负责爬取网页的源码,PageProcesser指定爬取的规则(即指定要爬取什么内容),然后交给Pipeline来存储爬取的内容,并交给用于管理的Scheduler URL,防止Downloader再次爬取该页面,防止爬取重复内容。
PageProcessor 爬取页面的全部内容
需求:编写爬虫程序,爬取csdn中博客的内容
1)引入依赖
us.codecraft
webmagic-core
0.7.3
us.codecraft
webmagic-extension
0.7.3
2)编写类来抓取网页内容
public class MyProcessor implements PageProcessor {
public void process(Page page) {
// 将爬取的网页源代码输出到控制台
System.out.println(page.getHtml().toString());
}
public Site getSite() {
return Site.me().setSleepTime(100).setRetryTimes(3);
}
public static void main(String[] args) {
Spider.create(new MyProcessor())
.addUrl("https://blog.csdn.net/")
.run();
}
}
Spider 是爬虫启动的入口点。在启动爬虫之前,我们需要使用 PageProcessor 创建一个 Spider 对象,然后使用 run() 来启动它。
蜘蛛的一些方法:
同时可以通过set方法设置Spider的其他组件(Downloader、Scheduler、Pipeline)。
Page 代表从 Downloader 下载的页面 - 它可能是 HTML、JSON 或其他文本内容。页面是WebMagic抽取过程的核心对象,它提供了一些抽取、结果保存等方法。
Site用于定义站点本身的一些配置信息,如编码、HTTP头、超时、重试策略等,代理等,可以通过设置Site对象来配置。
网站的一些方法:
爬取指定内容(Xpath)
如果我们要爬取网页的部分内容,需要指定xpath。XPath,即 XML 路径语言 (XMLPathLanguage),是一种用于确定 XML 文档的某个部分的位置的语言。XPath 使用路径表达式来选择 XML 文档中的节点或节点集。这些路径表达式与我们在常规计算机文件系统中看到的表达式非常相似。
我们通过指定 xpath 来抓取网页的一部分:
System.out.println(page.getHtml().xpath("//*[@id=\"mainBox\"]/main/div[1]/div/div/div[1]/h1").toString());
获取xpath的简单方法:打开网页,按F12
添加目标地址
我们可以通过添加目标地址从*敏*感*词*页面爬取更多页面:
目标地址正则表达式
有时我们只需要将当前页面中符合要求的链接添加到目标页面即可。这时候,我们可以使用正则表达式来过滤链接:
// 添加目标地址,从一个页面爬到另一个页面
page.addTargetRequests(page.getHtml().links().regex("https://blog.csdn.net/[a-z 0-9 _]+/article/details/[0-9]{8}").all());
System.out.println(page.getHtml().xpath("//*[@id=\"mainBox\"]/main/div[1]/div/div/div[1]/h1").toString());
管道控制台管道控制台输出
将处理结果输出到控制台
FilePipeline 文件保存
另存为 json
自定义管道
一般我们需要把爬取的数据放到数据库中,这个时候我们可以自定义Pipeline
创建一个实现 Pipeline 接口的类:
修改主方法:
调度器
我们刚刚完成的功能,每次运行可能会爬取重复页面,这是没有意义的。Scheduler(URL管理)最基本的功能就是对已经爬取的URL进行标记。可以实现 URL 的增量重复数据删除。
目前scheduler的实现主要有3种:
内存队列
使用 setScheduler 设置调度器:
文件队列
使用文件保存爬取的URL,在关闭程序下一次开始时,可以从之前获取的URL继续爬取
但是,要使用这种方法,首先要保证文件目录存在,所以先创建一个文件存放目录:
运行后文件夹E:\scheduler会生成两个文件.urls.txt和.cursor.txt
Redis 队列
使用Redis保存抓取队列,可用于多台机器同时协同抓取
首先运行redis服务器
示例(爬取csdn博客的用户昵称和头像)
1)引入依赖
2)创建配置文件
server:
port: 9014
spring:
application:
name: tensquare-article-crawler #指定服务名
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.227.129:3306/tensquare_article?characterEncoding=UTF8
username: root
password: 123456
jpa:
database: MySQL
show-sql: true
redis:
host: 192.168.227.129
3)创建一个启动类
@SpringBootApplication
public class ArticleCrawlerApplication {
public static void main(String[] args) {
SpringApplication.run(ArticleCrawlerApplication.class);
}
@Value("${spring.redis.host}")
private String redis_host;
@Bean
public IdWorker idWorker(){
return new IdWorker(1,1);
}
@Bean
public RedisScheduler redisScheduler(){
return new RedisScheduler(redis_host);
}
}
4)创建爬虫类
打开网页,按F12,找到头像和昵称
如上图:头像是标签中的一个属性,如何获取呢?
@Component
public class UserProcessor implements PageProcessor {
@Override
public void process(Page page) {
// 添加目标地址,从一个页面爬到另一个页面
page.addTargetRequests(page.getHtml().links().regex("https://blog.csdn.net/[a-z 0-9 _]+/article/details/[0-9]{8}").all());
// 添加字段,代码结构化,可多次使用
String nickName = page.getHtml().xpath("//*[@id=\"uid\"]/text()").get();
String image = page.getHtml().xpath("//*[@id=\"asideProfile\"]/div[1]/div[1]/a/img[1]/@src").get();
if (nickName != null && image != null){
page.putField("nickName",nickName);
page.putField("image",image);
} else {
// 不执行后面的步骤
page.setSkip(true);
}
}
@Override
public Site getSite() {
return Site.me().setSleepTime(100).setRetryTimes(3);
}
}
只需在对应的 xpath 路径后添加 /@property 名称即可
我们拿到头像的存储地址后,需要下载到本地,然后上传到我们自己的图片服务器,所以我们还需要一个下载工具类
package util;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
/**
* 下载工具类
*/
public class DownloadUtil {
public static void download(String urlStr,String filename,String savePath) throws IOException {
URL url = new URL(urlStr);
//打开url连接
URLConnection connection = url.openConnection();
//请求超时时间
connection.setConnectTimeout(5000);
//输入流
InputStream in = connection.getInputStream();
//缓冲数据
byte [] bytes = new byte[1024];
//数据长度
int len;
//文件
File file = new File(savePath);
if(!file.exists())
file.mkdirs();
OutputStream out = new FileOutputStream(file.getPath()+"\\"+filename);
//先读到bytes中
while ((len=in.read(bytes))!=-1){
//再从bytes中写入文件
out.write(bytes,0,len);
}
//关闭IO
out.close();
in.close();
}
}
5)创建存储类
@Component
public class UserPipeline implements Pipeline {
@Autowired
private IdWorker idWorker;
@Autowired
private UserDao userDao;
@Override
public void process(ResultItems resultItems, Task task) {
String nickName = resultItems.get("nickName");
String image = resultItems.get("image");
String imageName = image.substring(image.lastIndexOf("/") + 1) + ".jpg";
User user = new User();
user.setId(idWorker.nextId()+"");
user.setAvatar(imageName);
user.setNickname(nickName);
// 将用户存入数据库
userDao.save(user);
// 将图片下载下载
try {
DownloadUtil.download(image,imageName,"E:/tensquare/userimage");
} catch (IOException e) {
e.printStackTrace();
}
}
}
6)创建任务类
@Component
public class UserTask {
@Autowired
private UserProcessor userProcessor;
@Autowired
private UserPipeline userPipeline;
@Autowired
private RedisScheduler redisScheduler;
@Scheduled(cron = "0 57 22 * * ?")
public void UserTask(){
Spider spider = Spider.create(userProcessor);
spider.addUrl("https://blog.csdn.net/");
spider.addPipeline(userPipeline);
spider.setScheduler(redisScheduler);
spider.start();
}
}
7)为启动类添加注解
8)运行这个模块,数据会在指定时间自动爬取