项目介绍
项目要求:
使用JAVA制作爬虫,操作API爬取网页的信息,保存到本地。
实现原理
使用Jsoup解析HTML,获取网站源代码,通过解析HTML获取需要的数据,并保存本地。
Maven框架
Maven配置
配置Maven环境
首先要去下载Maven,这里是在Maven的下载地址: Maven – Download Apache Maven,然后解压到你想要的地方,然后打开bin文件夹,复制路径
然后配置环境变量(MAVEN_HOME 和 Path都设置成你安装目录下的bin目录 )。
然后Windows + R 输入 CMD,接着输入 mvn -v
来看看是否配置成功环境变量。
如果输出版本,就说明配置成功。
配置Maven设置
紧接着要开始设置Maven了
首先打开conf文件夹,打开settings.xml
找到 <localRepository>/path/to/local/repo</localRepository>
这句,复制出来,中间的
这句是定义自己想要的Jar包的位置,选择自己想要的位置/path/to/local/repo
然后配置Jar包下载的镜像。找到里面的 <mirror>
标签,然后改为阿里云的镜像
<!--阿里云镜像-->
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
然后保存,Maven设置完成。
IDJA上的Maven设置
打开IDJA ,点击“文件”,进入”新项目设置”。(英文版为: 点击File ,进入Other Settings Of New Project \New Project Settings)
搜索Maven(英文版同理)。
在”用户设置文件“导入之前在Setting.xml的设置,在“本地仓库”选择之前在Setting.xml中设置的Jar的路径,“Maven主路径”选择conf的上一级文件夹。(英文对照: “Maven主路径” : Maven home directopry ,”用户设置文件” : User settings file,”本地仓库” : Local repository)
然后点击”应用”(Apply)。
IDJA 的 Maven 设置成功o(〃^▽^〃)o
Maven目录结构
Maven1//Maven项目名
└─src
├─main
│ ├─java
│ └─resources
└─test
├─java
└─resources
- Windows系统显示文件目录树
在CMD窗口下输入
Tree + [查看目录树的地址]
就可显示了
Maven仓库依赖
点击此链接进入Maven仓库,点击选择需要的API版本,点击在需要的API找到Maven点击即可复制。
CMD编译和运行Maven项目
cmd找到项目的根目录,找到maven项目的根目录,在地址框输入cmd,回车(或者win + R,输入cmd打开cmd窗口然后 cd maven项目路径
),在弹出的cmd窗口中输入 mvn compile
编译。输出 “BUILD SUCCESS”说明编译成功。
我们看到了出现了这样的提示:
是因为编码设置的不正确,这时候要打开项目的pom.xml文件,在<properties>
里加入下面这句
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
然后再运行mvn compile
就不报错啦。
运行Maven项目
写一个JAVA程序
public class Main {
public static void main(String[] args){
System.out.println("Hello,Maven!");
}
}
然后在当前Cmd窗口下输入 mvn exec:java -Dexec.mainClass="PC"
就可以运行在main问减价下的Main类中的Main方法。
mvn exec:java -Dexec.mainClass="PC"
//注意: PC是我自己写的JAVA类名,-Dexec.mainClass会让Maven从项目目录的main文件夹开始
mvn exec:java -Dexec.mainClass=""
编译完成输出结果:
JAVA爬虫
配置到Maven框架,就可以愉快的编写JAVA爬虫了。
环境配置
前提:
IntelliJ IDEA
Maven框架
JDK 1.8
安装需要的Jar包
以下的所有Jar包均可在Maven仓库 https://mvnrepository.com/ 下载
接着要安装Jsoup包,用于解析HTML并查找(均放在<dependencies></dependencies>
标签中 )
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.3</version>
</dependency>
还有SLF4J包,用来记录日志。
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
Commons-io,常用的工具类
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
以及处理字符串的common-lang3
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
配置SLF4J
在resources下创建一个SLF4J配置文件,名为 log4j.properties
写入配置代码:
log4j.rootLogger=DEBUG,A1
log4j.logger.cn.itcast = DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss, SSS} [%t] [%c]-[%p] %m%n
至此Java的环境配置完成。
JAVA爬虫编写
使用 Jsoup 实现爬取文章封面
分析源代码,找出封面位置,是在<div class="cover">
中的<img>
标签的data-src
属性
接下来的操作,将围绕这个<div>
框和里面的<img>
标签展开
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.apache.commons.io.*;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
public class Main {
public static void main(String[] args) throws IOException{
/*获取HTML*/
//String Url = "https://xenolies.xyz/"; //爬取网站2
String Url = "https://xenolies.github.io/";//需要爬取的网站URL
//使用Jsoup.connect()方法链接Url,获取HTML文件
Connection connection = Jsoup.connect(Url);
//设置延时,避免出现Connection reset错误
connection.timeout(3000);
//使用Get(),解析HTML,使用Document来接受返回的信息
Document document = connection.get();
/*使用各种选择器来解析获取获取到的HTML*/
//使用Class选择元素,获取所有名为cover的元素
Elements cover = document.getElementsByClass("cover");
//创建list来保存爬出的图片URL
String[] UrlList = new String[cover.size()];
//for循环持续爬取图片,.size()获取循环次数
for (int Time = 0;Time < cover.size();Time++){
/*从获取的元素中获取数据*/
//获取属性值
//获取cover中的包含<img>标签的第几个<div>(数组排列)
Element div = cover.get(Time);
Elements imgUrl = div.getElementsByTag("img"); //获取到<img标签>
String ImgUrl = imgUrl.attr("data-src");
System.out.println("第" + (Time+1) + "张图片");
UrlList[Time] = ImgUrl; //将单个的图片地址添加进数组
}
String filePath = "C:\\Users\\35367\\Desktop\\Webps" ; //图片保存的位置
for (int i = 0;i < cover.size();i++){ //遍历,下载
File dir = new File(filePath);
//substring()方法来截取字符串,lastIndexOf()来截取最后一个 "/"出现时候的位置(要+1来跳过)
String fileName = UrlList[i].substring(UrlList[i].lastIndexOf("/") + 1,UrlList[i].length());
//File.separator为分隔符,在什么系统使用法对应的分隔符,用于保存
File file = new File(filePath + File.separator + fileName); //输出的路径
Connection connectionIMG = Jsoup.connect(UrlList[i]); //建立新的connection
URL url =new URL(UrlList[i]); //new成为Url以便后面使用
URLConnection ConnectionIMG = url.openConnection();
InputStream in = ConnectionIMG.getInputStream();
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
byte[] buf = new byte[1024];
int len = -1;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
}
}
}
爬取结果:
这样不是很方便整理,所以需要生成个表格。
那就用HSSFWorkBook生成个表格。
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
public class ImageExcel {
public static void main(String[] args) throws IOException{
/*获取HTML*/
//String Url = "https://xenolies.xyz/"; //爬取网站2
String Url = "https://xenolies.github.io/page/2";//需要爬取的网站URL
Connection connection = Jsoup.connect(Url);//使用Jsoup.connect()方法链接Url,获取HTML文件
//connection.timeout(3000); //设置延时,避免出现Connection reset错误
Document document = connection.get(); //使用Get(),解析HTML,使用Document来接受返回的信息
/*使用各种选择器来解析获取获取到的HTML*/
Elements cover = document.getElementsByClass("cover"); //使用Class选择元素,获取所有名为cover的元素
String[] UrlList = new String[cover.size()]; //创建list来保存爬出的图片URL
for (int Time = 0;Time < cover.size();Time++){ //for循环持续爬取图片,.size()获取循环次数
/*从获取的元素中获取数据*/
//获取属性值
Element div = cover.get(Time); //获取cover中的包含<img>标签的第几个<div>(数组排列)
Elements imgUrl = div.getElementsByTag("img"); //获取到<img标签>
String ImgUrl = imgUrl.attr("data-src");
System.out.println("第" + (Time+1) + "张图片");
System.out.println(ImgUrl);//查看输出的图片Url
UrlList[Time] = ImgUrl; //将单个的图片地址添加进数组
}
HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
HSSFSheet hssfSheet = hssfWorkbook.createSheet("Images");
hssfSheet.setColumnWidth(0, 10000);
hssfSheet.setColumnWidth(1, 20000);
String filePath = "C:\\Users\\35367\\Desktop\\Webps" ; //图片保存的位置
String ExcelPath = "C:\\Users\\35367\\Desktop\\ImageExcel.xls"; //Excal位置
for (int i = 0;i < cover.size();i++){
//遍历,下载
File dir = new File(filePath);
//substring()方法来截取字符串,lastIndexOf()来截取最后一个 "/"出现时候的位置(要+1来跳过)
String fileName = UrlList[i].substring(UrlList[i].lastIndexOf("/") + 1,UrlList[i].length());
if (i ==0){
HSSFRow Row = hssfSheet.createRow(i); //行
HSSFCell cell1 = Row.createCell(0);
HSSFCell cell2 = Row.createCell(1);
cell1.setCellValue("FileName");
cell2.setCellValue("ImageURL");
}else {
HSSFRow Row = hssfSheet.createRow(i); //行
HSSFCell cell1 = Row.createCell(0);
HSSFCell cell2 = Row.createCell(1);
cell1.setCellValue(fileName);
cell2.setCellValue(UrlList[i]);
}
//File.separator为分隔符,在什么系统使用法对应的分隔符,用于保存
File file = new File(filePath + File.separator + fileName); //输出的路径
URL url =new URL(UrlList[i]); //new成为Url以便后面使用
URLConnection ConnectionIMG = url.openConnection();
InputStream in = ConnectionIMG.getInputStream();
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
byte[] buf = new byte[1024];
int len = -1;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
FileOutputStream fos = new FileOutputStream(ExcelPath); //IO流写入
hssfWorkbook.write(fos);
fos.close();
System.out.println("Imgage.xls创建成功");
System.out.println(fileName + " 已下载");
}
}
}
运行结果:
Jsoup + HSSFWorkbook 爬取,生成表格
这次爬取的网页时LR2 的段位表
F12打开控制台,查看源代码,
发现我们要找的东西在 <tr>
框的 <th>
标签和 <td>标签
里面,单纯的提取 <tr>
会导致混乱,所以要加入一个判断。
因为段位表是表格,所以我们要引入一个新的Jar包 Poi ,来制作导出表格
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
使用教程可以参考这个 :使用HSSFWorkbook导出、操作excell
代码如下 :
import org.apache.poi.hssf.usermodel.*;
import org.jsoup.Connection;
import org.jsoup.Jsoup ;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
//确认爬取的HTML网页,
String url = "http://www.dream-pro.info/~lavalse/LR2IR/search.cgi?mode=gradelist";
//链接网页
Connection connection = Jsoup.connect(url);
//获取网站源代码
Document document = connection.get();
SPRank(document);
DPRank(document);
}
public static void SPRank(Document document) throws IOException {
Elements Table = document.getElementsByTag("table");
Element table = Table.get(0);
Elements Tr = table.getElementsByTag("tr");
//System.out.println(Tr);
Elements H3 = document.getElementsByTag("h3");
//System.out.println(H3);
String h31 = H3.get(0).text(); //SP段位名
HSSFWorkbook hssfWorkbook = new HSSFWorkbook(); //创建Excal表
HSSFSheet hssfSheetSP = hssfWorkbook.createSheet(h31); //创建名为 :"段位認定 シングル(2018) " Excel
//设置单元格宽度
hssfSheetSP .setColumnWidth(1, 8000);
HSSFCellStyle cellStyle= hssfWorkbook.createCellStyle();
//设置水平对齐的样式为居中对齐;
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//设置字体
HSSFFont font = hssfWorkbook.createFont();
font.setFontName("黑体");
int Th1 = 0; //列数
int Tr1 = Tr.size(); //行数
String star = ""; //小段位星级
String gradename = ""; //小段位名
String crossnum = ""; //小合格人数
String challengesnum = ""; //小挑战人数
String yield = ""; //小合格率
String Star = ""; //段位星级
String GradeName = ""; //段位名
String CrossNum = ""; //合格人数
String ChallengesNum = ""; //挑战人数
String Yield = ""; //合格率
for (int Tri = 0; Tri < Tr.size(); Tri++) {
Element TrTitle = Tr.get(Tri); //第几个Tr框
Elements Td = TrTitle.getElementsByTag("td"); //合格率等标题 : <th> 其他的时 : <td>
Elements Th = TrTitle.getElementsByTag("th");
HSSFRow hssfRow = hssfSheetSP.createRow(Tri); //在对应的行中填入数据,定位行
HSSFCell cell1 = hssfRow.createCell(0); //第rowi行第一个单元格
HSSFCell cell2 = hssfRow.createCell(1);
HSSFCell cell3 = hssfRow.createCell(2);
HSSFCell cell4 = hssfRow.createCell(3);
HSSFCell cell5 = hssfRow.createCell(4);
if (Td.size() == 0) { //获取小段位内容
} else {
star = Td.get(0).text();
gradename = Td.get(1).text();
crossnum = Td.get(2).text();
challengesnum = Td.get(3).text();
yield = Td.get(4).text();
cell1.setCellValue(star);
cell2.setCellValue(gradename);
cell3.setCellValue(crossnum);
cell4.setCellValue(challengesnum);
cell5.setCellValue(yield);
}
if (Th.size() == 0) { //获取段位表内容
} else {
Th1 = Th.size(); //获取列数
Star = Th.get(0).text();
GradeName = Th.get(1).text();
CrossNum = Th.get(2).text();
ChallengesNum = Th.get(3).text();
Yield = Th.get(4).text();
cell1.setCellValue(Star);
cell2.setCellValue(GradeName);
cell3.setCellValue(CrossNum);
cell4.setCellValue(ChallengesNum);
cell5.setCellValue(Yield);
}
//表名 : 段位認定 シングル(2018) (h31)
//项目名 : 1.星级 Star 2.段位名 GradeName 3.合格人数 CrossNum 4.挑战人数 ChallengesNum 5.通过率 Yield
//行数: Tr1 , 列数 : Th1
}
FileOutputStream fos = new FileOutputStream("C:\\Users\\35367\\Desktop\\LR2(SP).xls"); //IO流写入
hssfWorkbook.write(fos);
fos.close();
System.out.println("SPRank创建成功");
}
public static void DPRank(Document document) throws IOException{
Elements Table = document.getElementsByTag("table");
Element table = Table.get(1);
Elements Tr = table.getElementsByTag("tr");
//System.out.println(Tr);
Elements H3 = document.getElementsByTag("h3");
//System.out.println(H3);
String h32 = H3.get(1).text(); //SP段位名
HSSFWorkbook hssfWorkbook = new HSSFWorkbook(); //创建Excal表
HSSFSheet hssfSheetDP = hssfWorkbook.createSheet(h32); //创建名为 :"段位認定 DP(2018) " Excel表
//设置单元格宽度
hssfSheetDP .setColumnWidth(1, 8400);
HSSFCellStyle cellStyle= hssfWorkbook.createCellStyle();
//设置水平对齐的样式为居中对齐;
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//设置字体
HSSFFont font = hssfWorkbook.createFont();
font.setFontName("黑体");
int Th1 = 0; //列数
int Tr1 = Tr.size(); //行数
String star = ""; //小段位星级
String gradename = ""; //小段位名
String crossnum = ""; //小合格人数
String challengesnum = ""; //小挑战人数
String yield = ""; //小合格率
String Star = ""; //段位星级
String GradeName = ""; //段位名
String CrossNum = ""; //合格人数
String ChallengesNum = ""; //挑战人数
String Yield = ""; //合格率
for (int Tri = 0; Tri < Tr.size(); Tri++) {
Element TrTitle = Tr.get(Tri); //第几个Tr框
Elements Td = TrTitle.getElementsByTag("td"); //合格率等标题 : <th> 其他的时 : <td>
Elements Th = TrTitle.getElementsByTag("th");
HSSFRow hssfRow = hssfSheetDP.createRow(Tri); //在对应的行中填入数据,定位行
HSSFCell cell1 = hssfRow.createCell(0); //第rowi行第一个单元格
HSSFCell cell2 = hssfRow.createCell(1);
HSSFCell cell3 = hssfRow.createCell(2);
HSSFCell cell4 = hssfRow.createCell(3);
HSSFCell cell5 = hssfRow.createCell(4);
if (Td.size() == 0) {
}else {
star = Td.get(0).text();
gradename = Td.get(1).text();
crossnum = Td.get(2).text();
challengesnum = Td.get(3).text();
yield = Td.get(4).text();
cell1.setCellValue(star);
cell2.setCellValue(gradename);
cell3.setCellValue(crossnum);
cell4.setCellValue(challengesnum);
cell5.setCellValue(yield);
}
if (Th.size() == 0) {
}else {
Th1 = Th.size();
Star = Th.get(0).text();
GradeName = Th.get(1).text();
CrossNum = Th.get(2).text();
ChallengesNum = Th.get(3).text();
Yield = Th.get(4).text();
cell1.setCellValue(Star);
cell2.setCellValue(GradeName);
cell3.setCellValue(CrossNum);
cell4.setCellValue(ChallengesNum);
cell5.setCellValue(Yield);
}
}
//表名 : 段位認定 シングル(2018) (h31)
//项目名 : 1.星级 Star 2.段位名 GradeName 3.合格人数 CrossNum 4.挑战人数 ChallengesNum 5.通过率 Yield
//行数: Tr1 , 列数 : Th1
FileOutputStream fos = new FileOutputStream("C:\\Users\\35367\\Desktop\\LR2(DP).xls"); //IO流写入
hssfWorkbook.write(fos);
fos.close();
System.out.println("DPRank创建成功");
}
}
输出结果: