Java 8获取含AJAX生成内容的URL HTML及解析数据表格方案
解决方案
为什么直接解析HTML拿不到表格数据
目标页面的表格数据是通过JavaScript异步加载的,你直接获取的原始HTML只是页面骨架,实际数据还没被注入到DOM中,所以看不到带数据的表格。
方案1:使用支持JS渲染的Java库(HtmlUnit)
HtmlUnit是无界面的Java浏览器,能执行JS并渲染出完整的页面DOM,适合轻量的动态页面爬取,Java 8完全兼容。
实现步骤
- 引入依赖(Maven为例):
<dependency> <groupId>net.sourceforge.htmlunit</groupId> <artifactId>htmlunit</artifactId> <version>2.67.0</version> <!-- 选择兼容Java 8的版本 --> </dependency>
- 代码示例:
import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlTable; public class TcgPlayerParser { public static void main(String[] args) throws Exception { try (WebClient webClient = new WebClient()) { // 启用JavaScript,设置等待JS加载的时间 webClient.getOptions().setJavaScriptEnabled(true); webClient.waitForBackgroundJavaScript(5000); // 等待5秒让JS加载完成 // 访问目标页面 HtmlPage page = webClient.getPage("https://www.tcgplayer.com/categories/trading-and-collectible-card-games/magic-the-gathering/price-guides/khans-of-tarkir"); // 定位表格(根据页面实际的表格选择器,比如通过class或id) HtmlTable table = page.getFirstByXPath("//table[contains(@class, 'price-guide-table')]"); if (table != null) { // 遍历表格行和列,处理数据 table.getRows().forEach(row -> { row.getCells().forEach(cell -> { System.out.print(cell.getTextContent().trim() + "\t"); }); System.out.println(); }); } } } }
方案2:使用Selenium(适合复杂动态页面)
Selenium需要配合浏览器驱动(如ChromeDriver),能模拟真实浏览器的行为,处理更复杂的JS渲染场景。
实现步骤
- 引入依赖(Maven为例):
<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.141.59</version> <!-- 兼容Java 8的版本 --> </dependency>
- 下载对应浏览器的驱动(如ChromeDriver),确保版本和浏览器匹配,然后配置路径。
- 代码示例:
import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import java.util.List; public class TcgPlayerSeleniumParser { public static void main(String[] args) { // 设置ChromeDriver路径 System.setProperty("webdriver.chrome.driver", "path/to/chromedriver"); WebDriver driver = new ChromeDriver(); try { driver.get("https://www.tcgplayer.com/categories/trading-and-collectible-card-games/magic-the-gathering/price-guides/khans-of-tarkir"); // 等待页面加载(可以用显式等待替代固定睡眠) Thread.sleep(5000); // 定位表格 WebElement table = driver.findElement(By.cssSelector("table.price-guide-table")); List<WebElement> rows = table.findElements(By.tagName("tr")); // 遍历处理数据 for (WebElement row : rows) { List<WebElement> cells = row.findElements(By.tagName("td")); for (WebElement cell : cells) { System.out.print(cell.getText().trim() + "\t"); } System.out.println(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { driver.quit(); } } }
方案3:直接调用API接口(高效推荐)
动态页面的数据通常来自后端API,你可以通过浏览器开发者工具(F12)的「网络」面板,筛选XHR请求,找到获取价格数据的API接口,直接请求接口获取JSON格式的数据,解析效率更高,无需渲染JS。
操作步骤
- 打开目标页面,按F12打开开发者工具,切换到「网络」标签。
- 刷新页面,筛选「XHR」类型的请求,找到返回价格数据的接口(比如包含
price-guide或product相关的请求)。 - 复制该接口的URL、请求头(注意可能需要的Cookie或User-Agent),用Java的HttpURLConnection或OkHttp发送请求。
- 解析返回的JSON数据(可以用Jackson或Gson库)。
代码示例(用OkHttp+Jackson)
- 依赖:
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.9.3</version> <!-- 兼容Java 8 --> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.4</version> <!-- 兼容Java 8 --> </dependency>
- 代码(注意:API接口需要自己抓实际的,以下是示例结构):
import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; public class TcgPlayerApiParser { public static void main(String[] args) throws IOException { OkHttpClient client = new OkHttpClient(); // 替换为实际抓到的API接口URL String apiUrl = "https://example-tcgplayer-api-url.com/price-guides/khans-of-tarkir"; Request request = new Request.Builder() .url(apiUrl) .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36") // 若需要Cookie,添加Cookie头 // .addHeader("Cookie", "your-cookie-value") .build(); try (Response response = client.newCall(request).execute()) { if (response.isSuccessful() && response.body() != null) { String json = response.body().string(); ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(json); // 遍历JSON节点,提取需要的数据 JsonNode items = root.path("data").path("items"); for (JsonNode item : items) { String cardName = item.path("name").asText(); String price = item.path("marketPrice").asText(); System.out.println(cardName + ": " + price); } } } } }
注意事项
- 注意网站的
robots.txt和使用条款,避免频繁请求导致IP被封禁。 - 若使用API方案,接口可能会随时变化,需要定期检查。
- HtmlUnit和Selenium的版本要选择兼容Java 8的,避免出现版本不兼容问题。
内容的提问来源于stack exchange,提问作者Boris Ivanov
相关产品推荐
相关产品推荐

