Java数据科学指南

978-7-115-48163-4
作者: [加]鲁什迪·夏姆斯(Rushdi Shams)
译者: 武传海
编辑: 胡俊英

图书目录:

详情

本书介绍了关于数据科学模型构建的多种方法,借助Java语言的一些库,例如MLlib、Weka、DL4j等,读者能够更好地完成数据科学任务。本书通过对一些开发技巧的介绍,帮助读者解决一些常见或偶尔的开发中的问题,让读者学到一系列分析、解决问题的办法。

图书摘要

版权信息

书名:Java数据科学指南

ISBN:978-7-115-48163-4

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

著    [加] 鲁什迪•夏姆斯(Rushdi Shams)

译    武传海

责任编辑 胡俊英

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315


Copyright ©2017 Packt Publishing. First published in the English language under the title Java Data Science Cookbook.

All rights reserved.

本书由英国Packt Publishing公司授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式或任何手段复制和传播。

版权所有,侵权必究。


现如今,数据科学已经成为一个热门的技术领域,它涵盖了人工智能的各个方面,例如数据处理、信息检索、机器学习、自然语言处理、数据可视化等。而Java作为一门经典的编程语言,在数据科学领域也有着卓越的表现。

本书旨在通过Java编程来引导读者更好地完成数据科学任务。本书通过9章内容,详细地介绍了数据获取与清洗、索引的建立和检索数据、统计分析、数据学习、信息的提取、大数据处理、深度学习、数据可视化等重要主题。

本书适合想通过Java解决数据科学问题的读者,也适合数据科学领域的专业人士以及普通Java开发者阅读。


Rushdi Shams毕业于加拿大韦仕敦大学,获得了机器学习应用博士学位,主攻方向是自然语言处理(Natural Language Processing,NLP)。在成为机器学习与NLP领域的专家之前,他讲授本科生与研究生课程。在YouTube上,他一直运营着一个名为“跟Rushdi一起学”(Learn with Rushdi)的频道,并且做得有声有色,该频道主要面向想学习计算机技术的朋友。

感谢我的家人、朋友与同事,谢谢你们不断地给予我支持、鼓励,以及中肯的批评与建议。

此外,还要感谢Packt公司的Ajith与Cheryl,谢谢他们自发地与我保持持续的合作关系。


Prashant Verma从2011年就开始了他的IT生涯,当时他是爱立信公司的一名Java开发人员,面向的是电信领域。在有了几年的Java EE开发经验之后,他转战大数据领域,几乎用过所有流行的大数据技术,比如Hadoop、Spark、Kafka、Flume、Mongo、Cassandra等,而且还熟悉Scala与Python编程语言。目前,他供职于QA Infotech公司,是一名首席数据工程师,致力于使用数据分析与机器学习解决E-Learning领域中的问题。

此外,Prashant也是Packt出版的Apache Spark for Java Developers一书的技术审稿人。

首先感谢Packt Publishing给我审阅本书的机会,还要感谢我的雇主、家人,谢谢他们在我忙于审读本书时所表现出的耐心。

谨以此书献给我漂亮的妻子Mah-Zereen与可爱的女儿Ruayda!


当今,数据科学是一个专业化的热门领域,它涵盖人工智能的各个方面,比如数据处理、信息检索、机器学习、自然语言处理、大数据、深度神经网络、数据可视化。在本书中,我们将讲解数据科学领域中既流行又智能的技术,这些技术分散在全书各个章节中,涉及70多个问题。

请记住,目前各个领域对高级数据科学家的需求是非常旺盛的,我们主要使用Java编写了本书各个章节,包括那些使用Java编写的著名的、经典的、最新的数据科学库。首先我们介绍数据采集与清洗流程,而后了解一下如何对所获取的数据建立索引以及进行检索。随后,我们讲解数据的统计描述、统计推断及其应用。接着,安排两个连续的章节讲解面向数据的机器学习应用,这些内容是创建智能系统的基础。除此之外,所讲解的内容还包括现代信息检索与自然语言处理技术。大数据是一个新兴的热门领域,本书内容会涉及其中几个方面。并且,我们还会讲解使用深度神经网络进行深度学习的基础知识。最后,我们学习如何使用有意义的视觉方式或图形表示数据以及从数据中获取的信息。

本书面向的读者是那些对数据科学感兴趣,或者打算应用Java数据科学技术来进一步理解底层数据的朋友。

第1章 “获取数据与清洗数据”,介绍各种读写数据的方法,以及对数据进行清洗去除其中噪声的方法。本章所涉及的数据文件类型广为人知,比如PDF、ASCII、CSV、TSV、XML、JSON。此外,本章还介绍用来提取Web数据的方法。

第2章 “为数据建立索引与搜索数据”,讲解如何使用Apache Lucene为数据建立索引以实现快速检索。本章介绍的技术是现代搜索技术的基础。

第3章 “数据统计分析”,讲解应用Apache Math API进行数据收集乃至分析统计指标的内容。本章还包含一些高级概念,比如统计显著性检验这一标准的工具,科研人员可以通过它将得到的结果与基准数据进行比较。

第4章 “数据学习Ⅰ”,包含使用Weka机器学习库进行分类、聚类、特征选择的内容。

第5章 “数据学习Ⅱ”,本章是前一章的后续内容,讲解使用另一个Java库——Java-ML库进行数据导入导出、分类、特征选择的内容。本章还包含使用斯坦福分类器(Stanford Classifier)与MOA(Massive Online Access)进行基本分类的内容。

第6章 “从文本数据提取信息”,介绍对文本数据应用数据科学技术以提取信息的方法。内容涉及Java核心应用以及OpenNLP、Stanford CoreNLP、Mallet、Weka等著名的机器学习库,学习如何使用它们来完成信息提取与检索任务。

第7章 “处理大数据”,本章涵盖机器学习大数据平台应用的内容,比如Apache Mahout、Spark-MLib。

第8章 “数据深度学习”,包含使用DL4j库进行深度学习的基础内容,介绍word2vec算法、信念网络与自动编码器。

第9章 “数据可视化”,讲解如何使用GRAL包为数据生成具有吸引力的信息展示图表。这个包功能众多,我们只讲解其中最基础的绘图功能。

在本书中,我们使用Java来解决各种实际的数据科学问题。对于那些想了解如何使用Java解决问题的朋友,本书所讲解的内容正是他们所需要的。阅读本书需要你具备最基本的Java知识,比如懂得Java类、对象、方法、实参与形参、异常、导出JAR文件等内容。书中给出的代码都配有相应的讲解、介绍以及提示,这有助于各位读者更好地理解它们。对于书中所解决问题的背后原理,大部分我们都不会进行详细讲解,但必要时我们会提供相应的参考内容,以供感兴趣的读者进一步学习。

