整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

利用Jsoup技术从互联网上获取数据

利用Jsoup技术从互联网上获取数据

着Web的发展,人们越来越需要从互联网上获取数据并进行分析。为此,Java提供了一个功能强大的库——Jsoup,它可以帮助我们轻松地从Web页面中提取信息。在这篇文章中,我们将探讨如何使用Java和Jsoup来实现一个简单的网络爬虫。

一、Jsoup简介

Jsoup是一款基于Java的HTML解析器,可以将HTML文档转换为可操作的Java对象。Jsoup提供了一些简单而方便的API来解析HTML,例如选择器API、DOM操作API、属性处理API等。这使得我们可以轻松地从Web页面中提取所需的数据。由于Jsoup的高度灵活性和易用性,它被广泛应用于Web抓取和数据挖掘领域。

二、开始编写爬虫

在编写我们的网络爬虫之前,我们需要做一些准备工作。首先,我们需要安装Java和Jsoup,并设置Java环境变量。然后,我们需要确定我们要从哪个网站获取数据,并了解该网站的结构。在这个例子中,我们将使用豆瓣电影作为我们的目标网站,并从该网站获取电影的基本信息。

在Java中使用Jsoup非常简单。我们只需要在Java项目中导入Jsoup库,并使用以下代码创建一个Document对象

Document doc=Jsoup.connect("https://movie.douban.com/top250").get();

这个代码将会从豆瓣电影的Top250页面中获取数据,并创建一个Document对象来存储这些数据。我们可以使用Document对象的方法来解析HTML文档,并提取我们需要的信息。例如,我们可以使用以下代码来获取页面的标题:

String title=doc.title();

在这个例子中,我们将获取页面的标题作为一个字符串。我们可以在控制台上输出这个字符串,以验证我们的代码是否有效:

System.out.println("页面标题是:" + title);

如果一切正常,我们应该能够在控制台上看到页面的标题。

三、提取数据

现在我们已经成功地从豆瓣电影的Top250页面中获取了HTML文档,并将其存储在了一个Document对象中。接下来,我们需要从这个HTML文档中提取我们所需的信息。在这个例子中,我们将提取电影的基本信息,例如电影名称、导演、演员、评分和评论数等。

我们可以使用Jsoup提供的选择器API来轻松地选择HTML文档中的元素。例如,如果我们想选择页面上所有的电影条目,我们可以使用以下代码:

Elements movieElements=doc.select("div.item");

这个代码将会从HTML文档中选择所有class为item的div元素,并将它们存储在一个Elements对象中。接下来,我们可以遍历这些元素,并提取我们所需的信息。例如,我们可以使用以下代码获取每个电影的名称和评分:

for (Element movie : movieElements) {
    String title=movie.select("div.hd a span").text();
    String rating=movie.select("span.rating_num").text();
    System.out.println("电影名称:" + title + ",评分:" + rating);
}

在这个例子中,我们使用选择器API来选择每个电影条目中的电影名称和评分元素。然后,我们使用text()方法来获取这些元素的文本内容,并将它们打印到控制台上。

我们还可以使用选择器API来选择其他元素,例如导演和演员。例如,我们可以使用以下代码获取每个电影的导演和演员:

for (Element movie : movieElements) {
    String directors=movie.select("div.bd p").first().ownText();
    String actors=movie.select("div.bd p").get(1).ownText();
    System.out.println("导演:" + directors + ",演员:" + actors);
}

在这个例子中,我们使用选择器API来选择每个电影条目中的导演和演员元素。然后,我们使用ownText()方法来获取这些元素的文本内容,并将它们打印到控制台上。

四、分页爬取数据

到目前为止,我们已经成功地从豆瓣电影的Top250页面中提取了电影的基本信息。然而,Top250页面只包含前250部电影的信息,如果我们想获取更多的电影信息,我们需要使用分页来获取。

