JAVA爬虫实战项目——OKX解析
前言
因为项目的需要,所以需要学习Java爬虫,我是参照B站教程:【【狂神说Java】Jsoup爬虫入门实战】这一视频教程,进行学习的,在这里记录一下自己的学习经验和问题解答,以供后续复盘回看。
介绍
爬虫的生命周期:
- 页面下载
- 链接提取
- URL管理
- 内容抽取及持久化
通用爬虫:宽度遍历,对网页进行无差别的进行抓取,但是效率不高,因为是爬取的网页上的所有内容
垂直型爬虫:关注内容与准确率,仅仅抓取到有效信息的数据
例如webmagic
主要技术
模拟浏览器:HttpClient
html解析:jsoup
初始配置
新建Maven项目直接使用Project,不需要选下面的Maven Archetype

项目建好之后,pom.xml中添加Jsoup的依赖,Jsoup 是一款专为 Java 打造的 HTML 解析利器,它能轻松从 URL、文件或字符串中解析 HTML 内容。其具备易用、快速、灵活的特性,可通过类似 CSS 选择器的语法精准定位元素,方便地提取元素文本与属性值,还能自如地进行 DOM 操作,如添加、删除、修改元素等,在网页数据抓取、信息提取及 HTML 文档处理等场景中广受 Java 开发者青睐,是处理 HTML 数据的得力助手。
我这里用的是1.10.2版本的
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>
JSoup主程序
因为需要访问的是OKX,所以我们需要在代码中添加代理服务器,在这里先打印的是document,因为还不确定,能不能找到我们需要的类,所以先测试页面的读取效果。
package com.tuling.utils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
public class HtmlParse {
public static void main(String[] args) throws IOException {
// 设置要解析的url
String url = "https://www.okx.com";
// 设置代理服务器
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("代理服务器地址", 代理服务器端口));
// 解析网页
Document document = Jsoup.connect(url)
.proxy(proxy)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko)Chrome/91.0.4472.124 Safari/537.36")
.get();
// 获取指定class的元素
Elements element = document.getElementsByClass("要查找的类");
System.out.println(document.html());
}
}
这返回的结果并没有找到我们想要的数据,问题就在于jsoup读取的是静态的界面,而对于动态更新的数据,不能捕获到。
后来我们通过F12开发者工具,监控Network,看看能不能找到我们想要的东西

可以看到,有一个filter-list的信息,里面储存的信息刚好可以和界面对应上,需要我们点击按钮才能获取到这一信息,所以在程序开发的时候,需要有点击这一操作,所以只靠Jsoup肯定是不能满足我们的需求,这时就需要找到另一个工具——Selenium。
Selenium+ChromeDriver程序
程序启动后,会调用ChromeDriver启动模拟浏览器,Selenium点击按钮并读取json数据,给他保存起来。
为了更好的满足可读性,需要从json中获取我们需要的数据,假如字段中含有price,则把price后的数据打印出来。
依赖安装
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.9.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
package com.tuling;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v85.network.Network;
import org.openqa.selenium.devtools.v85.network.model.RequestId;
import java.io.FileWriter;
import java.io.IOException;
import java.time.Instant;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
// 设置chromedriver.exe的路径
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
WebDriver chromeDriver = new ChromeDriver();
DevTools devTools = ((ChromeDriver) chromeDriver).getDevTools();
devTools.createSession();
final RequestId[] targetRequestId = new RequestId[1];
boolean found = false;
// 启用网络监控
devTools.send(Network.enable(Optional.of(100000000), Optional.empty(), Optional.empty()));
// 先访问页面
//https://www.okx.com/zh-hans/web3/detail/501/5QS7RcHfGUa2ZtrovPvEJMB9coqroiT7H48dPSwFpump
String url = "https://www.okx.com/zh-hans/web3/detail/501/GorvUUSkJGSzJUebM5W6berUkZ5pG8nmnn7tmk74pump";
chromeDriver.get(url);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 添加响应监听器,捕获特定URL的响应
devTools.addListener(Network.responseReceived(), responseReceived -> {
if (responseReceived.getResponse().getUrl().contains("filter-list")) {
targetRequestId[0] = responseReceived.getRequestId();
}
});
while (true) {
// 点击交易历史按钮
WebElement button = chromeDriver.findElement(By.className("index_tab-item__z34vL"));
button.click();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 获取响应体
if (targetRequestId[0]!= null) {
try {
String jsonResponse = devTools.send(Network.getResponseBody(targetRequestId[0])).getBody();
System.out.println("历史数据json已获取");
System.out.println("解析json......获取价格数据");
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(jsonResponse);
JsonNode dataNode = root.get("data");
if (dataNode!= null && dataNode.has("list")) {
JsonNode listNode = dataNode.get("list");
int count = 0;
System.out.println("==========价格=============");
for (JsonNode item : listNode) {
if (count >= 10) {
break;
}
if (item.has("price")) {
System.out.println(item.get("price"));
count++;
}
}
System.out.println("=========================");
}
long timestamp = Instant.now().getEpochSecond();
String fileName = timestamp + ".json";
try (FileWriter fileWriter = new FileWriter(fileName)) {
fileWriter.write(jsonResponse);
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
进一步开发
上面我们已经完成了对动态数据的获取,那对于在Network中找不到json数据的,我们只能采用静态获取的方式,这方法的优点是易于寻找数据,但是缺点是数据不灵活,就是已经写死的。
package com.tuling;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v85.network.Network;
import org.openqa.selenium.devtools.v85.network.model.RequestId;
import java.io.FileWriter;
import java.io.IOException;
import java.time.Instant;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
// 设置chromedriver.exe的路径
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
WebDriver chromeDriver = new ChromeDriver();
DevTools devTools = ((ChromeDriver) chromeDriver).getDevTools();
devTools.createSession();
final RequestId[] targetRequestId = new RequestId[1];
boolean found = false;
// 启用网络监控
devTools.send(Network.enable(Optional.of(100000000), Optional.empty(), Optional.empty()));
// 先访问页面
//https://www.okx.com/zh-hans/web3/detail/501/5QS7RcHfGUa2ZtrovPvEJMB9coqroiT7H48dPSwFpump
String url = "https://www.okx.com/zh-hans/web3/detail/501/GorvUUSkJGSzJUebM5W6berUkZ5pG8nmnn7tmk74pump";
chromeDriver.get(url);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 添加响应监听器,捕获特定URL的响应
devTools.addListener(Network.responseReceived(), responseReceived -> {
if (responseReceived.getResponse().getUrl().contains("filter-list")) {
targetRequestId[0] = responseReceived.getRequestId();
}
});
while (true) {
// 点击交易历史按钮
WebElement button = chromeDriver.findElement(By.className("index_tab-item__z34vL"));
button.click();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("币种名称:ZAILGO");
//获取MarketCap和Liquidity,静态获取方法,和VPN所在地区有关,在哪即为哪里的货币
java.util.List<WebElement> elementList = chromeDriver.findElements(By.className("index_value__QnvWy"));
if (elementList.size() >= 2) {
// 通过索引0获取第一个元素
WebElement firstElement = elementList.get(0);
System.out.println("Market Cap: " + firstElement.getText());
// 通过索引1获取第二个元素
WebElement secondElement = elementList.get(1);
System.out.println("Liquidity: " + secondElement.getText());
}
// 获取响应体
if (targetRequestId[0]!= null) {
try {
String jsonResponse = devTools.send(Network.getResponseBody(targetRequestId[0])).getBody();
//System.out.println("历史数据json已获取");
//System.out.println("解析json......获取价格数据");
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(jsonResponse);
JsonNode dataNode = root.get("data");
if (dataNode!= null && dataNode.has("list")) {
JsonNode listNode = dataNode.get("list");
int count = 0;
System.out.println("==========价格=============");
for (JsonNode item : listNode) {
if (count >= 10) {
break;
}
if (item.has("price")) {
System.out.println(item.get("price"));
count++;
}
}
System.out.println("=========================");
}
long timestamp = Instant.now().getEpochSecond();
String fileName = timestamp + ".json";
try (FileWriter fileWriter = new FileWriter(fileName)) {
fileWriter.write(jsonResponse);
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
更多推荐
所有评论(0)