这里我们继续上篇的内容,完善如何将爬取的数据插入到数据库中,并对前边所提到的推荐量问题做一下视觉上的更改。

先写一个对推荐量的类型转换类:

package com.qiku.util;public class SpiderUtil {public static String DataFormat(String txt){      //类名一般要大写if(txt.contains("万")){   //判断是否包含 “万”txt = "" + Double.parseDouble(txt.substring(0,txt.length()-1)) * 10000 ;}elsetxt = txt + ".0";return txt;}public static int StrToInt(String novelAdviceNumber){String temp = DataFormat(novelAdviceNumber);String str = temp.substring(0,temp.indexOf("."));//返回一个将 str 字符类型数据转换为 Integer 整型数据。return Integer.parseInt(str);    }
}

对上面代码中一些方法的简要说明:contains("万") 方法判断该属性上的值中是否包含字符串 “万” ;Double 类中一个方法 parseDouble() ,作用是将字符串转换为 double 类型。subString(a,b) 方法表示将截取下标从 a 开始到 b 结束的字符;indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置 ;stringObject.indexOf(searchvalue,fromindex),该方法将从头到尾地检索字符串 stringObject,看它是否含有子串 searchvalue(必须参数,规定需检索的字符串值), 开始检索的位置在字符串的 fromindex(可选的整数参数,合法取值是 0 到 stringObject.length -1)处或字符串的开头(没有指定 fromindex 时),如果找到一个 searchvalue ,则返回 searchvalue 的第一次出现的位置。

接下来创建一个小说类,用于生成对象,体现面向对象思想:

package com.qiku.entity;public class NovelInfo {public String NovelName ;        //小说名称public int NovelWordCount ;       //小说总字数public int NovelAdviceNumber ;   //小说推荐量public String getNovelName() {return NovelName;}public void setNovelName(String novelName) {NovelName = novelName;}public int getNovelWordCount() {return NovelWordCount;}public void setNovelWordCount(int novelWordCount) {NovelWordCount = novelWordCount;}public int getNovelAdviceNumber() {return NovelAdviceNumber;}public void setNovelAdviceNumber(int novelAdviceNumber) {NovelAdviceNumber = novelAdviceNumber;}
}

建议:这里定义的小说元素名称尽量和你本地数据库表中设置的字段保持一样,因为这里边代码稍微有些多,起名不同的话容易乱,当然这只是建议。

这几步都完成之后,开始获取本地数据库的连接,在此之前先把数据库表建好,如:

我这里表名为 novelinfo ,里面有三个字段,分别表示小说名称的 NovelName ,小说总字数的 NovelWordCount ,小说推荐量的 NovelAdviceNumber 。接下来开始创建获取数据库连接的类:

package com.qiku.DBUtils;import java.sql.DriverManager;
import java.sql.SQLException;import com.mysql.jdbc.Connection;public class DBUtil {private final String URL = "jdbc:mysql://localhost:3306/henuspider" ;//  ?useUnicode=true&characterEncoding=utf8 private final String USER_NAME = "root" ;private final String PASSWD = "123456" ;private final String DRIVER = "com.mysql.jdbc.Driver" ;public static DBUtil db;//定义的私有构造函数,用来生成对象private DBUtil(){    }public static synchronized DBUtil getIntance(){if(db==null){db=new DBUtil();}return db;}public Connection getConnection() throws Exception {try{Class.forName(DRIVER);//加载驱动Connection connection = (Connection) DriverManager.getConnection(URL,USER_NAME,PASSWD);return connection;}catch(ClassNotFoundException e){e.printStackTrace();}    return null;}
}

刚开始定义的 URL 值不能乱设,是根据前面所设置的主机名称、数据库端口、数据库名称等来填写,下面的同样按照前面设置来,还需要注意大小写,这个也很重要,至于那个 jdbc:mysql 不是很清楚,貌似我们是通过 jdbc 来获取数据库连接 mysql 的,所以...(如果有大神知道的话也可以解惑一下)

我们上面定义的方法是静态方法,仅用来生成 DBUtil 对象,又由于该方法是静态的,调用方式和一般的不一样,是通过 getIntance() 方法来调用,synchronized 是为多线程数据安全同步使用,简单理解 synchronized 的作用,假如在多个类中同时调用 DButil.getInstance() 方法,因为是同时并发,所以就不保证整个系统中只有一个,所以需要加入“同步”机制:synchronized 。 DButil 类对象:db ,也就是说,通过在 方法 getIntance() 前加上 synchronized 。就类似门上的一把锁,同时只能有一个人开门,开门后,进入里面办事,办完后,再快速的关门,把锁的钥匙给另一个想开锁进门办事的人;若不加同步机制,就类似一个房间(getIntance)有多个门可以进入,这样同时多个人进来,就会有同一个数据被多个人同时处理的情况。

关于 Class.forname()  我是第一次接触,我们讲师大致意思就是说是为了给数据库加载驱动什么的,我后来查了查,大致意思差不多,详解见 Class.forname() 的使用 。

获取过数据库连接之后,下面就是对数据库进行相关操作:

package com.qiku.dao;import java.sql.PreparedStatement;import com.mysql.jdbc.Connection;
import com.qiku.DBUtils.DBUtil;
import com.qiku.entity.NovelInfo;public class NovelDao {public int insertNovelInfo(NovelInfo novel) throws Exception{String sql="insert into novelinfo(NovelName,NovelWordCount,NovelAdviceNumber) values (?,?,?)";DBUtil dbutil = DBUtil.getIntance();Connection connection = dbutil.getConnection();PreparedStatement ps = connection.prepareStatement(sql);//往数据库表中添加数据ps.setString(1, novel.getNovelName());ps.setInt(2, novel.getNovelWordCount());ps.setInt(3, novel.getNovelAdviceNumber());int result = ps.executeUpdate();//按顺序关闭对应资源(释放资源):ps.close();connection.close();return result;   }
}

同样,字符串中是 sql 语句,不能乱写。现在基本上需要的功能类都写好了,开始实现我们写的成功不成功,在带有主函数的类中(即最初实现数据爬取的类)添加后续的功能,完整的代码为:

package com.qiku.seivice;import java.io.IOException;import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;import com.qiku.dao.NovelDao;
import com.qiku.entity.NovelInfo;
import com.qiku.util.SpiderUtil;public class WebpageSpider {public static void main(String[] args) throws Exception {// TODO 自动生成的方法存根//定义小说所在网页位置String URL="https://www.qidian.com/search?kw=完美世界";//获取 Jsoup 连接Connection connect = Jsoup.connect(URL);//触发 URL 对应的 html 信息Document document = connect.get();//定位所有小说所在的路径Elements NovelList = document.select(".book-img-text ul li");//遍历输出for(Element ele:NovelList) {Elements NovelName = ele.select(".book-mid-info h4");System.out.println("小说名称: "+NovelName.text());Elements NovelWordCount = ele.select(".total p span");System.out.println("小说总字数: "+NovelWordCount.first().text());//或者这样定义//在网页源代码中可以看到总字数和推荐量位于同一个 div 下,故能一起用。String NovelAdviceNumber = NovelWordCount.last().text();System.out.println("小说推荐量: "+NovelAdviceNumber);NovelDao novelDao = new NovelDao();NovelInfo novelInfo = new NovelInfo();novelInfo.setNovelName(NovelName.text());novelInfo.setNovelWordCount(SpiderUtil.StrToInt(NovelWordCount.first().text()));novelInfo.setNovelAdviceNumber(SpiderUtil.StrToInt(NovelAdviceNumber));int result = novelDao.insertNovelInfo(novelInfo);System.out.println("结果: "+result);System.out.println();}}
}

运行结果为:

显示的结果表明已经成功了,那么我们去看下数据库中是否真的有数据:

我们发现,小说的总字数。总推荐量都转换为相应的数字并入库了,但小说名称却是 一堆问号,这是什么情况呢?这表示在数据入库时发生了乱码。我们回到获取数据库连接的类中,把下面注释的部分加上:

package com.qiku.DBUtils;import java.sql.DriverManager;
import java.sql.SQLException;import com.mysql.jdbc.Connection;public class DBUtil {private final String URL = "jdbc:mysql://localhost:3306/henuspider?useUnicode=true&characterEncoding=utf8" ;//  ?useUnicode=true&characterEncoding=utf8 private final String USER_NAME = "root" ;private final String PASSWD = "123456" ;private final String DRIVER = "com.mysql.jdbc.Driver" ;public static DBUtil db;//定义的私有构造函数,用来生成对象private DBUtil(){   }public static synchronized DBUtil getIntance(){if(db==null){db=new DBUtil();}return db;}public Connection getConnection() throws Exception {try{Class.forName(DRIVER);//加载驱动Connection connection = (Connection) DriverManager.getConnection(URL,USER_NAME,PASSWD);return connection;}catch(ClassNotFoundException e){e.printStackTrace();}    return null;}
}

再次运行结果后,查看数据库:

诶,这样就成了(嘻嘻嘻),这就是数据采集的全部过程。先从网页爬取数据,然后将其封装到一个一个对象中,通过 jdbc 获取数据库连接,将爬取的数据保存至数据库中,使其长久化。下面再说一下这做好的一个项目如何打包给客户(这是我们讲师课外提的),见 数据采集及其可视化(三),如果不感兴趣,那就直接进入后续的可视化操作吧,见 数据采集及其可视化(四)。

奇酷学院-数据采集及其可视化(二)相关推荐

  1. 奇酷学院-数据采集及其可视化(一)

    前言: 这个呢,是我们学院小学期时我选择的一个项目,大致讲的就是如何从网页上爬取数据,爬取下来之后先保存至本地的数据库中,之后根据自己的需要对相应的数据进行可视化操作,例如通过柱状图.折线图.扇形图等 ...

  2. 奇酷学院-数据采集及其可视化(四)

    前面已经将数据从网上爬取下来并存放至数据库了,但仅仅有一堆数据让别人分析,这也太不直观也不方便,所以为了将这些数据能够更加清晰直观地展示出来,我们需要对其进行可视化操作. 我们需要先获取数据库连接,然 ...

  3. 奇酷学院-数据采集及其可视化(五)

    接着说,在创建类前仍分别创建相应的包去区分: 像获取数据库连接的 DBUtils,封装小说类对象的 entity 这些直接用前面的代码即可,我这里也不演示了,关于对数据库操作的 dao 我们需要做下修 ...

  4. 奇酷学院-数据采集及其可视化(三)

    如果处于上学阶段,这部分应该算是不重要的,大家有兴趣就看看,我这也只是写下来记记. 现在我们这部分项目是已经写好了: 接下来就是打包给客户,能够让他们不使用 eclipse 就能运行我们写的代码,就能 ...

  5. python计算商品总价_GitHub - ideaOzy/data_analysis: 基于Python的南京二手房数据采集及可视化分析...

    基于Python的南京二手房数据采集及可视化分析 1 内容简介 首先通过爬虫采集链家网上所有南京二手房的房源数据,并对采集到的数据进行清洗:然后,对清洗后的数据进行可视化分析,探索隐藏在大量数据背后的 ...

  6. 达芬奇密码 第八十二章

    达芬奇密码 第八十二章[@more@] 第八十二章 "舰队街?"兰登在车后看着提彬,问道.舰队街藏有墓穴?迄今为止,雷爵士竟然还在耍他的把戏,对将在何处找到那"骑士的坟墓 ...

  7. 【毕业设计_课程设计】基于Python的南京二手房数据采集及可视化分析

    文章目录 0 项目说明 1 内容简介 2 应用技术介绍 3 数据采集 3.1 数据清洗 4 数据可视化 5 项目工程 0 项目说明 基于Python的南京二手房数据采集及可视化分析 提示:适合用于课程 ...

  8. 数据清洗python实现箱线图_GitHub - nonefirst/data_analysis: 基于Python的南京二手房数据采集及可视化分析...

    基于Python的南京二手房数据采集及可视化分析 1 内容简介 首先通过爬虫采集链家网上所有南京二手房的房源数据,并对采集到的数据进行清洗:然后,对清洗后的数据进行可视化分析,探索隐藏在大量数据背后的 ...

  9. python 可视化 二维坐标标注等等

    python 可视化 二维坐标标注等等 - 蔡军帅 - 博客园https://www.cnblogs.com/caiyishuai/p/9607250.html 大佬的分享,在这里方便自己总结学习,因 ...

最新文章

  1. Linux 性能监控常用命令
  2. 一次失败的尝试:paxosstore示例编译
  3. 使用window任务计划
  4. 聚类 | 超详细的性能度量和相似度方法总结
  5. 把CNN里的乘法全部去掉会怎样?华为提出移动端部署神经网络新方法
  6. linux mysql 备份脚本_linux下mysql备份脚本
  7. 用java提示用户输入学生个数_编写程序,提示用户输入一个数N,然后显示1~N的所有偶数平方值,求大神看看我写的程序哪里有问题。。...
  8. 记录——《C Primer Plus (第五版)》第九章编程练习第十题
  9. 串行通信(二):串口流控
  10. 5.WEB版QQ多人聊天,带离线留言功能
  11. c语言常用数学函数6,C语言入门(6)——C语言常用数学函数
  12. js去除字符串空格(空白符)
  13. 微软原版win10系统启动盘的制作
  14. 读《因果的真相》第四章摘抄笔记
  15. kettle整合kafka
  16. Java-基于SSM的健身后台管理系统
  17. 电阻的基本原理、参数、应用与选型
  18. 复星联合超越保2020,升级了,但更便宜!
  19. Echarts图表自适应宽高大小
  20. 【详解+安装失败解决】Win11系统装CH340驱动方法

热门文章

  1. 零一的昔日织-2022
  2. Windows10系统重置指南
  3. php 类似charcodeat,charCodeAt与AscW函数的区别说明
  4. [日语二级词汇]形容词
  5. 克拉美罗下界 CRLB的计算
  6. ixwebhosting空间商介绍
  7. Vue 快速使用指南
  8. vue.js实现一个计算器
  9. 企业财务制度二--会计科目名称和编号(一)1701 固定资产清理(转载)
  10. ssm+jsp计算机毕业设计智慧教育大数据系统86adu(程序+lw+源码+远程部署)