使用Java进行网页数据抓取

用于网页抓取的流行语言有Python、JavaScript和Node.js、PHP、Java、C#等。因为有很多选择,想要确定哪种语言最合适并不容易。每种语言都有其优点和缺点。在本文中,我们将使用Java进行网页抓取并使用 Java创建一个网页抓取工具。

有两个最常用的Java网页抓取库——JSoupHtmlUnit

JSoup是一个强大的库,可以有效地处理格式错误的HTML。这个库的名字来自于短语“tag soup”,它指的是格式错误的HTML文档。

HtmlUnit是用于Java程序的无图形用户界面或无头的浏览器。它可以模拟浏览器的关键方面,例如从页面中获取特定元素、单击这些元素等。正如这个库的名称所暗示的那样,它通常用于单元测试。这是一种模拟浏览器以进行测试的方法。

HtmlUnit也可用于网页抓取。好消息是,只需一行,就可以关闭JavaScript和CSS。这个库对网页抓取很有帮助,因为大多数情况下不需要JavaScript和CSS。后面我们将检查这两个库并创建网页抓取工具。

使用Java构建网络爬虫的先决条件 

本教程使用Java进行网页抓取,前提是您要熟悉Java编程语言。为了管理包,我们将使用Maven。

除了Java基础知识外,您需要对网站的工作原理有初步的了解。还需要对HTML和使用XPath或CSS Selectors选择其中的元素有很好的了解。请注意,并非所有库都支持XPath。

SS Selectors的快速概览
在我们继续本Java网页抓取教程之前,先回顾一下CSS Selectors

#firstname–选择任何id等于“firstname”的元素

.blue–选择class包含“blue”的任何元素

p–选择所有<p>标签

div#firstname–选择等于“firstname”的div元素id

p.link.new–请注意,此处没有空格。选择<p class=”link new”>

p.link .new–请注意此处的空格。选择在<p class=”link”>里“new”类的任何元素

接下来,让我们回顾一下可用Java进行网页抓取的库。

使用JSoup配合Java抓取网页

JSoup可能是使用Java进行网页抓取最常用的库了。让我们使用这个库来创建一个Java网页抓取工具。

总体来说,使用Java进行网页抓取涉及三个步骤。

获取JSoup

使用Java进行网页抓取的第一步是获取Java库。Maven可以在这里提供帮助。使用任何Java IDE创建一个Maven项目。如果您不想使用Maven,请前往以下页面查找替代进行下载:

https://jsoup.org/download

pom.xml(Project Object Model)文件中,为依赖项添加一个新部分并为JSoup添加一个依赖项。该pom.xml文件如下:

<dependencies>

       <dependency>

          <groupId>org.jsoup</groupId>

          <artifactId>jsoup</artifactId>

       <version>1.14.1</version>

       </dependency>

</dependencies>

有了以上条件,我们就可以创建一个Java抓取工具了。

获取和解析HTML

使用Java进行网页抓取的第二步是从目标URL中获取HTML并将其解析为Java对象。让我们从导入开始:

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.jsoup.*.并不是一个好习惯。想要始终准确导入您需要的内容尽量少用通配符。上述导入是我们将在本Java网页抓取教程中使用的内容。

JSoup提供了这个connect功能。此函数连接URL并返回一个Document.以下是获取页面HTML的方法:

Document doc = Jsoup.connect(“https://en.wikipedia.

org/wiki/Jsoup”).get();

您会经常在一些地方看到这行代码,但它有一个缺点。这种快捷的方式没有做任何错误处理。更好的方法是创建一个函数。此函数以URL作为参数。首先,创建一个连接并将其存储在一个变量中。之后,get()调用连接对象的方法来检索HTML文档。该文档作为Document类的实例返回。该get()方法可以抛出一个IOException,此IOException需要进行处理,如下:

public static Document getDocument

(String url) {

Connection conn = Jsoup.connect(url);

Document document = null;

try {

    document = conn.get();

} catch (IOException e) {

    e.printStackTrace();

// handle error

}

return document;

}