如果你想了解如何使用Java解决现实世界中与数据科学相关的问题,那么本书正是为你准备的。在内容覆盖方面,由于本书内容涵盖数据科学的方方面面,因此对于那些正在从事数据学习相关工作,并寻求使用Java解决项目问题的朋友而言,本书也具有十分重要的参考价值。

在本书中,你将经常看到如下几个标题:“准备工作”“操作步骤”“工作原理”“更多内容”“另见”。

对于本书的每一节内容,我们会使用如下几个小标题来组织相关内容。

本部分指出学习本节内容需要做的准备,也包含安装一些必需软件或做一些预先设置的内容。

本部分包含跟学中要做的具体步骤。

本部分通常讲解与前一部分内容相关的更多细节。

本部分讲解与前面内容相关的更多知识,通过阅读本部分内容,让读者掌握更多相关知识。

本部分提供了一些有用的页面链接,从中读者可以获取更多与当前主题相关的有用内容。

在本书中,在不同类型的信息之间,你将看到大量不同的文本类型。下面给出了这些类型的一些示例,并对它们所代表的含义进行了说明。

正文中出现的代码用语、数据表名、文件夹名、文件名、文件扩展名、路径名、虚拟URL、用户输入、推特标签显示如下:“在它们之间,你会发现一个名为lib的文件夹,它就是感兴趣的文件夹。”

代码块设置如下:

    classVals = new ArrayList<String>();      
      for (int i = 0; i < 5; i++){        
        classVals.add("class" + (i + 1));    
    }

命令行输入或输出写成如下形式:

@relation MyRelation 

@attribute age numeric 
@attribute name string 
@attribute dob date yyyy-MM-dd 
@attribute class {class1,class2,class3,class4,class5} 

@data 
35,'John Doe',1981-01-20,class3 
30,'Harry Potter',1986-07-05,class1 

正文中的新术语与关键词以粗体形式标识出来。你在屏幕截图中看到的词,比如在菜单或对话框中,出现在正文中的形式如下:“从Administration面板选择System info”。

警告或重要注释出现在这里


提示与技巧出现在这里


本书由异步社区出品,社区(https://www.epubit.com/)为您提供相关资源和后续服务。

本书提供如下资源:

要获得以上配套资源,请在异步社区本书页面中点击,跳转到下载界面,按提示进行操作即可。注意:为保证购书读者的权益,该操作会给出相关提示,要求输入提取码进行验证。

如果您是教师,希望获得教学配套资源,请在社区本书页面中直接联系本书的责任编辑。

作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,点击“提交勘误”,输入勘误信息,单击“提交”按钮即可。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/selfpublish/submission即可)。

如果您是学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。

“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT技术图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT技术图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近30年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。

社区二维码

服务号二维码


本章涵盖如下内容:

每个数据科学家都需要处理存储在磁盘中的数据,这些数据涉及的格式有ASCII文本、PDF、XML、JSON等。此外,数据还可以存储在数据库表格中。在对数据进行分析之前,数据科学家首先要做的是从这些数据源获取各种格式的数据,并对这些数据进行清洗,去除其中的噪声。本章我们将学习这些内容,即了解如何从不同数据源获取各种格式的数据。

在这一过程中,我们将用到外部Java库(Java归档文件,简称JAR文件),这些库的使用不仅限于本章,还贯穿于整本书。这些库由不同开发者或组织开发,方便了大家的使用。编写代码时,我们会用到Eclipse IDE工具,它是Windows平台下最好的集成开发环境,全书都会使用它。接下来,我们将讲解如何导入任意一个外部JAR文件,以下各个部分将指导你把外部JAR文件导入到项目中,跟随步骤动手去做即可。

对于一个Eclipse项目,你可以采用如下方法添加JAR文件:首先依次单击“Project|Build Path|Configure Build Path”,在Libraries选项卡中,单击“Add External JARs”,选择你想添加到项目的外部JAR文件,如图1-1所示。

图1-1

这部分内容(以及后面各部分内容)是为那些想从复杂目录结构中提取文件路径与名称的数据科学家准备的,以方便进一步进行后续分析。这里的复杂目录结构是指在一个根目录下包含大量目录与文件。

开始之前,需要做如下准备工作。

1.创建复杂的目录结构(目录层数你自己决定)。

2.在其中一些目录中创建文本文件,而在另一些目录中留空。

1.首先编写一个static方法,即listFiles(File rootDir),它带有一个File类型的参数,该参数可以是根目录或起始目录。这个方法将返回一系列文件,这些文件存在于参数所指定的根目录(以及其他所有下级子目录)中。

     public static Set<File> listFiles(File rootDir) {

2.然后,创建一个HashSet对象,用来包含文件信息。

     Set<File> fileSet = new HashSet<File>();

3.在创建好HashSet对象之后,要检查参数指定的根目录及其子目录是否为null。当为null时,直接把HashSet对象返回即可,不需要进行进一步处理。

     if (rootDir == null || rootDir.listFiles() == null){
                  return fileSet;
        }

4.接着,检查根目录中的每个目录(或文件),判断它是文件还是目录。如果是文件,就把它添加到HashSet中;如果是一个目录,就递归地调用本方法,并把当前目录路径与名称传递给它。

     for (File fileOrDir : rootDir.listFiles()) {
                  if (fileOrDir.isFile()){
                    fileSet.add(fileOrDir);
                  }
                  else{
                    fileSet.addAll(listFiles(fileOrDir));
                  }
          }

5.最后,把HashSet返回给该方法的调用者。

     return fileSet;
        }

listFiles(File rootDir)方法的完整代码如下,包含执行该方法所需要的类与驱动方法。

import java.io.File;
import java.util.HashSet;
import java.util.Set;

