本章内容为一个实战项目,主要的实战方向为使用Javad的
WebMagic
爬虫框架来爬取LOL的英雄资料和一些图片。本章节需要学习的小伙伴们具备一些初步的JavaSE知识,以及最好能对Maven进行使用。
如果你还不知道
Maven
是什么,以及不知道如何创建一个Maven
项目的话,请移步:Maven教程传送门那么我们就开始吧!
文章目录
1.什么是爬虫?
爬虫是指使用代码模拟用户批量发送网络请求,批量获取数据的行为。
通俗点来来讲,爬虫就是一个探测机器,它的基本操作就是模拟人的行为去各个网站溜达,点点按钮,查查数据,或者把看到的信息背回来。就像一只虫子在一幢楼里不知疲倦地爬来爬去。
我们见到的最常见的爬虫就是比如
百度、谷歌..
之类的搜索引擎
1.1爬虫亦有善恶
我们知道互联网也是一个江湖,在这个大江湖之中,爬虫也是区分善恶的(当然这只是一个概念)。
其实说白了呢就是看使用者如何去使用它。
- 像谷歌这样的搜索引擎爬虫,每隔几天对全网的网页扫一遍,供大家查阅,各个被扫的网站大都很开心。这种就被定义为「善意爬虫」。
- 但是,像抢票软件这样的爬虫,对着 12306 每秒钟恨不得撸几万次。铁总并不觉得很开心。这种就被定义为「恶意爬虫」。(注意,抢票的你觉得开心没用,被扫描的网站觉得不开心,它就是恶意的。)
- 为什么说12306不开心呢,因为在20年前的一份数据表明
12306最高峰时 1 天内页面浏览量达 813.4 亿次,1 小时最高点击量 59.3 亿次,平均每秒 164.8 万次
。相信如果被这样捕捉的服务器是你的服务器,你也不会开心的。
- 为什么说12306不开心呢,因为在20年前的一份数据表明
1.2.爬虫的本质
实质上爬虫的本质就是模拟人为打开浏览器,然后去获取页面上的信息。
只不过这种人为的动作被我们的代码所代替。
1.3.爬虫的基本流程
对于初学者入门来说,其实爬虫的基本流程主要在四步
1.请求目标链接 -> 2.获取响应内容 -> 3.解析内容 -> 4.存储数据
- 请求目标链接:发起一个带有header、请求参数等信息的Request,等待服务器响应
- 获取服务器响应内容:服务器正常响应后,Response的内容即包含所有页面内容(可以是HTML、JSON字符串、二进制数据(图片、视频)等等)
- 解析内容:将得到的内容进行解析,HTML解析、JSON解析、二进制流解析等等
- 存储数据:存储形式多样,可以存为文本,也可以存储到数据库,或者存为特定格式的文件
2.WebMagic
一般来说爬虫只是一种技术,其实任何语言都是可以实现爬虫的,区分为简单与复杂。
我们所知道的市面上比较常见的爬虫就是
Python或者Go
比较多但是实际上在
Java
中也是可以完成爬虫这一操作,并且有一个相对而言比较成熟的框架就是WebMagic
今天我们就用这个框架来实战一下如何爬取
英雄联盟
的英雄信息与图片。
2.1.框架概述
WebMagic的设计参考了业界最优秀的爬虫Scrapy,而实现则应用了HttpClient、Jsoup等Java世界最成熟的工具,目标就是做一个Java语言Web爬虫的教科书般的实现
2.2.设计架构
WebMagic的结构分为
Downloader
、PageProcessor
、Scheduler
、Pipeline
四大组件,并由Spider将它们彼此组织起来。这四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。
可以依据架构图我们看到整个执行流程大概为
1.发起一个HTTP请求
2.将这个HTTP内容下载下来(Downloader)
3.将内容交给PageProcesser进行处理(框架的处理核心)
4.1.处理内容后,可以再次发起请求
4.2.处理的结果可以交给
Pipeline
来进行最后的收尾工作(比如存到数据库、或者保存为文件等等)
更详细的内容可以直接查看官方的文档说明,这里就不一一赘述了。🚪 官方传送门
3.项目实战(初窥篇)
3.1.准备工作
直接添加WebMagic相关的框架依赖。
直接复制进pom.xml文件中即可
<dependencies>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>0.7.3</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>0.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- hutool工具jar包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.9</version>
</dependency>
</dependencies>
3.2.工具介绍(hutool)
这是一个包含各大常用工具方法的Java工具包。
里面具有丰富的工具资源,可以让你省下不少写一些通用方法的时间。
Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug
官方传送门:Hutool官方地址
可以在官方地址中查看对应的文档信息。
这次主要我们要用到Hutool工具中对
文件、请求
的处理的工具!
🎁Hutool名称的由来
Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu”是公司名称的表示,tool表示工具。Hutool谐音“糊涂”,一方面简洁易懂,一方面寓意“难得糊涂”。
3.3.初窥门径
我们进行爬虫的第一步就是先明确的我们的需求。
首先我们应当想办法找到
LOL
英雄资料的页面(URL),然后我们才开始解析我们的页面。
学会解析页面
首先我们要鼠标右键
查看网页源代码
由此我们可以发现我们的页面数据不过是寥寥几十行,并没有我们所需要的英雄数据信息,说明当前网站的页面信息并不是静态的。而是动态的(这里需要大家对HTTP请求有一定的基础知识)
因为数据是动态的所以我们需要去查看当前页面的请求链接去分析和寻找(这里需要耐心一点)
打开官网地址我们需要按下
F12
然后选择Network
刷新一下来查看当前网页的数据源是怎么展示在页面上的请求链接,我们可以发现一个比较可疑的链接
hero_list.js
从名字来看是英雄列表的意思,只要你点进去查看返回结果可以发现这个就是我们想要的信息。
由此分析我们就得到了当前英雄信息的数据源,我们接下来要做的就是去处理这个数据。
我们得到了我们要请求的路径为:https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js?ts=2780729
3.4.利用WebMagic处理请求
得到我们的需要的数据源之后,我们就要学会利用我们的爬虫来往数据源里面进行爬取数据。
对于数据的处理我们是通过自定义
PageProcessor
来完成的,所以我们需要创建一个类来实现这个接口。并且重写我们的
process()
核心函数,改为我们要做的事情。
简单梳理一下我们要做的事情
- 判断请求路径是否与我们的目标路径一致
- 路径如果一致则获取文件中的
json
数据转换成Java对象 - 将处理好变成Java对象的数据存到
page
对象中等待Pipeline
的处理 Pipeline
对象在接收到处理好传递过来的数据的时候,进行收尾工作,可以选择保存文件、输出在控制台
等等
博主在代码中也对内容步骤进行了注释,可以进行参考查看。
核心处理代码
import cn.dengsz.common.Constants;
import cn.dengsz.common.model.HeroInfo;
import cn.dengsz.common.model.HeroSkin;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;
import java.util.List;
import java.util.stream.Collectors;
/\*\*
\* @author Deng's
\* 去获取页面的进程
\*/
public class HerosListPageProcessor implements PageProcessor {
/\*\*
\* 核心程序部分
\*/
@Override
public void process(Page page) {
// 处理英雄列表信息
if (page.getUrl().get().equals(Constants.HERO\_URL)) {
// 获取页面内容
String jsonResult = page.getJson().toString();
// 利用fastjson解析json内容(根据返回内容决定获取key:hero的内容)
JSONObject jsonObject = JSONObject.parseObject(jsonResult);
// 将内容转换成数组
JSONArray heros = jsonObject.getJSONArray(Constants.HERO\_KEY);
// 版本信息、更新时间
String version = jsonObject.getString(Constants.VERSION);
String updateFileTime = jsonObject.getString(Constants.UPDATE\_TIME);
// 获取到数据数组 判断数组内容是否为null
if (heros.size() == 0) {
return;
}
// 将处理好的信息存入Pipeline中
List<HeroInfo> heroInfoList = heros.toJavaList(HeroInfo.class);
page.putField(Constants.HERO\_KEY, heroInfoList);
page.putField(Constants.VERSION, version);
page.putField(Constants.UPDATE\_TIME, updateFileTime);
}
}
@Override
public Site getSite() {
// 设置相关的请求头信息,防止反爬虫或者无效访问被拒绝
return Site.me().setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10\_15\_7) AppleWebKit/" +
"537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
.addHeader("accept-encoding", "gzip, deflate, br")
.addHeader("accept-language", "zh-CN,zh;q=0.9,en;q=0.8")
.addHeader("origin", "https://101.qq.com")
.setCharset("utf-8")
.setRetryTimes(3).setSleepTime(1000);
}
}
英雄信息的对象模型
import lombok.Data;
/\*\*
\* @author Deng's
\* 仅仅获取一些有用的相关数据 保存下来。
\*/
@Data
public class HeroInfo {
/\*\*
\* 英雄id
\*/
private String heroId;
/\*\*
\* 中文名
\*/
private String name;
/\*\*
\* 别名
\*/
private String alias;
/\*\*
\* 信息标题
\*/
private String title;
/\*\*
\* 金币售价
\*/
private String goldPrice;
/\*\*
\* 点券售价
\*/
private String couponPrice;
/\*\*
\* 一些关键信息
\*/
private String keywords;
}
一些固定的常量
写一些常量方便之后需要改动的时候进行全局直接生效。
比如
文件存储位置、初始访问链接、固定常量名
等等
/\*\*
\* @author Deng's
\* 一些解析数据的常量
\*/
public class Constants {
public static final String HERO\_KEY = "hero";
public static final String VERSION = "version";
public static final String UPDATE\_TIME = "fileTime";
public static final String PIC\_URL = "https://game.gtimg.cn/images/lol/act/img/js/hero/";
public static final String HERO\_URL = "https://game.gtimg.cn/images/lol/act/img/js/heroList/hero\_list.js?ts=2780565";
/\*\*
\* 预设一些文件存储地址
\* 英雄信息文件、英雄图片文件存储路径(默认桌面)
\*/
public static final String HERO\_INFO\_FILE = "/Users/dengs/Desktop/lol-skins/hero.json";
public static final String HERO\_PIC\_FILE = "/Users/dengs/Desktop/lol-skins/";
}
核心的自定义Pipeline类
本教程将英雄数据存储为本地的
json
文件,存储地址可以去改动Constants
类中的HERO_INFO_FILE
常量值来改变。
import cn.dengsz.common.Constants;
import cn.dengsz.common.model.HeroInfo;
import cn.dengsz.common.model.HeroSkin;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
/\*\*
\* @author Deng's
\* 处理由pageProcessor处理好后 塞过来的英雄数据(当然你可以在这里改造成存入数据库)
\*/
@Slf4j
public class LolHeroPipeline implements Pipeline {
@Override
public void process(ResultItems resultItems, Task task) {
// 判断当前请求路径是什么 再决定做什么事情
if (resultItems.getRequest().getUrl().equals(Constants.HERO\_URL)) {
// 根据Processor传递过来参数做下一步处理
List<HeroInfo> heroInfoList = resultItems.get(Constants.HERO\_KEY);
// 利用hutool可以将内容快速输出成文件
try {
//Constants.HERO\_INFO\_FILE 为文件输出的地址
FileWriter fileWriter = new FileWriter(Constants.HERO\_INFO\_FILE);
fileWriter.write(JSONObject.toJSONString(heroInfoList));
fileWriter.close();
} catch (IOException e) {
log.error("写出英雄信息出现问题,请查看:{}", e.getMessage());
throw new RuntimeException(e);
}
}
}
}
最后放上这个项目的启动类
import cn.dengsz.common.Constants;
import cn.dengsz.core.HerosListPageProcessor;
import cn.dengsz.core.LolHeroPipeline;
import us.codecraft.webmagic.Spider;
### 一、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
![](https://img-blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)
### 二、学习软件
工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
![](https://img-blog.csdnimg.cn/img_convert/8c4513c1a906b72cbf93031e6781512b.png)
### 三、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
![](https://img-blog.csdnimg.cn/afc935d834c5452090670f48eda180e0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP5aqb56eD56eD,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里无偿获取](https://bbs.csdn.net/topics/618317507)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
![](https://img-blog.csdnimg.cn/img_convert/8c4513c1a906b72cbf93031e6781512b.png)
### 三、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
![](https://img-blog.csdnimg.cn/afc935d834c5452090670f48eda180e0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP5aqb56eD56eD,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里无偿获取](https://bbs.csdn.net/topics/618317507)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**