在某些情况下,您需要传递自定义用户代理。这可以通过userAgent()在调用函数之前将用户代理字符串发送到函数来完成get()

Connection conn = Jsoup.connect(url);

conn.userAgent(“custom user agent”);

document = conn.get();

此操作基本能解决遇到的常见问题。

查询HTML

任何Java网络爬虫构建过程中最关键的步骤是查询HTMLDocument对象以获取所需数据。这是您在用Java编写网络爬虫时花费大部分时间的地方。

JSoup支持多种提取所需元素的方法。比如getElementByIDgetElementsByTag等,使得它更容易查询DOM。

这是导航到Wikipedia上的JSoup页面示例。右键单击标题并选择“检查”,从而打开选定标题的开发人员工具。

使用Java进行网页数据抓取
使用Java进行网页数据抓取 1

在这种情况下,可以使用getElementByIDgetElementsByClass。这里要注意的一个重点是getElementById(注意单数Element返回一个Element对象,getElementsByClass(注意复数Elements返回Element对象的数组列表。

这个Elements的非常方便,因为这个库有一个Elements的扩展ArrayList<Element>.这个扩展使代码更简洁并提供更多功能。

在下面的代码示例中,first()方法可用于从ArrayList.获取第一个元素,在获得元素的引用后,text()可以用来获取文本。

Element firstHeading = document.getElementsByClass

(“firstHeading”).

first();

System.out.println(firstHeading.text());

这些功能都不错;但是,它们仅限于JSoup。对于大多数情况,select函数可能是更好的选择。选择功能不起作用的唯一情况是您需要向上遍历文档的时候。在这些情况下,您可能需要使用parent()children()child()。有关所有可用方法的完整列表,请访问此页面:

https://jsoup.org/cookbook/extracting-data/dom-navigation

以下代码演示了如何使用selectFirst()方法,该方法会返回第一个匹配项。

Element firstHeading= document.selectFirst

(“.firstHeading”);

在这个例子中,使用了selectFirst()方法。如果需要选择多个元素,可以使用该select()方法。将采用CSS Selector作为参数并返回一个实例Elements,它是类型ArrayList<Element>的扩展。

使用HtmlUnit配合Java抓取网页

有很多方法可以读取和修改加载的页面。HtmlUnit可以像浏览器一样使网页交互变得容易,包括阅读文本、填写表单、单击按钮等。在这种情况下,我们将使用该库中的方法从URL读取信息。

如上一节所述,使用Java进行网页抓取涉及三个步骤。

获取和解析HTML

使用Java进行网页抓取的第一步是获取Java库。Maven可以在这里提供帮助。创建一个新的maven项目或使用在上一节中创建的项目。如果您不想使用Maven,请前往此页面查找替代进行下载:

https://sourceforge.net/projects/htmlunit/

在该pom.xml文件中,dependenciesHtmlUnit添加一个新部分并为其添加依赖项。该pom.xml文件将如下所示:

<dependency>   <groupId>net.sourceforge.htmlunit

</groupId>

<artifactId>htmlunit</artifactId>

<version>2.51.0</version>

</dependency>

获取HTML

使用Java进行网页抓取的第二步是从目标URL中检索HTML作为 Java对象。让我们从导入开始:

import com.gargoylesoftware.htmlunit.

WebClient;

import com.gargoylesoftware.htmlunit.html.

DomNode;

import com.gargoylesoftware.htmlunit.html.

DomNodeList;

import com.gargoylesoftware.htmlunit.html.

HtmlElement;

import com.gargoylesoftware.htmlunit.html.

HtmlPage;

如上一节所述,执行通配符导入(例如import com.gargoylesoftware.htmlunit.html.*.)并不是一个好习惯。我们依旧不使用通配符,只导入我们需要的内容。这里导入的是我们将在本Java网页抓取教程中使用的内容。

在这个例子中,我们将抓取这个Librivox页面:

https://librivox.org/the-first-men-in-the-

moon-by-hg-wells

HtmlUnit使用WebClient类来获取页面。第一步是创建此类的实例。在这个例子中,不需要CSS渲染,也没有使用JavaScript。我们可以设置选项来禁用这两个。

WebClient webClient = new WebClient();

webClient.getOptions().setCssEnabled

(false);

webClient.getOptions().

setJavaScriptEnabled

(false);

HtmlPage page = webClient.getPage

(“https://librivox.org/the-first-men-in-

the-moon-by-hg-wells”);

请注意,getPage()函数可以抛出

IOException.您需要在try-catch中引用它。

以下是函数返回HtmlPage实例的一个实现示例:

public static HtmlPage getDocument

(String url)  {

HtmlPage page = null;

try (final WebClient webClient = new WebClient()) {       webClient.getOptions().setCssEnabled

(false);   webClient.getOptions().

setJavaScriptEnabled

(false);

     page = webClient.getPage(url);

} catch (IOException e) {

     e.printStackTrace();

}

return page;

}

然后我们可以继续下一步。

查询HTML

有三类方法可以配合HTMLPage使用。第一个方法是利用DOM的方法,会使用getElementById()getElementByName()等,然后返回一个元素。这些也跟getElementsById()一样有类似的对应项,会返回所有匹配项。这类方法会返回一个DomElement对象或一个DomElement对象列表。

HtmlPage page = webClient.getPage(“https://en.wikipedia.

org/wiki/Jsoup”);

DomElement firstHeading = page.

getElementById (“firstHeading”);

System.out.print(firstHeading.

asNormalizedText()); // prints Jsoup 

第二类方法是使用XPath。在本Java网页抓取教程中,我们将使用Java创建一个网页抓取工具。

导航到此页面:
https://librivox.org/the-first-men-in-the-moon-by-hg-wells

右键单击书名,然后单击检查。如果您已经熟悉XPath,您应该能够看到选择书名的XPath是

//div[@class=”content-wrap clearfix”]/h1.

使用Java进行网页数据抓取
使用Java进行网页数据抓取 2

通过Xpath选择元素

有两种方法可以使用XPath—getByXPath()getFirstByXPath().它们返回HtmlElement而不是DomElement。请注意,引号等特殊字符需要使用反斜杠进行转义:

HtmlElement book = page.getFirstByXPath(“//div[@class=

\”content-wrap clearfix\”]/h1″);

System.out.print(book.

asNormalizedText());

最后,第三类方法是使用CSS选择器。这类方法是querySelector()querySelectorAll()。他们分别返回DomNodeDomNodeList

<DomNode>

为了使这个Java网络爬虫教程更加真实,让我们打印页面中的所有章节名称、读者名称和阅读持续时间。第一步是确定可以选择所有行的选择器。接下来,我们将使用querySelectorAll()方法选择所有行。最后,我们将对所有行运行一个循环并调用querySelector()以提取每个单元格的内容。

String selector = “.chapter-download 

tbody tr”;

DomNodeList<DomNode> rows = page.

querySelectorAll(selector);

for (DomNode row : rows) {

String chapter = row.querySelector

(“td:nth-child(2) a”).asNormalizedText();

String reader = row.querySelector

(“td:nth-child(3) a”).asNormalizedText();

String duration = row.querySelector

(“td:nth-child(4)”).asNormalizedText();

System.out.println(chapter + “\t ” + 

reader + “\t ” + duration);

}

结论

—— 结论 ——

几乎每个企业都需要网络抓取来分析数据并在市场上保持竞争力。了解网页抓取的基础知识以及如何使用Java构建网页抓取工具可以最终帮助企业做出更明智、更快速的决策,这对于企业取得成功至关重要。在本文中,我们看到了两个Java网页抓取示例。

如果您已经了解Java,则可能不需要探索用于网络抓取的任何其他语言。