前几天有人找到我问会不会写爬虫,我说简单的可以,复杂的就没有办法了。
结果丢给我一个报名网站,要实时获取对方网站不同地区部门职位的报名情况,所以就尝试了一下。
效果还可以,代码如下:
需要的依赖:
pom.xml
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.16.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.39</version>
</dependency>
具体代码:
RobotServer
package com.demo.server;
import com.alibaba.fastjson2.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author zf
* @ClassName RobotServer.java
* @ProjectName demo
*/
@Service
public class RobotServer {
// 目标网站信息
static String host = "";
static String path = "";
static String url = host + path;
static String updateTime = "null";
public JSONObject queryData(String areaCode) {
ArrayList<Object> list = new ArrayList<>();
try {
// 使用Jsoup发送GET请求获取网页内容
Document document = Jsoup.connect(url).get();
// 获取form表单元素
Element formElement = document.selectFirst("form");
// 获取职位所属地区选择框元素
Element jobAreaListElement = formElement.selectFirst("select[name=jobAreaList]");
// 模拟表单提交
formElement.selectFirst("input[type=submit]").attr("value", "查询");
formElement.selectFirst("select[name=jobAreaList] option[value=" + areaCode + "]")
.attr("selected", "selected"); //选中指定的职位所属地区
// 修改提交URL地址
url = url.replace(path, formElement.attr("action"));
// 发送POST请求并获取结果
document = Jsoup.connect(url).data(jobAreaListElement.attr("name"), areaCode).post();
// 获取更新时间
updateTime = extractTime(document.select("span").first().text());
// 获取所有满足条件的table
Elements tables = document.select("table.tableline");
// 获取第3个table
Element thirdTable = tables.get(2);
// 获取表格的所有行
Elements rows = thirdTable.select("tr");
// 遍历每一行,跳过表头
for (int i = 1; i < rows.size(); i++) {
Element row = rows.get(i);
// 获取每一行的列
Elements cols = row.select("td");
// 获取部门名称
String department = cols.get(0).text();
// 获取职位名称
String position = cols.get(1).text();
// 获取开考比例
String examRatio = cols.get(2).text();
// 获取招考人数
String recruitCount = cols.get(3).text();
// 获取报名成功人数
String cellStyle = cols.get(4).attr("style"); //获取单元格的style属性
// 实际报名人数
String application = getApplication(cellStyle);
// 具体报考数据
JSONObject obj = new JSONObject();
obj.put("department", department); //部门名称
obj.put("position", position); //职位名称
obj.put("examRatio", examRatio); //开考比例
obj.put("recruitCount", recruitCount); //招考人数
obj.put("application", application); //报名成功人数
list.add(obj);
}
} catch (Exception e) {
// 异常处理
e.printStackTrace();
}
// 返回数据
JSONObject object = new JSONObject();
object.put("updateTime", updateTime);
object.put("list", list);
return object;
}
// 格式化报名人数
private String getApplication(String cellStyle) {
// 默认报名人数
String application = "null";
// 判断cellStyle是否包含特定选项
String[] colors = {"DodgerBlue", "Yellow", "Red"}; //颜色集合
String[] ranges = {"0-2", "3-50", "51+"}; //对应的区间集合
boolean hasColor = false; //初始化标志变量,用于判断是否存在特定颜色
for (String color : colors) { //遍历所有颜色
if (cellStyle.contains(color)) { //如果cellStyle包含颜色
hasColor = true; //设置标志变量为true
break;
}
}
if (hasColor) { //如果存在特定颜色
for (int c = 0; c < colors.length; c++) { //遍历颜色集合
if (cellStyle.contains(colors[c])) { //如果cellStyle包含当前颜色
application = ranges[c]; //设置对应的区间值
break;
}
}
}
return application;
}
// 格式化时间
public static String extractTime(String input) {
String pattern = "(\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}:\\d{2}:\\d{2})";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(input);
if (m.find()) {
String rawTime = m.group(1);
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = inputFormat.parse(rawTime);
return outputFormat.format(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
return "null";
}
}