public class TestRecursiveDirectoryTraversal {
   public static void main(String[] args){
      System.out.println(listFiles(new File("Path for root
          directory")).size());
   }
   public static Set<File> listFiles(File rootDir) {
      Set<File> fileSet = new HashSet<File>();
      if(rootDir == null || rootDir.listFiles()==null){
          return fileSet;
      }
      for (File fileOrDir : rootDir.listFiles()) {
            if (fileOrDir.isFile()){
              fileSet.add(fileOrDir);
            }
            else{
              fileSet.addAll(listFiles(fileOrDir));
            }
      }
      return fileSet; 
   }
}

请注意,代码中的HashSet用来存储文件路径与名称。这意味着我们不会有任何重复项,这是因为Java中的Set这种数据结构不包含重复项。

你可以使用前面一部分演示的操作步骤,采用递归方法把多层目录中的文件名列出来。除此之外,我们还有另外一种更简单、更方便的方法来完成它,那就是使用Apache Commons IO,并且只需编写少量代码即可。

开始之前,需要做如下准备。

1.本部分会用到一个名称为Commons IO的Java库,它来自于Apache基金会。全书中,我们会使用Commons IO 2.5版本,请从Commons官网下载JAR文件。

2.在Eclipse中,把下载的JAR文件包含到你的项目中(作为外部JAR文件)。

1.创建listFiles方法,它带有一个参数,用来指定层级目录的根目录。

     public void listFiles(String rootDir){

2.创建一个文件对象,并把根目录名传递给它。

     File dir = new File(rootDir);

3.Apache Commons库的FileUtils类中包含一个名称为listFiles()方法。使用这个方法提取所有文件名,并且把它们放入一个带有<File>泛型的列表变量中。使用TrueFileFilter.INSTANCE来匹配所有目录。

     List<File> files = (List<File>) FileUtils.listFiles(dir,
       TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);

4.我们可以像下面这样把文件名显示在标准输出中。由于我们把文件名放入了一个列表之中,所以我们可以通过某种方法对这些文件中的数据进行进一步处理。

     for (File file : files) {
        System.out.println("file: " + file.getAbsolutePath());
     }

5.关闭方法。

     }

完整代码包括方法代码、类代码,以及驱动方法,如下所示:

import java.io.File;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter; 

public class FileListing{
   public static void main (String[] args){
      FileListing fileListing = new FileListing();
      fileListing.listFiles("Path for the root directory here");
   }
   public void listFiles(String rootDir){
      File dir = new File(rootDir);

      List<File> files = (List<File>) FileUtils.listFiles(dir,
        TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
      for (File file : files) {
         System.out.println("file: " + file.getAbsolutePath());
      } 
   }

如果你想把带有一些特定扩展名的文件列出来,还可以使用Apache Commons库中的listFiles方法。但是这个方法的参数有些不同,它拥有3个参数,分别为文件目录、扩展名(String[])、递归与否。在这个库中还有一个有趣的方法,即listFilesAndDirs(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter),如果你想把文件与目录全部列出来,可以使用它。

在许多场合下,数据科学家所拥有的数据是文本格式的。我们有很多方法可以用来读取文本文件的内容,这些方法各具优缺点:一些方法执行起来耗时、耗内存,而另一些方法执行速度很快,也不需要消耗太多计算机内存;一些方法可以把全部文本内容一次性读出,而另一些方法则只能一行行地读取文本文件。至于到底要选择哪种方法,则取决于你所面对的任务,以及你决定采用何种方法来处理这个任务。

在这部分中,我们将演示使用Java 8把文本文件的全部内容一次性读出来的方法。

1.首先,创建一个String对象,用来保存待读取的文本文件的目录与名称。

     String file = "C:/dummy.txt";

2.使用Paths类的get()方法,可以得到待读文件的路径。get()方法的参数是String对象,用来指定文件名,它的输出作为lines()方法的输入。lines()方法包含于Files类之中,用来读取一个文件的所有行,并且返回Stream,也就是说,这个方法的输出定向到一个Stream变量。因为我们的dummy.txt文件中包含字符串数据,所以把Stream变量的泛型设置为String

整个读取过程需要放入一个try...catch块中,用来应对读取过程中可能发生的异常,比如当试图读取的文件不存在或已损坏时,就会抛出异常。

下面代码用来把dummy.txt文件中的内容全部显示出来。在stream变量中包含着文本文件的所有行,所以需要使用它的forEach()方法显示出每行内容。

   try (Stream<String> stream = Files.lines(Paths.get(file))) {
   stream.forEach(System.out::println); } catch (IOException e) {
   System.out.println("Error reading " + file.getAbsolutePath());
   }

在上一节中我们学习了使用Java8从文本文件中一次性读取所有内容,其实我们也可以使用Apache Commons IO API一次性读取文本文件的所有内容。

开始之前,需要做如下准备。

1.本部分,我们会用到一个名为Apache Commons IO的Java库。

2.在Eclipse中,把下载好的JAR文件包含到你的项目中。

1.假设你要读取的文件为dummy.txt,它位于C:/目录之下。首先,需要创建一个文件对象,用来访问这个文件,如下所示:

     File file = new File("C:/dummy.txt");

2.接着,创建一个字符串对象,用来保存文件中的文本内容。这里我们要使用readFileToString()方法,它来自于Apache Commons IO库,是FileUtils类的一个成员方法。调用这个方法的方式有很多,但是现在,你只需知道我们要传递两个参数给它,第一个参数是file对象,用来指定要读取的文件,第二个参数是文件的编码,在示例中,我们将其设置为UTF-8

     String text = FileUtils.readFileToString(file, "UTF-8");

3.只要使用上面两行代码,我们就可以读取文本文件内容,并将它们存入一个String变量中。但是,你可不是一个普通的数据科学家,你比其他人要聪明得多。所以,你在上面两行代码的前后又添加了几行代码,用来处理Java方法抛出的异常,比如你试图读取的文件不存在或者已经损坏,就会触发异常。为此,我们需要把上面两行代码放入到一个try...catch块之中,如下所示:

     File file = new File("C:/dummy.txt");
     try {
     String text = FileUtils.readFileToString(file, "UTF-8");
     } catch (IOException e) {
     System.out.println("Error reading " + file.getAbsolutePath());
     }

在解析与提取数据时,最难搞的文件类型之一是PDF文件。有些PDF文件甚至无法解析,因为它们有密码保护,而其他一些则包含着扫描的文本与图像。所以,这种动态文件类型有时会成为数据科学家的梦魇。本部分演示如何使用Apache Tika从PDF文件提取文本,当然前提是PDF文件没有被加密,也没有密码保护,而只包含非扫描的文本。

开始之前,需要先做如下准备。

1.下载Apache Tika 1.10 JAR文件,并且将其作为外部Java库包含到你的Eclipse项目中。

2.把任意一个未锁定的PDF文件保存到C:/目录之下,并且命名为testPDF.pdf

1.创建一个名称为convertPdf(String)的方法,它带有一个字符串参数,用来指定PDF文件名称。

     public void convertPDF(String fileName){

2.创建一个输入流,用来以字节流的形式包含PDF数据。

     InputStream stream = null;

3.创建一个try块,如下所示:

     try{

4.把文件指派给刚刚创建好的stream

     stream = new FileInputStream(fileName);

5.在Apache Tika包中包含着许多不同的解析器。如果你不知道该选用哪一个,或者说你还有其他类型的文档需要转换,那么你应该使用AutoDetectParser解析器,如下所示:

     AutoDetectParser parser = new AutoDetectParser();

6.创建一个handler,用来处理文件的正文内容。请注意,创建时需要把构造函数的参数设为-1。通常,Apache Tika会对处理的文件进行限制,要求它至多包含100 000个字符。使用-1让这个handler忽略这个限制。

     BodyContentHandler handler = new BodyContentHandler(-1);

7.创建一个metadata对象。

     Metadata metadata = new Metadata();

8.调用解析器对象的parser()方法,并把上面创建的这些对象传递给它。

     parser.parse(stream, handler, metadata, new ParseContext());

9.使用handler对象的tostring()方法,获取从文件中提取的正文文本。

     System.out.println(handler.toString());

10.关闭try块,并且添加catchfinally块。最后,关闭整个方法,如下所示:

     }catch (Exception e) {
                   e.printStackTrace();
              }finally {
                  if (stream != null)
                       try {
                            stream.close();
                       } catch (IOException e) {
                         System.out.println("Error closing stream");
                       }
                  }
     }

下面代码包含convertPdf(String)方法的完整代码,以及相应的类与驱动方法。在调用convertPdf(String)方法时,你需要提供待转换的PDF文件的路径与名称,即把该方法的参数指定为C:/testPDF.pdf

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.BodyContentHandler;

public class TestTika {
     public static void main(String args[]) throws Exception {
          TestTika tika = new TestTika();
          tika.convertPdf("C:/testPDF.pdf");
     }
     public void convertPdf(String fileName){
          InputStream stream = null;
          try {
              stream = new FileInputStream(fileName);
              AutoDetectParser parser = new AutoDetectParser();
              BodyContentHandler handler = new BodyContentHandler(-1);
              Metadata metadata = new Metadata();
              parser.parse(stream, handler, metadata, new
                  ParseContext());
              System.out.println(handler.toString());
          }catch (Exception e) {
              e.printStackTrace();
          }finally {
              if (stream != null)
                   try {
                        stream.close();
                   } catch (IOException e) {
                        System.out.println("Error closing stream");
                   }
          }
     }
}

ASCII文本文件中通常会包含一些非必要的字符,这些字符通常产生于转换过程中,比如把PDF转换为文本或把HTML转换为文本的过程中。并且,这些字符常常被看作噪声,它们是数据处理的主要障碍之一。本部分,我们学习使用正则表达式为ASCII文本数据清洗一些噪声的方法。

1.创建一个名为cleanText(String)的方法,它带有一个String类型的参数,用来指定要清洗的文本。

     public String cleanText(String text){

2.在你的方法中,添加如下几行代码,而后把清洗后的文本返回,并关闭方法。在如下代码中,第一行代码用来去掉非ASCII字符,紧接的一行用来把连续的空格字符替换为单个空格字符。第三行用来清除所有ASCII控制字符。第四行用来去除ASCII非打印字符。最后一行用来从Unicode移除非打印字符。

     text = text.replaceAll("[^p{ASCII}]","");
     text = text.replaceAll("s+", " ");
     text = text.replaceAll("p{Cntrl}", "");
     text = text.replaceAll("[^p{Print}]", "");
     text = text.replaceAll("p{C}", "");

     return text; 
     }

以下代码是方法的完整代码,包含相应类与驱动方法。

public class CleaningData {
   public static void main(String[] args) throws Exception {
      CleaningData clean = new CleaningData();
      String text = "Your text here you have got from some file";
      String cleanedText = clean.cleanText(text);
      //清洗文本处理
   }
   public String cleanText(String text){
      text = text.replaceAll("[^p{ASCII}]","");
        text = text.replaceAll("s+", " ");
        text = text.replaceAll("p{Cntrl}", "");
        text = text.replaceAll("[^p{Print}]", "");
        text = text.replaceAll("p{C}", "");
        return text;
   }
}

对数据科学家来说,另一种经常处理的文件格式是CSV(逗号分隔)文件,在这种文件中数据之间通过逗号进行分隔。CSV文件非常流行,因为大部分电子表格应用程序都可以读取它,比如MS Excel。

本部分,我们将学习解析CSV文件,以及处理所提取的数据点的方法。

开始之前,需要先做如下准备。

1.下载Univocity JAR文件,并将其作为外部库添加到你的Eclipse项目中。

2.使用Notepad创建一个CSV文件,它包含如下数据。创建好之后,把文件的扩展名修改为.csv,并把它保存到C盘之下,即C:/testCSV.csv

     Year,Make,Model,Description,Price
     1997,Ford,E350,"ac, abs, moon",3000.00
     1999,Chevy,"Venture ""Extended Edition""","",4900.00
     1996,Jeep,Grand Cherokee,"MUST SELL!
     air, moon roof, loaded",4799.00
     1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
     ,,"Venture ""Extended Edition""","",4900.00

1.创建一个名为parseCsv(String)的方法,它带有一个String类型的参数,用来指定待解析的文件名。

     public void parseCsv(String fileName){

2.而后创建一个配置对象,该对象用来提供多种配置选项。

     CsvParserSettings parserSettings = new CsvParserSettings();

3.借助于配置对象,你可以打开解析器的自动检测功能,让它自动侦测输入中包含何种行分隔符序列。

     parserSettings.setLineSeparatorDetectionEnabled(true);

4.创建一个RowListProcessor对象,用来把每个解析的行存储在列表中。

RowListProcessor rowProcessor = new RowListProcessor();

5.你可以使用RowProcessor来配置解析器,以对每个解析行的值进行处理。你可以在com.univocity.parsers.common.processor包中找到更多RowProcessors,但是你也可以自己创建。

     parserSettings.setRowProcessor(rowProcessor);

6.如果待解析的CSV文件包含标题头,你可以把第一个解析行看作文件中每个列的标题。

     parserSettings.setHeaderExtractionEnabled(true);

7.接下来,使用给定的配置创建一个parser实例。

     CsvParser parser = new CsvParser(parserSettings);

8.parser实例的parse()方法用来解析文件,并把每个经过解析的行指定给前面定义的RowProcessor

     parser.parse(new File(fileName));

9.如果解析中包含标题,则可使用如下代码获取这些标题。

     String[] headers = rowProcessor.getHeaders();

10.随后,你可以很容易地处理这个字符串数组,以获取这些标题值。

11.另一方面,我们在列表中可以找到行值。只要使用一个for循环即可把列表打印出来,如下所示。

     List<String[]> rows = rowProcessor.getRows();
     for (int i = 0; i < rows.size(); i++){
        System.out.println(Arrays.asList(rows.get(i)));
     }

12.最后,关闭方法。

     }

整个方法的完整代码如下所示:

import java.io.File;
import java.util.Arrays;
import java.util.List;

import com.univocity.parsers.common.processor.RowListProcessor;
import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;

public class TestUnivocity {
      public void parseCSV(String fileName){
          CsvParserSettings parserSettings = new CsvParserSettings();
          parserSettings.setLineSeparatorDetectionEnabled(true);
          RowListProcessor rowProcessor = new RowListProcessor();
          parserSettings.setRowProcessor(rowProcessor);
          parserSettings.setHeaderExtractionEnabled(true);
          CsvParser parser = new CsvParser(parserSettings);
          parser.parse(new File(fileName));

          String[] headers = rowProcessor.getHeaders();
          List<String[]> rows = rowProcessor.getRows();
          for (int i = 0; i < rows.size(); i++){
            System.out.println(Arrays.asList(rows.get(i)));
          }
     }
     public static void main(String[] args){
        TestUnivocity test = new TestUnivocity();
        test.parseCSV("C:/testCSV.csv");
     } 
}

有很多采用Java编写的CSV解析器。但是,相比较而言,Univocity是执行速度最快的一个。

不同于CSV文件,TSV(制表符分隔)文件中所包含的数据通过TAB制表符进行分隔。本部分,我们将学习使用Univocity从TSV文件提取数据点的方法。

开始之前,先做如下准备工作。

1.下载Univocity JAR文件,并将其作为外部库包含到你的Eclipse项目中。

2.使用Notepad创建一个TSV文件,它包含如下数据。创建好之后,把文件的扩展名修改为.tsv,并把它保存到C盘之下,即C:/testTSV.tsv

Year   Make    Model   Description Price
1997   Ford    E350    ac, abs, moon   3000.00
1999   Chevy   Venture "Extended Edition"      4900.00
1996   Jeep    Grand Cherokee  MUST SELL!nair, moon roof, loaded 4799.00
1999   Chevy   Venture "Extended Edition, Very Large"      5000.00
       Venture "Extended Edition"      4900.00

1.创建一个名称为parseTsv(String)的方法,它带有一个String类型的参数,用来指定待解析的文件名。

     public void parseTsv(String fileName){

2.本部分中TSV文件的行分隔符为换行符或n。为了把字符n设置为行分隔符,修改设置如下所示。

     settings.getFormat().setLineSeparator("n");

3.使用这些设置,创建一个TSV解析器。

     TsvParser parser = new TsvParser(settings);

4.使用如下代码,把TSV文件中的所有行一次性解析出来。

     List<String[]> allRows = parser.parseAll(new File(fileName));

5.遍历列表对象,打印或处理数据行,代码如下所示。

     for (int i = 0; i < allRows.size(); i++){
              System.out.println(Arrays.asList(allRows.get(i))); 
            {

6.最后,关闭方法。

     }

下面代码中包含整个方法的完整代码,以及相应类与驱动方法。

import java.io.File;
import java.util.Arrays;
import java.util.List;

import com.univocity.parsers.tsv.TsvParser;
import com.univocity.parsers.tsv.TsvParserSettings;

public class TestTsv {
   public void parseTsv(String fileName){
       TsvParserSettings settings = new TsvParserSettings();
       settings.getFormat().setLineSeparator("n");
       TsvParser parser = new TsvParser(settings);
       List<String[]> allRows = parser.parseAll(new File(fileName));
       for (int i = 0; i < allRows.size(); i++){
         System.out.println(Arrays.asList(allRows.get(i)));
       }
    }
}

通常,文本数据是没有结构的,不同于文本数据,在XML文件中的数据是具有结构的。XML是组织数据的一种流行方式,借助它,我们可以非常方便地准备、传递以及利用数据。有很多方法可以用来解析XML文件的内容。本书中,我们将学习使用一个名为JDOM的Java库来解析XML文件。

开始之前,先做如下准备工作。

1.下载JDOM 2.06版本(JAR文件)。

2.在Eclipse中,创建一个项目,并把上面下载的JAR文件作为外部JAR文件包含进去。

3.打开notepad,新建一个名称为dummyxml的文件,文件扩展名为.xml,文件包含的内容简单如下:

     <?xml version="1.0"?>
     <book>
        <author>
           <firstname>Alice</firstname>
           <lastname>Peterson</lastname>
        </author>
        <author>
           <firstname>John</firstname>
           <lastname>Doe</lastname>
        </author>
      </book>

1.创建一个名称为builderSAXBuilder对象。

     SAXBuilder builder = new SAXBuilder();

2.接下来,你需要创建一个File对象,用来指向待解析的XML文件。如果你已经把XML文件保存到C盘之下,则将其放入如下代码片段中。

     File file = new File("c:/dummyxml.xml");

3.在try语句块中,需要创建一个Document对象,它表示你的XML文件。

     try {
       Document document = (Document) builder.build(file);

4.在解析呈现树状结构的XML文件时,需要知道文件的根元素,以便开始遍历整个树(换言之,开始进行系统的解析)。因此,需要创建一个Element类型的rootNode对象,用来保存根元素,在我们的示例中,它对应于<book>节点。

     Element rootNode = document.getRootElement();

5.接着,获取根节点下所有名称为author的子节点。由于调用getChildren()方法所得到的是子节点列表,所以还需要有一个列表变量来存储它们。

     List list = rootNode.getChildren("author");

6.然后,使用for循环遍历整个子节点列表,以获取列表中的项目元素。每个元素都存储在Element类型的node变量中。这个变量有一个名称为getChildText()的方法,其参数为子元素名称,返回子元素的文本内容,如果指定的子元素不存在,就返回null。这个方法用起来非常方便,因为调用getChild().getText()可能会抛出NullPointerException异常。

     for (int i = 0; i < list.size(); i++) {
        Element node = (Element) list.get(i);
     System.out.println("First Name : " +
       node.getChildText("firstname"));
     System.out.println("Last Name : " +
       node.getChildText("lastname"));
     }

7.最后,关闭try语句块,并添加如下catch语句块处理可能遇到的异常。

     } catch (IOException io) {
           System.out.println(io.getMessage());
     } catch (JDOMException jdomex) {
           System.out.println(jdomex.getMessage());
     }

完整代码如下:

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

public class TestJdom {

   public static void main(String[] args){
      TestJdom test = new TestJdom();
      test.parseXml("C:/dummyxml.com");
   }
   public void parseXml(String fileName){
      SAXBuilder builder = new SAXBuilder();
      File file = new File(fileName);
      try {
         Document document = (Document) builder.build(file);
         Element rootNode = document.getRootElement();
         List list = rootNode.getChildren("author");
         for (int i = 0; i < list.size(); i++) {
            Element node = (Element) list.get(i);
            System.out.println("First Name : " +
                node.getChildText("firstname"));
            System.out.println("Last Name : " +
                node.getChildText("lastname"));
         }
      } catch (IOException io) {
         System.out.println(io.getMessage());
      } catch (JDOMException jdomex) {
         System.out.println(jdomex.getMessage());
      }
   }
}

XML解析器类型多样,每种解析器都各有优点。Dom Parser。这种解析器会把文档的完整内容加载到内存中,并在内存中创建自己的层次树。SAX Parser:这种解析器不会把整个文档全部加载到内存中,文档的解析基于事件触发。JDOM Parser:JDOM解析器采用类似DOM解析器的方式解析文档,但是更加便捷。StAX Parser:这种解析器采用类似于SAX解析器的方式处理文档,但是效率更高。XPath Parser:这类解析器基于路径表达式来解析文档,经常与XSLT一起使用。DOM4J Parser:这是一个使用Java集合框架(该框架提供了对DOM、SAX、JAXP的支持)来解析XML、XPath、XSLT的Java库。

类似于XML文件,JSON也是一种人类可读的轻量级数据交换格式。JSON是JavaScript Object Notation(JavaScript对象表示法)的首字母缩写。JSON正成为一种由现代Web应用程序所生成与解析的流行格式。本部分中,我们将学习如何编写JSON文件。

开始之前,先做如下准备工作。

下载json-simple-1.1.1.jar,并将其作为外部库添加到你的Eclipse项目中。

1.创建一个名称为writeJson(String outFileName)的方法,它带有一个String类型参数,用来指定要生成的JSON文件名。本节我们将创建它,并与JSON信息一起输出。

2.创建一个JSON对象,使用它的put()方法,添加几个字段,比如图书与作者。下面代码用来创建一个JSON对象,然后添加书名及其作者名字。

     JSONObject obj = new JSONObject();
       obj.put("book", "Harry Potter and the Philosopher's Stone");
       obj.put("author", "J. K. Rowling");

3.接着,假设针对这本书有3个书评。我们可以把它们一起放入一个JSON数组中,具体操作如下:首先,我们使用数组对象的add()方法添加评论,当把所有评论添加到数组之后,我们再把数组添加到上一步所创建的JSON对象。

JSONArray list = new JSONArray();

list.add("There are characters in this book that will remind us of all the
people we have met. Everybody knows or knew a spoilt, overweight boy like
Dudley or a bossy and interfering (yet kind-hearted) girl like Hermione");
list.add("Hogwarts is a truly magical place, not only in the most obvious
way but also in all the detail that the author has gone to describe it so
vibrantly.");
list.add("Parents need to know that this thrill-a-minute story, the first
in the Harry Potter series, respects kids' intelligence and motivates them
to tackle its greater length and complexity, play imaginative games, and
try to solve its logic puzzles. ");

obj.put("messages", list);

4.接下来,我们把JSON对象中的信息写入到一个输出文件中,后面我们将使用这个文件演示如何读取与解析JSON文件。下面的try...catch代码块用来把信息写到JSON文件。

     try {
              FileWriter file = new FileWriter("c:test.json");
              file.write(obj.toJSONString());
              file.flush();
              file.close();

     } catch (IOException e) {
              //your message for exception goes here.
     }

5.我们也可以把JSON对象的内容显示在标准的输出中,如下所示。

     System.out.print(obj);

6.最后,关闭方法。

     }

完整代码如下,包括writeJson()方法的全部代码,以及相应类与用于调用writeJson()方法的驱动方法(main方法),代码执行后会生成一个JSON文件。

import java.io.FileWriter;
import java.io.IOException;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

public class JsonWriting {

   public static void main(String[] args) {
      JsonWriting jsonWriting = new JsonWriting();
      jsonWriting.writeJson("C:/testJSON.json");
   }

   public void writeJson(String outFileName){
      JSONObject obj = new JSONObject();
      obj.put("book", "Harry Potter and the Philosopher's Stone");
      obj.put("author", "J. K. Rowling");

      JSONArray list = new JSONArray();
      list.add("There are characters in this book that will remind us
        of all the people we have met. Everybody knows or knew a
          spoilt, overweight boy like Dudley or a bossy and interfering
            (yet kind-hearted) girl like Hermione");
      list.add("Hogwarts is a truly magical place, not only in the most
        obvious way but also in all the detail that the author has gone
          to describe it so vibrantly.");
      list.add("Parents need to know that this thrill-a-minute story,
        the first in the Harry Potter series, respects kids'
          intelligence and motivates them to tackle its greater length
            and complexity, play imaginative games, and try to solve
              its logic puzzles. ");

      obj.put("messages", list);

     try {

         FileWriter file = new FileWriter(outFileName);
         file.write(obj.toJSONString());
         file.flush();
         file.close();

      } catch (IOException e) {
         e.printStackTrace();
      }

      System.out.print(obj); 
   }
}

在输出文件中将包含如下数据。请注意,这里为了增加可读性,我们对输出的结果进行了一些调整,实际输出的是一大段纯文本。

{
"author":"J. K. Rowling",
"book":"Harry Potter and the Philosopher's Stone",
"messages":[
         "There are characters in this book that will remind us of all the
people we have met. Everybody knows or knew a spoilt, overweight boy like
Dudley or a bossy and interfering (yet kind-hearted) girl like Hermione",
         "Hogwarts is a truly magical place, not only in the most obvious
way but also in all the detail that the author has gone to describe it so
vibrantly.",
         "Parents need to know that this thrill-a-minute story, the first
in the Harry Potter series, respects kids' intelligence and motivates them
to tackle its greater length and complexity, play imaginative games, and
try to solve its logic puzzles."
         ] 
}

在本部分,我们将学习读取或解析JSON文件的方法。在这里,我们将使用上一小节创建的JSON文件作为待读取或解析的文件。

开始之前,先做如下准备。

根据上一小节的操作步骤,创建一个JSON文件,里面包含图书名称、作者与书评信息。我们将使用这个文件来学习解析与读取JSON文件的方法。

1.在读取或解析JSON文件之前,我们需要先创建一个JSON解析器。

     JSONParser parser = new JSONParser();

2.接着,在try语句块中,把书名与作者字段的值提取出来。在此之前,需要先使用解析器的parse()方法读取JSON文件。parse()方法会把文件内容作为一个Object返回。因此,我们需要一个Object类型的变量来保存文件内容。然后,把object指派给一个JSON对象,以便进行进一步处理。请注意,在把object指派给JSON对象时,需要进行类型转换处理。

     try { 
       Object obj = parser.parse(new FileReader("c:test.json"));
       JSONObject jsonObject = (JSONObject) obj;

       String name = (String) jsonObject.get("book");
       System.out.println(name);

       String author = (String) jsonObject.get("author");
       System.out.println(author);
     }

3.接下来需要从JSON对象提取的字段是评论字段,它是一个数组。我们需要使用如下代码对数组进行遍历。

     JSONArray reviews = (JSONArray) jsonObject.get("messages");
       Iterator<String> iterator = reviews.iterator();
       while (iterator.hasNext()) {
          System.out.println(iterator.next());
     }

4.最后,添加catch语句块,处理解析期间可能遇到的3种异常,然后关闭方法。

     } catch (FileNotFoundException e) {
              //你的异常处理代码
           } catch (IOException e) {
              //你的异常处理代码
           } catch (ParseException e) {
              //你的异常处理代码
           }
      }

完整代码整理如下,包括完整的方法代码、相应类,以及驱动方法。

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

public class JsonReading {
   public static void main(String[] args){
      JsonReading jsonReading = new JsonReading();
      jsonReading.readJson("C:/testJSON.json");
   }
   public void readJson(String inFileName) {
      JSONParser parser = new JSONParser();
      try {
         Object obj = parser.parse(new FileReader(inFileName));
         JSONObject jsonObject = (JSONObject) obj;

         String name = (String) jsonObject.get("book");
         System.out.println(name);

         String author = (String) jsonObject.get("author");
         System.out.println(author);

         JSONArray reviews = (JSONArray) jsonObject.get("messages");
         Iterator<String> iterator = reviews.iterator();
         while (iterator.hasNext()) {
            System.out.println(iterator.next());
         }
      } catch (FileNotFoundException e) {
         //Your exception handling here
      } catch (IOException e) {
         //Your exception handling here
      } catch (ParseException e) {
         //Your exception handling here
      }
   }
}

上面的代码正常运行之后,你会在标准输出中看到JSON文件的内容。

当今,大量数据存在于Web上。在这些数据中,有些是带有结构的,有些是半结构化的,有些是不带结构的。因此,需要不同的技术来从Web上提取它们。有很多方法可以用来提取Web数据。其中,最简单易用的一种是使用一个名称为JSoup的外部Java库。本部分,我们将学习使用JSoup提供的一些方法来提取Web数据。

开始之前,先做如下准备工作。

1.下载jsoup-1.9.2.jar文件,并把下载到的JAR文件作为外部库添加到你的Eclipse项目中。

2.如果你喜欢使用Maven,请根据下载页面中的操作提示,把JAR文件添加到你的Eclipse项目中。

1.创建一个名称为extractDataWithJsoup(String url)的方法。调用该方法时,你需要提供给它一个Web地址作为参数。这样,我们就可以从这个URL提取Web数据了。

     public void extractDataWithJsoup(String href){

2.调用JSoup的connect()方法,并把要连接的URL地址(从该地址提取数据)传递给它。紧随其后,接连调用其他几个方法。首先是timeout()方法,带有的参数为毫秒,接下来的两个方法分别定义了连接期间的用户代理名称,以及指定是否忽略连接错误。紧接着这两个方法调用的是get()方法,它返回一个Document对象。因此,我们需要事先声明一个Document类型的doc变量来保存get()方法所返回的Document对象。

     doc =
       Jsoup.connect(href).timeout(10*1000).userAgent
         ("Mozilla").ignoreHttpErrors(true).get();

3.由于这段代码可能会抛出IOException异常,所以我们要把它放入一个try...catch语句块之中,如下所示:

     Document doc = null;
     try {
      doc = Jsoup.connect(href).timeout(10*1000).userAgent
        ("Mozilla").ignoreHttpErrors(true).get();
        } catch (IOException e) {
           //你的异常处理代码
     }

由于我们不习惯于使用毫秒来计算时间,因此在代码中需要把毫秒作为时间单位时,一个更好的做法是把时间写成10×1 000的形式,即10秒。这样做,可以进一步提高代码的可读性。

4.Document对象提供了大量用于提取数据的方法。如果你想提取URL的标题,你可以使用title()方法,如下所示:

     if(doc != null){
      String title = doc.title();

5.如果你只想从Web页面中提取正文文本的内容,你可以接连调用Document对象的body()text()方法,如下所示:

     String text = doc.body().text();

6.如果你想从URL中提取所有超链接,你可以使用Document对象的select()方法,并把a[href]作为参数提供给它。这样,你就可以一次性获取所有链接。

     Elements links = doc.select("a[href]");

7.或许你想分别处理Web页面中的链接,这也很容易办到。你只需要遍历所有链接,获取各个链接即可。

     for (Element link : links) {
         String linkHref = link.attr("href");
         String linkText = link.text();
         String linkOuterHtml = link.outerHtml();
         String linkInnerHtml = link.html();
     System.out.println(linkHref + "t" + linkText + "t" +
       linkOuterHtml + "t" + linkInnterHtml);
     }

8.最后,结束if条件语句,并关闭方法。

     } 
     }

完整代码整理如下,包括完整的方法代码、相应类,以及驱动方法。

import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class JsoupTesting {
   public static void main(String[] args){
      JsoupTesting test = new JsoupTesting();
      test.extractDataWithJsoup("Website address preceded by http://");
   }

   public void extractDataWithJsoup(String href){
      Document doc = null;
      try {
         doc = Jsoup.connect(href).timeout(10*1000).userAgent
             ("Mozilla").ignoreHttpErrors(true).get();
      } catch (IOException e) {
         //Your exception handling here
      }
      if(doc != null){
         String title = doc.title();
         String text = doc.body().text();
         Elements links = doc.select("a[href]");
         for (Element link : links) {
            String linkHref = link.attr("href");
            String linkText = link.text();
            String linkOuterHtml = link.outerHtml();
            String linkInnerHtml = link.html();
            System.out.println(linkHref + "t" + linkText + "t" +
                linkOuterHtml + "t" + linkInnterHtml);
         }
      }
   }
}

Selenium是一个基于Java的工具,用来进行自动软件测试或质量控制。有趣的是,Selenium也可以用来自动提取与利用Web数据。本部分,我们将学习如何使用它。

开始之前,先做如下准备。

1.下载selenium-server-standalone-2.53.1.jarseleniumjava-2.53.1. zip。从后者提取selenium-java-2.53.1.jar文件。把这两个JAR文件作为外部Java库添加到你的Eclipse项目中。

2.下载并安装Firefox 47.0.1。注意选择与自身操作系统相对应的版本。

由于Selenium与Firefox之间存在版本冲突问题,当你使用某个特定版本运行代码时,请记得把Firefox的自动下载更新与安装选项关闭。

1.创建一个名称为extractDataWithSelenium(String)的方法,它带有一个String类型的参数,用来指定等待提取数据的URL地址。我们可以从URL提取的数据类型多种多样,比如标题、头部,以及下拉选择框中的值。本部分,我们将只讲解如何提取Web页面中的文本部分。

     public String extractDataWithSelenium(String url){

2.接着,使用如下代码创建一个Firefox Web驱动器。

     WebDriver driver = new FirefoxDriver();

3.调用WebDriver对象的get()方法,并把URL地址传递给它。

     driver.get("http://cogenglab.csd.uwo.ca/rushdi.htm");

4.我们可以使用xpath查看网页文本,其中id的值就是内容,如图1-2和图1-3所示。

图1-2

图1-3

5.调用findElement()方法找到这个特定元素,并且返回一个WebElement对象。创建一个名称为webElementWebElement对象来保存这个返回值。

     WebElement webElement = driver.findElement(By.xpath("/­/­*
       [@id='content']"));

6.WebElement对象有一个名为getText()的方法。调用这个方法,获取Web页面中的文本,并把文本放入一个String类型的变量中,如下所示:

     String text = (webElement.getText());

7.最后,返回String变量,关闭方法。

     }

完整代码整理如下,包括完整的方法代码、相应类,以及main()驱动方法。

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class TestSelenium {
   public String extractDataWithSelenium(String url) {
      WebDriver driver = new FirefoxDriver();
      driver.get("http://cogenglab.csd.uwo.ca/rushdi.htm");
      WebElement webElement = driver.findElement(By.xpath("//­*
        [@id='content']"));
      System.out.println(webElement.getText());
      return url;
   }

   public static void main(String[] args){
      TestSelenium test = new TestSelenium();
      String webData = test.extractDataWithSelenium
        ("http://cogenglab.csd.uwo.ca/rushdi.htm");
      //process webData
   }
}

Selenium与Firefox之间存在兼容性的问题。有些版本的Selenium无法与某些版本的Firefox协同工作。上面讲解中所使用的Selenium与Firefox版本能够很好地协同工作,但是这并不能保证示例代码在其他版本的Selenium与Firefox上也能正常工作。

由于Selenium与Firefox之间存在版本冲突问题,当你使用某个特定版本运行代码时,请记得把Firefox的自动下载更新与安装选项关闭。

数据也可能存储在数据库的表格中。本部分,我们将演示如何从MySQL的数据表中读取数据。

开始之前,先做如下准备。

1.下载并安装MySQL community server。本部分使用的是MySQL 5.7.15版本。

2.创建一个名称为data_science的数据库。在这个数据库中,创建一个名称为books的数据表,包含如图1-4所示的数据。

图1-4

本部分中字段类型是什么并不重要,但是字段名称必须与上表给出的那些完全一样。

3.下载独立于平台的MySQL JAR文件,并将其作为外部库添加到你的Java项目中。这里使用的是5.1.39版本。

1.创建一个名为readTable(String user, String password, String server)的方法,带有的3个参数分别是用户名、密码,以及你的MySQL数据库的服务器名称。

     public void readTable(String user, String password, String
       server){

2.创建一个MySQL数据源,并且通过这个数据源,设置用户名、密码与服务器名。

     MysqlDataSource dataSource = new MysqlDataSource();
       dataSource.setUser(user);
       dataSource.setPassword(password);
       dataSource.setServerName(server);

3.在try语句块中,创建数据库连接。通过这个连接,创建一条语句,用来执行SELECT查询,以便从数据表中获取信息。返回的查询结果将存储在结果集中。

     try{
       Connection conn = dataSource.getConnection();
       Statement stmt = conn.createStatement();
       ResultSet rs = stmt.executeQuery("SELECT * FROM
       data_science.books");

4.接着,遍历结果集,通过指定列名提取每个列。请注意,在使用相应方法提取列值之前,需要事先知道每个列字段的数据类型。比如,由于我们知道ID字段的数据类型是整型,所以我们可以选用getInt()方法来获取它。

     while (rs.next()){
       int id = rs.getInt("id");
       String book = rs.getString("book_name");
       String author = rs.getString("author_name");
       Date dateCreated = rs.getDate("date_created");
       System.out.format("%s, %s, %s, %sn", id, book, author,
         dateCreated);
     }

5.遍历结束后,关闭结果集、查询语句与连接。

     rs.close();
       stmt.close();
       conn.close();

6.在从数据表读取数据过程中可能会出现异常,使用catch语句对可能出现的异常进行处理。最后关闭方法。

     }catch (Exception e){
        // 你的异常处理代码
       }
     }

完整代码整理如下,包括完整的方法代码、相应类,以及驱动方法。

import java.sql.*;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
public class TestDB{
     public static void main(String[] args){
          TestDB test = new TestDB();
          test.readTable("your user name", "your password", "your MySQL
              server name");
     }
     public void readTable(String user, String password, String server)
         {
         MysqlDataSource dataSource = new MysqlDataSource();
         dataSource.setUser(user);
         dataSource.setPassword(password);
         dataSource.setServerName(server);
         try{
              Connection conn = dataSource.getConnection();
              Statement stmt = conn.createStatement();
              ResultSet rs = stmt.executeQuery("SELECT * FROM
                  data_science.books");
              while (rs.next()){
                   int id = rs.getInt("id");
                   String book = rs.getString("book_name");
                   String author = rs.getString("author_name");
                   Date dateCreated = rs.getDate("date_created");
                   System.out.format("%s, %s, %s, %sn", id, book,
                       author, dateCreated);
               }
               rs.close();
               stmt.close();
               conn.close();
          }catch (Exception e){
               //这里是你的异常处理代码
          }
     }
}

上面的代码正常执行之后,将会把数据表中的数据显示出来。


相关图书

Python数据科学实战
Python数据科学实战
数据分析实战:方法、工具与可视化
数据分析实战:方法、工具与可视化
Power BI数据挖掘与可视化分析
Power BI数据挖掘与可视化分析
从0到1——Python数据可视化
从0到1——Python数据可视化
善用图表——一看就懂的商业数据表达术
善用图表——一看就懂的商业数据表达术
从Power BI 到 Power Platform:低代码应用开发实战
从Power BI 到 Power Platform:低代码应用开发实战

相关文章

相关课程