Java網(wǎng)頁數(shù)據(jù)采集器實例教程:數(shù)據(jù)存儲
簡介:
作為全球運用最廣泛的語言,Java 憑借它的高效性,可移植性(跨平臺),代碼的健壯性以及可強大的可擴展性,深受廣大應(yīng)用程序開發(fā)者的喜愛. 作為一門強大的開發(fā)語言,正則表達式在其中的應(yīng)用當(dāng)然是必不可少的,而且正則表達式的掌握能力也是那些高級程序員的開發(fā)功底之體現(xiàn),做一名合格的網(wǎng)站開發(fā)的程序員(尤其是做前端開發(fā)),正則表達式是必備的。
最近,由于一些需要,用到了java和正則,做了個的足球網(wǎng)站的數(shù)據(jù)采集程序,由于是***次做關(guān)于java的html頁面數(shù)據(jù)采集,必然在網(wǎng)上查找了很多資料,但是發(fā)現(xiàn)運用如此廣泛的java在使用正則做html采集方面的(中文)文章是少之又少,都是簡單的談了下java正則的概念,沒有真正用在實際網(wǎng)頁html采集,所以實例教程更是***(雖然java有它自己的Html Parser,而且十分強大),但個人覺得作為如此深入人心的正則表達式,理應(yīng)有其相關(guān)的java實例教程,而且應(yīng)該很多很全.于是在完成java版的html數(shù)據(jù)采集程序之后,本人便打算寫個關(guān)于正則表達式在java上的html頁面采集,以便有相關(guān)興趣的讀者更好的學(xué)習(xí).
本期概述:
上期我們講到了html頁面的數(shù)據(jù)采集,為了方便我們今后來調(diào)用收集到的數(shù)據(jù),這期我們要講講如何做數(shù)據(jù)存儲(MySql數(shù)據(jù)庫).
數(shù)據(jù)采集頁面 2011-2012賽季英超球隊?wèi)?zhàn)績
關(guān)于Java操作MySql
在使用java 操作MySql數(shù)據(jù)庫之前 我們需要在項目文件中導(dǎo)入 一個jar包(mysql-connector-java-5.1.18-bin)
可以在MySql官網(wǎng)下載 Connector/J 5.1.18
***次使用MySql? 請看java連接MYSQL
如何在java項目中導(dǎo)入jar包?
關(guān)于MySql數(shù)據(jù)庫
如果是初學(xué)者 想使用MySql數(shù)據(jù)庫的話 可以去這里XAMPP中文官網(wǎng) 下載 XAMPP 套裝
XAMPP(Apache+MySQL+PHP+PERL)是一個功能強大的建 XAMPP 軟件站集成軟件包,而且一鍵式安裝,無需修改配置文件,非常好用。
好了 需要準備的事宜都完成了 我們開始寫代碼
打開MySql數(shù)據(jù)庫 創(chuàng)建數(shù)據(jù)庫 和表 (拷貝如下代碼 到mysql里直接執(zhí)行即可)
- //創(chuàng)建數(shù)據(jù)庫 htmldatacollection
- CREATE DATABASE htmldatacollection;
- //在創(chuàng)建表之前 我們需要使用數(shù)據(jù)庫htmldatacollection
- use htmldatacollection;
- //在數(shù)據(jù)庫里 創(chuàng)建一個表 Premiership 用于存儲我們收集到的數(shù)據(jù)
- //這里為了方便 所有字段 全部是字符串格式
- CREATE TABLE Premiership(Date varchar(15),
- HomeTeam varchar(20),
- AwayTeam varchar(20),
- Result varchar(20)
- )
創(chuàng)建好后 我們來看看數(shù)據(jù)庫結(jié)構(gòu)
數(shù)據(jù)庫弄好了 我們開始實施java代碼
這里簡單介紹下各個類以及類所包含的方法
DataStorage類 以及包含的 dataStore()方法 用于數(shù)據(jù)收集和存儲
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.URL;
- public class DataStorage {
- public void dataStore() {
- // 首先用一個字符串 來裝載網(wǎng)頁鏈接
- String strUrl= "http://www.footballresults.org/league.php?all=1&league=EngPrem";
- String sqlLeagues = "";
- try {
- // 創(chuàng)建一個url對象來指向 該網(wǎng)站鏈接 括號里()裝載的是該網(wǎng)站鏈接的路徑
- // 更多可以看看 http://wenku.baidu.com/view/8186caf4f61fb7360b4c6547.html
- URL url = new URL(strUrl);
- // InputStreamReader 是一個輸入流讀取器 用于將讀取的字節(jié)轉(zhuǎn)換成字符
- // 更多可以看看 http://blog.sina.com.cn/s/blog_44a05959010004il.html
- InputStreamReader isr = new InputStreamReader(url.openStream(),
- "utf-8"); // 統(tǒng)一使用utf-8 編碼模式
- // 使用 BufferedReader 來讀取 InputStreamReader 轉(zhuǎn)換成的字符
- BufferedReader br = new BufferedReader(isr);
- String strRead = ""; // new 一個字符串來裝載 BufferedReader 讀取到的內(nèi)容
- // 定義3個正則 用于獲取我們需要的數(shù)據(jù)
- String regularDate = "(\\d{1,2}\\.\\d{1,2}\\.\\d{4})";
- String regularTwoTeam = ">[^<>]*</a>";
- String regularResult = ">(\\d{1,2}-\\d{1,2})</TD>";
- //創(chuàng)建 GroupMethod類的對象 gMethod 方便后期調(diào)用其類里的 regularGroup方法
- GroupMethod gMethod = new GroupMethod();
- //創(chuàng)建DataStructure數(shù)據(jù)結(jié)構(gòu) 類的對象 用于數(shù)據(jù)下面的數(shù)據(jù)存儲
- DataStructure ds = new DataStructure();
- //創(chuàng)建MySql類的對象 用于執(zhí)行MySql語句
- MySql ms = new MySql();
- int i = 0; // 定義一個i來記錄循環(huán)次數(shù) 即收集到的球隊比賽結(jié)果數(shù)
- int index = 0; // 定義一個索引 用于獲取分離 2個球隊的數(shù)據(jù) 因為2個球隊正則是相同的
- // 開始讀取數(shù)據(jù) 如果讀到的數(shù)據(jù)不為空 則往里面讀
- while ((strRead = br.readLine()) != null) {
- /**
- * 用于捕獲日期數(shù)據(jù)
- */
- String strGet = gMethod.regularGroup(regularDate, strRead);
- // 如果捕獲到了符合條件的 日期數(shù)據(jù) 則打印出來
- if (!strGet.equals("")) {
- //System.out.println("Date:" + strGet);
- //將收集到的日期存在數(shù)據(jù)結(jié)構(gòu)里
- ds.date = strGet;
- // 這里索引+1 是用于獲取后期的球隊數(shù)據(jù)
- ++index; // 因為在html頁面里 源代碼里 球隊數(shù)據(jù)是在剛好在日期之后
- }
- /**
- * 用于獲取2個球隊的數(shù)據(jù)
- */
- strGet = gMethod.regularGroup(regularTwoTeam, strRead);
- if (!strGet.equals("") && index == 1) { // 索引為1的是主隊數(shù)據(jù)
- // 通過subtring方法 分離出 主隊數(shù)據(jù)
- strGet = strGet.substring(1, strGet.indexOf("</a>"));
- //System.out.println("HomeTeam:" + strGet); // 打印出主隊
- //將收集到的主隊名稱 存到 數(shù)據(jù)結(jié)構(gòu)里
- ds.homeTeam = strGet;
- index++; // 索引+1之后 為2了
- // 通過subtring方法 分離出 客隊
- } else if (!strGet.equals("") && index == 2) { // 這里索引為2的是客隊數(shù)據(jù)
- strGet = strGet.substring(1, strGet.indexOf("</a>"));
- //System.out.println("AwayTeam:" + strGet); // 打印出客隊
- //將收集到的客隊名稱 存到數(shù)據(jù)結(jié)構(gòu)里
- ds.awayTeam = strGet;
- index = 0; //收集完客隊名稱后 需要將索引還原 用于收集下一條數(shù)據(jù)的主隊名稱
- }
- /**
- * 用于獲取比賽結(jié)果
- */
- strGet = gMethod.regularGroup(regularResult, strRead);
- if (!strGet.equals("")) {
- // 這里同樣用到了substring方法 來剔除'<' 和 "</TD>" 標簽 來獲取我們想要的比賽結(jié)果
- strGet = strGet.substring(1, strGet.indexOf("</TD>"));
- //System.out.println("Result:" + strGet);
- ds.result = strGet; //將收集到的比賽結(jié)果存到數(shù)據(jù)結(jié)構(gòu)里
- //System.out.println();
- //MySql插入語句
- sqlLeagues = "INSERT INTO Premiership values(\""
- + ds.date + "\"," + "\"" + ds.homeTeam
- + "\"," + "\"" + ds.awayTeam + "\","+ "\"" + ds.result + "\")";
- //調(diào)用MySql類的datatoMySql()方法 來執(zhí)行 MySql插入語句
- ms.datatoMySql(sqlLeagues);
- i++; //每插入完一條記錄 i+1;
- System.out.println("第"+i+"條數(shù)據(jù)插入成功");
- }
- }
- // 當(dāng)讀完數(shù)據(jù)后 記得關(guān)閉 BufferReader
- br.close();
- //System.out.println("共收集到" + i + "條比賽記錄");// 打印出循環(huán)次數(shù)
- //當(dāng)數(shù)據(jù)存儲完成后 打印出 收集球隊記錄數(shù)
- System.out.println("數(shù)據(jù)存儲完畢,共插入數(shù)據(jù)庫"+i+"條記錄");
- } catch (IOException e) {
- // 如果出錯 拋出異常
- e.printStackTrace();
- }
- }
- }
DataStructure類 簡單數(shù)據(jù)結(jié)構(gòu) 里面包含了相應(yīng)的字段 用于將收集的數(shù)據(jù)臨時性存儲
- //創(chuàng)建一個數(shù)據(jù)結(jié)構(gòu)類來 裝載收集到的數(shù)據(jù)
- public class DataStructure {
- //定義數(shù)據(jù)字段
- public String homeTeam;
- public String awayTeam;
- public String date;
- public String result;
- }
GroupMethod類 以及包含的 regularGroup()方法 用于正則匹配html 源代碼上的數(shù)據(jù)
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- public class GroupMethod {
- // 傳入2個字符串參數(shù) 一個是pattern(我們使用的正則) 另一個matcher是html源代碼
- public String regularGroup(String pattern, String matcher) {
- Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
- Matcher m = p.matcher(matcher);
- if (m.find()) { // 如果讀到
- return m.group();// 返回捕獲的數(shù)據(jù)
- } else {
- return ""; // 否則返回一個空值
- }
- }
- }
MySql類 以及包含的 datatoMySql() 方法 用于執(zhí)行SQL插入語句 將臨時存儲在數(shù)據(jù)結(jié)構(gòu)里的數(shù)據(jù) 插入到MySql數(shù)據(jù)庫中
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.SQLException;
- import java.sql.Statement;
- /**
- * @MySql類用于實施MySql查詢語句
- */ 9 public class MySql {
- //定義MySql驅(qū)動,數(shù)據(jù)庫地址,數(shù)據(jù)庫用戶名 密碼, 執(zhí)行語句和數(shù)據(jù)庫連接
- public String driver = "com.mysql.jdbc.Driver";
- public String url = "jdbc:mysql://127.0.0.1:3306/htmldatacollection";
- public String user = "root";
- public String password = "root";
- public Statement stmt = null;
- public Connection conn = null;
- //創(chuàng)建一個插入數(shù)據(jù)的方法
- public void datatoMySql(String insertSQl) {
- try {
- try {
- Class.forName(driver).newInstance();
- } catch (Exception e) {
- System.out.println("Unable to find the local driver");
- e.printStackTrace();
- }
- //創(chuàng)建連接
- conn = DriverManager.getConnection(url, user, password);
- //創(chuàng)建一個 Statement 對象來將 SQL 語句發(fā)送到數(shù)據(jù)庫
- stmt = conn.createStatement();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- try {
- //執(zhí)行SQL 插入語句
- stmt.executeUpdate(insertSQl);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- try {
- //執(zhí)行完 停止執(zhí)行語句
- stmt.close();
- //執(zhí)行完關(guān)閉數(shù)據(jù)庫連接
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Main 主函數(shù) 用于數(shù)據(jù)輸出
- public class Main {
- public static void main(String[] args) {
- //在主函數(shù)里調(diào)用DataStorage類里的dataStore()方法
- DataStorage ds = new DataStorage();
- ds.dataStore();
- }
- }
好了 下面我們來執(zhí)行下 看看結(jié)果
數(shù)據(jù)采集頁面 2011-2012賽季英超球隊?wèi)?zhàn)績
Html頁面截圖-初始階段
MySql數(shù)據(jù)庫截圖-初始階段
Html頁面截圖-結(jié)束階段
MySql數(shù)據(jù)庫截圖-結(jié)束階段
一共收集到 189條記錄
MySql數(shù)據(jù)庫顯示 189 行數(shù)據(jù)
這樣 我們2011-2012英超聯(lián)盟賽季的比賽戰(zhàn)績就全部收集并存到MySql數(shù)據(jù)庫里了 :)
當(dāng)然這里只是抓取并存儲了一個頁面的內(nèi)容,如果感興趣 想抓去更多的頁面內(nèi)容 你可以分析下該鏈接后的聯(lián)盟名 例如 league=EngPrem 通過改變league名來獲取所有聯(lián) 盟的比賽數(shù)據(jù) 你可以寫個 枚舉接口 把所有球隊的名字放進去. 然后在DataStorage類里 實施該接口 將 枚舉 轉(zhuǎn)換成 球隊數(shù)組
然后來附加到 "http://www.footballresults.org/league.php?all=1&league=" 鏈接后面 來補齊鏈接 循環(huán)讀取各個聯(lián)盟比賽頁面的內(nèi)容
同樣 還有更智能的方法 你可以寫個方法 從http://www.footballresults.org/allleagues.php 頁面 獲取所有球隊的名字 同樣循環(huán)補齊鏈接 讀取各聯(lián)盟頁面內(nèi)容
附上源代碼下載 htmlDataStorage.zip
原文鏈接:http://www.cnblogs.com/longwu/archive/2012/01/03/2310588.html
【編輯推薦】