提交 384c02e1 authored 作者: wangmenglong's avatar wangmenglong

增加爬虫

上级 f561fd6b
......@@ -205,6 +205,20 @@
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
<!-- Selenium 核心依赖(包含 WebDriver 所有核心类) -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.18.1</version> <!-- 最新稳定版,适配 Chrome 120+ -->
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.4</version>
</dependency>
</dependencies>
<build>
......
package com.jfb.recruit.controller.api;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
public class HttpClientHdfsUtils {
/**
* 根据系统当前时间在 HDFS 上创建文件并写入数据。
* 会以当前日期作为文件夹名,在 /JobData 目录下创建文件夹,然后在该文件夹中创建指定文件名的文件并写入数据。
*
* @param url HDFS 的 URI,例如 "hdfs://localhost:9000"
* @param fileName 要创建的文件名
* @param data 要写入文件的数据
*/
public static void createFileBySysTime(String url, String fileName, String data) {
// 指定操作 HDFS 的用户为 root
System.setProperty("HADOOP_USER_NAME", "root");
// 定义文件路径变量
Path filePath = null;
// 获取系统当前时间
Calendar calendar = Calendar.getInstance();
Date currentTime = calendar.getTime();
// 定义日期格式化对象,将日期格式化为 yyyyMMdd 的形式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
// 获取格式化后的日期字符串,作为文件夹名
String directoryName = dateFormat.format(currentTime);
// 创建 Hadoop 配置对象
Configuration conf = new Configuration();
// 将传入的 URL 转换为 URI 对象
URI hdfsUri = URI.create(url);
// 使用 try-with-resources 语句自动管理 FileSystem 资源,确保资源正确关闭
try (FileSystem fileSystem = FileSystem.get(hdfsUri, conf)) {
// 构建要创建的目录路径
filePath = new Path("/SESSECS/" + directoryName);
// 检查目录是否存在,如果不存在则创建
if (!fileSystem.exists(filePath)) {
// 创建目录,包括所有必要的父目录
fileSystem.mkdirs(filePath);
}
// 构建要创建的文件的完整路径
Path fullFilePath = new Path(filePath.toString() + "/" + fileName);
// 在指定路径创建文件并获取输出流
try (FSDataOutputStream outputStream = fileSystem.create(fullFilePath)) {
// 将数据转换为字节数组输入流
ByteArrayInputStream inputStream = new ByteArrayInputStream(data.getBytes());
// 将输入流中的数据复制到输出流中,即写入文件
IOUtils.copyBytes(inputStream, outputStream, conf, true);
}
} catch (IOException e) {
// 打印异常堆栈信息,方便调试
System.err.println("在 HDFS 上创建文件并写入数据时发生错误: " + e.getMessage());
e.printStackTrace();
}
}
}
package com.jfb.recruit.controller.api;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* HttpClientResp 类用于封装 HTTP 响应的相关信息,包括响应状态码、响应内容和请求头信息。
* 该类实现了 Serializable 接口,以便可以进行序列化操作。
*/
public class HttpClientResp implements Serializable {
// 序列化版本号,用于保证序列化和反序列化的兼容性
private static final long serialVersionUID = -2224539827395038194L;
// 响应状态码
private int code;
// 响应数据
private String content;
// 请求头信息,使用 Map 存储,键为头信息的名称,值为头信息的值
private Map<String, String> headers;
/**
* 空参构造函数,用于创建一个空的 HttpClientResp 对象。
*/
public HttpClientResp() {
this.headers = new HashMap<>();
}
/**
* 构造函数,用于创建一个仅包含响应状态码的 HttpClientResp 对象。
*
* @param code 响应状态码
*/
public HttpClientResp(int code) {
this.code = code;
this.headers = new HashMap<>();
}
/**
* 构造函数,用于创建一个仅包含响应内容的 HttpClientResp 对象。
*
* @param content 响应内容
*/
public HttpClientResp(String content) {
this.content = content;
this.headers = new HashMap<>();
}
/**
* 构造函数,用于创建一个包含响应状态码和响应内容的 HttpClientResp 对象。
*
* @param code 响应状态码
* @param content 响应内容
*/
public HttpClientResp(int code, String content) {
this.code = code;
this.content = content;
this.headers = new HashMap<>();
}
/**
* 构造函数,用于创建一个包含响应状态码、响应内容和请求头信息的 HttpClientResp 对象。
*
* @param code 响应状态码
* @param content 响应内容
* @param headers 请求头信息
*/
public HttpClientResp(int code, String content, Map<String, String> headers) {
this.code = code;
this.content = content;
this.headers = headers != null ? headers : new HashMap<>();
}
/**
* 获取响应状态码。
*
* @return 响应状态码
*/
public int getCode() {
return code;
}
/**
* 设置响应状态码。
*
* @param code 响应状态码
*/
public void setCode(int code) {
this.code = code;
}
/**
* 获取响应内容。
*
* @return 响应内容
*/
public String getContent() {
return content;
}
/**
* 设置响应内容。
*
* @param content 响应内容
*/
public void setContent(String content) {
this.content = content;
}
/**
* 获取请求头信息。
*
* @return 请求头信息的 Map
*/
public Map<String, String> getHeaders() {
return headers;
}
/**
* 设置请求头信息。
*
* @param headers 请求头信息的 Map
*/
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
/**
* 向请求头信息中添加一个键值对。
*
* @param key 请求头的名称
* @param value 请求头的值
*/
public void addHeader(String key, String value) {
this.headers.put(key, value);
}
/**
* 获取响应状态码,与 getCode 方法功能相同,提供一个更具描述性的方法名。
*
* @return 响应状态码
*/
public int getStatusCode() {
return code;
}
/**
* 将请求头信息保存到指定的 JSON 文件中。
*
* @param filePath 要保存的 JSON 文件的路径
* @throws IOException 如果保存文件时发生 I/O 错误
*/
public void saveHeadersToJson(String filePath) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(new File(filePath), headers);
}
/**
* 重写 toString 方法,用于方便打印对象的信息。
*
* @return 包含响应状态码和响应内容的字符串
*/
@Override
public String toString() {
return "HttpClientResp [code=" + code + ", content=" + content + ", headers=" + headers + "]";
}
/**
* 内部类,用于模拟 ObjectMapper 类,用于将请求头信息保存到 JSON 文件中。
*/
private static class ObjectMapper {
public void writeValue(File file, Map<String, String> headers) {
throw new UnsupportedOperationException("Not implemented");
}
}
}
package com.jfb.recruit.controller.api;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
/**
* HttpClientUtils 类提供了使用 Apache HttpClient 进行 HTTP POST 请求的工具方法。
* 包含封装请求头、请求参数,执行请求并获取响应内容,以及释放资源等功能。
*/
public class HttpClientUtils {
// 编码格式,发送编码格式统一用 UTF-8
private static final String ENCODING = "UTF-8";
// 设置连接超时时间,单位毫秒
private static final int CONNECT_TIMEOUT = 6000;
// 请求获取数据的超时时间(即响应时间),单位毫秒
private static final int SOCKET_TIMEOUT = 6000;
/**
* 封装 HTTP 请求头。
* 将传入的请求头参数添加到 HttpRequestBase 对象中。
*
* @param params 请求头参数的键值对映射
* @param httpMethod HttpRequestBase 对象,用于表示 HTTP 请求
*/
public static void packageHeader(Map<String, String> params, HttpRequestBase httpMethod) {
// 检查请求头参数是否为空
if (params != null) {
// 获取请求头参数的键值对集合
Set<Entry<String, String>> entrySet = params.entrySet();
// 遍历键值对集合,将每个键值对添加到请求头中
for (Entry<String, String> entry : entrySet) {
httpMethod.setHeader(entry.getKey(), entry.getValue());
}
}
}
/**
* 封装 HTTP 请求参数。
* 将传入的请求参数封装到 HttpEntityEnclosingRequestBase 对象中。
*
* @param params 请求参数的键值对映射
* @param httpMethod HttpEntityEnclosingRequestBase 对象,用于表示包含实体的 HTTP 请求
* @throws UnsupportedEncodingException 如果不支持指定的编码格式
*/
public static void packageParam(Map<String, String> params, HttpEntityEnclosingRequestBase httpMethod) throws UnsupportedEncodingException {
// 检查请求参数是否为空
if (params != null) {
// 创建一个 NameValuePair 列表,用于存储请求参数
List<NameValuePair> nvps = new ArrayList<>();
// 获取请求参数的键值对集合
Set<Entry<String, String>> entrySet = params.entrySet();
// 遍历键值对集合,将每个键值对添加到 NameValuePair 列表中
for (Entry<String, String> entry : entrySet) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
// 将 NameValuePair 列表封装到 UrlEncodedFormEntity 中,并设置编码格式
httpMethod.setEntity(new UrlEncodedFormEntity(nvps, ENCODING));
}
}
/**
* 获取 HTTP 响应内容。
* 执行 HTTP 请求并返回响应结果的封装对象。
*
* @param httpResponse CloseableHttpResponse 对象,用于表示 HTTP 响应
* @param httpClient CloseableHttpClient 对象,用于执行 HTTP 请求
* @param httpMethod HttpRequestBase 对象,用于表示 HTTP 请求
* @return HttpClientResp 对象,封装了响应状态码和响应内容
* @throws Exception 如果执行请求或处理响应时发生异常
*/
public static HttpClientResp getHttpClientResult(CloseableHttpResponse httpResponse, CloseableHttpClient httpClient, HttpRequestBase httpMethod) throws Exception {
// 执行 HTTP 请求
httpResponse = httpClient.execute(httpMethod);
// 检查响应是否有效
if (httpResponse != null && httpResponse.getStatusLine() != null) {
String content = "";
// 检查响应实体是否存在
if (httpResponse.getEntity() != null) {
// 将响应实体内容转换为字符串,并设置编码格式
content = EntityUtils.toString(httpResponse.getEntity(), ENCODING);
}
// 创建并返回 HttpClientResp 对象,封装响应状态码和响应内容
return new HttpClientResp(httpResponse.getStatusLine().getStatusCode(), content);
}
// 如果响应无效,返回表示内部服务器错误的 HttpClientResp 对象
return new HttpClientResp(HttpStatus.SC_INTERNAL_SERVER_ERROR);
}
/**
* 通过 HttpClient Post 方式提交请求头和请求参数,从服务端返回状态码和 JSON 数据内容。
*
* @param url 请求的 URL
* @param headers 请求头参数的键值对映射
* @param params 请求参数的键值对映射
* @return HttpClientResp 对象,封装了响应状态码和响应内容
* @throws Exception 如果执行请求或处理响应时发生异常
*/
public static HttpClientResp doPost(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
// 创建默认的 CloseableHttpClient 对象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 创建 HttpPost 对象,用于表示 POST 请求
HttpPost httpPost = new HttpPost(url);
// 封装请求配置项,设置连接超时时间和响应超时时间
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
// 设置 POST 请求的配置项
httpPost.setConfig(requestConfig);
// 封装请求头
packageHeader(headers, httpPost);
// 封装请求参数
packageParam(params, httpPost);
// 初始化 CloseableHttpResponse 对象,用于存储响应结果
CloseableHttpResponse httpResponse = null;
try {
// 执行请求并获得响应结果
return getHttpClientResult(httpResponse, httpClient, httpPost);
} finally {
// 释放资源
release(httpResponse, httpClient);
}
}
/**
* 释放 httpclient(HTTP 请求)对象资源和 httpResponse(HTTP 响应)对象资源。
*
* @param httpResponse CloseableHttpResponse 对象,用于表示 HTTP 响应
* @param httpClient CloseableHttpClient 对象,用于执行 HTTP 请求
* @throws IOException 如果关闭资源时发生 I/O 异常
*/
private static void release(CloseableHttpResponse httpResponse, CloseableHttpClient httpClient) throws IOException {
// 检查响应对象是否为空,若不为空则关闭
if (httpResponse != null) {
httpResponse.close();
}
// 检查客户端对象是否为空,若不为空则关闭
if (httpClient != null) {
httpClient.close();
}
}
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论