在豆瓣电影中,每个页面最多显示25部电影。因此,如果我们想获取前1000部电影的信息,我们需要遍历40个页面。为了实现这个功能,我们需要使用循环来遍历每个页面,并提取每个页面中的电影信息。例如,我们可以使用以下代码获取前1000部电影的信息:

for (int i=0; i < 40; i++) {
    String url="https://movie.douban.com/top250?start=" + i * 25;
    Document doc=Jsoup.connect(url).get();
    Elements movieElements=doc.select("div.item");
    for (Element movie : movieElements) {
        String title=movie.select("div.hd a span").text();
        String rating=movie.select("span.rating_num").text();
        String directors=movie.select("div.bd p").first().ownText();
        String actors=movie.select("div.bd p").get(1).ownText();
        System.out.println("电影名称:" + title + ",评分:" + rating + ",导演:" + directors + ",演员:" + actors);
    }
}

在这个例子中,我们使用循环来遍历前40个页面。

五、注意问题

问题1:使用Jsoup抓取数据时,如果网站是https开头,可能存在证书SSL证书安全的问题,无法直接爬虫。请求会报错:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target

解决方案有很多,这里推荐一种封装一个工具类,在爬虫之前调用一下这个方法即可。

import javax.net.ssl.*;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JsoupUtil {
    public static void trustEveryone() {
        try {
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            SSLContext context=SSLContext.getInstance("TLS");
            context.init(null, new X509TrustManager[]{new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以下是一个完整的示例:

import com.ruoyi.aqosc.util.JsoupUtil;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;

public class PaChongDemo {

    public static void main(String[] args) throws IOException {
        JsoupUtil.trustEveryone();
        //要爬取的网站
        String url="https://jxj.anqing.gov.cn/xxfb/tzgg/index.html";
        //获得一个和网站的链接,注意是Jsoup的connect
        Connection connect=Jsoup.connect(url);
        //获得该网站的Document对象
        Document document=connect.get();
        //我们可以通过对Document对象的select方法获得具体的文本内容
        Elements rootselect=document.select(".navjz ul li");
        for(Element ele : rootselect){
            Elements dateElements=ele.select(".right.date");
            //发布时间
            String date=dateElements.text();
            System.out.println("发布时间:"+date);

            //然后获得a标签里面具体的内容
            Elements titleElements=ele.select("a");
            //文章名称
            String title=titleElements.attr("title");
            System.out.println("文章名称:"+title);

            //文章链接
            String sourceUrl=titleElements.attr("href");
            System.out.println("文章链接:"+sourceUrl);
        }
    }
}

运行之后控制台打印结果:

有时候需要进入详情页面获取更多详细信息,比如作者,正文,附件之类的,跟上面类似,前面已经拿到了文章链接,拿文章链接跟上面一样再去执行一次 Connection connect=Jsoup.connect(文章链接);获取页面元素即可。

问题2:如果正文内的图片、附件之类的使用的是相对路径,因为抓取之后到新的服务器,前缀变了,新的服务器对应的路径并没有相应的文件,在前端显示的时候就会提示找不到,如何处理呢?处理方法也比较简单,就是进行地址转化,使用绝对地址。

Elements links=element.select("a");
for(Element link: links){
    link.attr("href",link.attr("abs:href"));
}

Elements imgs=element.select("img");
for(Element img: imgs){
    img.attr("src",img.attr("abs:src"));
}

查找"a"和"img",将其中的href元素值修改为绝对路径。link.attr("abs:href")将会得到对应链接的绝对路径,其中属性为abs:href。同理,img.attr("abs:src")可以得到图片绝对路径abs:src。

以下是一个详细的demo:

你太美。

虽然第一个html代码写的非常随意,就四个字:鸡你太美。但是用浏览器打开之后确实是能看到是以网页的形式所展现的。这个现象就有点奇怪了,为什么?讲道理,只要是一种语言,必定有自己的语法格式,得按它的套路去写才能认为代码写的是对的,然后才能去正常的运行。

但是这里就四个字:鸡你太美,它就能把这个东西给显示出来,这是为什么?其实很简单。

·可以看一下,按一下F12,把浏览器的开发者工具给打开。

·然后选中elements标签页,如果是中文版,这里就应该是元素。

·这里有4行文本,这4行文本里面有没有一个比较熟悉的东西?鸡你太美这四个字是不是HTML代码里面写的东西?如果把这个东西改了,鸡你太美baby。

·然后就不再打开HTML文件了,直接按刷新。这里变成了鸡你太美baby,这里是不是也变成了鸡你太美baby。

·再比如加点东西,保存刷新,有没有发现什么规律?这里写什么,这一段就是什么,但其他地方是没变的。

所以有理由相信这份代码的完全体应该是什么?应该就是这个。所以先来把它复刻一下,尖括号。要注意,尖括号得是英文输入法下的尖括号。html,有个had,后面又有一个head,只不过head前面加了一个斜杠。至于这些东西到底是什么意思,等一下再说。

先把代码搞完,鸡左边有个body,后面有个body,下面又有一个斜杠。html好保存,然后刷新,效果和之前的阉割版是一样的。

然后来看一下这些尖括号到底是什么意思,其实还是挺简单的。首先在html里面,像这种用尖括号括起来的东西称之为元素。在国内有的人喜欢把它称为标签,其实都是一个意思,就是元素的意思。所以在这里有几种元素,很明显是三种,一种是html,一种是head,还有一种是body。

这个时候有的小白可能会问了,为什么有的前面是加了个斜杠的?其实是这样子的,在html里面有些元素是有包裹区间的,就比如body元素,body元素里面的数据或者叫内容是从哪到哪?很明显这个是开头,这个是结尾,然后掐头去尾,内容就在这,懂了吧?开头结尾。

所以head元素的数据在哪?就在这,什么都没有。head元素的数据在哪?很明显就是这个。知道元素的概念之后,接下来再看一下这几种元素都是什么意思。

·首先html元素是告诉浏览器,接下来是html代码。

·然后head还有body是什么意思?其实可以把HTML代码想象成是一个人,一个人有自己的头,还有身体,而且人家的脑袋里面此时此刻在想什么是看不出来的。所以head元素里面的内容一般都是去写一些对于页面的一些设置,或者在这个区域里面所看不到的一些东西。

就比如里面可以再加个元素,比如说叫title,title我相信大家应该都知道,就是标题的意思,这个也是一样的,起止。然后中间这里写什么?选项卡的这里名字就是什么?就比如坤坤牛逼,保存,然后刷新,是不是变成了坤坤牛逼?当然,想把这个东西放到别的地方也行,比如说放到body里面,然后保存,一刷新,你看也是坤坤牛逼,对吧?但是一般来说按照规范,一般是放到这种head元素里面去,这是head元素。

·然后接下来是body,body就是人的身体,人家长得什么样子,身材好不好,到底前凸不凸,后翘不翘,一眼就能看得出来,多看一眼都会爆炸的那种。所以在body元素里面,一般都是写一些在这个区域里面能看到的东西,就比如说一些文字或者说一些图片等等,所以这个才是html代码最基本的结构。

·然后回过头来再看一下最初的问题,什么?就是一开始代码不是这个样子的吗?没有,那些head、html、body却依然能在浏览器上正确的显示出来。其实很简单,就是因为虽然就写了这个东西,但是浏览器会读取代码文件里面所写的内容,写了什么就能读到什么。

如果代码不够规范,浏览器就会自动的帮你把这些元素给补齐,补齐完之后才是真正的HTML代码。有了正确的代码之后,浏览器才会根据这份代码来进行渲染,也就是现在所看到的样子。

所以代码千万条,规范第一条,因为永远都不会想知道浏览器到底会对不规范的代码进行什么样的修改,把它改成什么样子。所以html代码的最基本的格式就是html、head、body。修改后的结果:鸡你太美。

文本标记语言

HTML 代表超文本标记语言。它给出了网站或网页的基本结构。它定义了您的网站在结构方面的外观,即网站包含标题、输入、表单、表格、按钮等等。

HTML 代码

<!DOCTYPE html>
<html>
  <head>
    <title>Hello world</title>
  </head>
  <body> 
    <h1>Hello world</h1>
  </body>
</html>


您可以在此处查看 Hello world 网站的实时版本,其代码写在上面。

我们将详细讨论每一行代码,以便您能够了解每一行的想法。

<!DOCTYPE html>

这一行基本上告诉网络浏览器我们正在使用哪个HTML版本。在本例中我们是HTML5

html

这是包含我们网页的所有代码的HTML元素。换句话说,这包含了网页所需的所有结构和设置,即外部 CSS、JS、CDN 等。您可能会注意到所有内容都位于<html>和之间</html>。这是因为这样所有的内容都会在这些元素之间。<html>通常指的是开始标签,</html>通常指的是结束标签。

该元素包含了网页的所有要求。例如,如果您想添加一些外部 CSS 文件、外部 JS 文件或一些外部 CDN(这是网站的要求),那么此元素就会派上用场。如果您不了解 CSS,它用于样式目的,JS 用于功能目的,CDN 代表内容交付网络。

标题

该元素包含显示在Web 浏览器选项卡中的标题。如果您访问 Hello world 网站,您会注意到网络浏览器的选项卡中有标题。这是这些标签的主要工作。Hello world<title>...</title>

身体

该元素包含用户可见的结构。您可以想象到的上述元素可以用于我们网页的设置。主要内容进入正文部分。

h1

h1是用于标题的标题元素。如果您访问 hello world 网站,我们可以看到的 hello world 就是标题。h1不仅仅是我们拥有的标题元素。我们有一个标题元素,从 开始h1,直到 ,h6唯一的区别是h1较大,然后尺寸减小,直到 h6

如果您想了解有关 HTML 元素的更多信息,可以在此处查看。

让我们创建一些表

<table>
  <tr>
    <th>S.No.</th>
    <th>Day</th>
  </tr>
  <tr>
    <td>1</td>
    <td>Sunday</td>
  </tr>
  <tr>
    <td>2</td>
    <td>Monday</td>
  </tr>
  <tr>
    <td>3</td>
    <td>Tuesday</td>
  </tr>
  <tr>
    <td>4</td>
    <td>Wednesday</td>
  </tr>
  <tr>
    <td>5</td>
    <td>Thursday</td>
  </tr>
  <tr>
    <td>6</td>
    <td>Friday</td>
  </tr>
  <tr>
    <td>7</td>
    <td>Saturday</td>
  </tr>
</table>


table:这是用于创建表格的表格元素。
tr:表示表格行。即表的行。
td:表示表数据。即包含该表的数据。

您可以在此处查看代码的实时版本。
注意此代码必须写在body元素之间。

是时候创建 HTML 表单了

当您上网时,您可能见过一些 HTML 表单。让我们来创建我们自己的 HTML 表单。

这是代码片段。

    <form>
        Name: <input type="text" name="name"><br>
        Email: <input type="email" name="email"><br>
        <input type="submit" value="Submit">
    </form>


form:HTML 元素帮助我们创建 HTML 表单。
input:输入元素允许我们获取用户的输入。和称为HTML 属性type="email"name="email"

您可以在此处查看该网页的实时版本。
注意此代码必须写在body元素之间。

结论

总之,HTML 通过定义其结构作为网站或网页的基础。它决定了网站在标题、表单、表格、按钮等元素方面的显示方式。通过使用 HTML 标签和元素,我们可以创建结构良好且组织良好的网页。