最新版本:Java网页数据采集器[续篇-远程操作]【转载】
优采云 发布时间: 2022-10-11 18:52最新版本:Java网页数据采集器[续篇-远程操作]【转载】
本期概述
上一期我们学习了html页面采集之后的数据查询,但这只是本地查询数据库。如果我们想通过远程操作进行数据采集、存储和查询,我们应该怎么做呢?毛呢布?
今天一起来学习一下:如何通过本地客户端远程访问服务器到采集,存储和查询数据。
资料采集页面2011-2012英超球队战绩
学习简单的远程访问(RMI 示例)
首先,让我们学习一个简单的客户端远程访问服务器的示例。
这里使用Java RMI(远程方法调用)
Java RMI 是一种机制,它使 Java 虚拟机能够调用另一个 Java 虚拟机上的对象上的方法以实现远程访问。
但是要通过客户端实现远程访问,就必须绑定一个远程接口对象(即客户端可以访问的服务器上的方法都必须收录在这个接口中)。
好的,让我们编写示例代码。
定义远程接口
首先,我们需要编写一个继承远程对象Remote的远程接口HelloInterface。
接口HelloInterface中有一个sayHello方法,用于客户端连接后打招呼。
由于sayHello方法继承了远程Remote对象,所以需要抛出RemoteException远程异常。
package Remote_Interface;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 接口HelloInterface 继承了 远程接口 Remote 用于客户端Client远程调用
*/
public interface HelloInterface extends Remote{
public String sayHello(String name) throws RemoteException;
}
实现接口(在服务端实现接口)
接下来我们实现接口中的方法,实现接口的方法在服务端。
这里的HelloInterfaceImpl 类实现了接口HelloInterface 中的方法。
注意:这里的HelloInterfaceImpl也继承了U优采云tRemoteObject远程对象,必须写。虽然不写代码智能提示不会提示错误,但是服务器启动后会报莫名其妙的错误。
由于U优采云tRemoteObject远程对象需要抛出RemoteException,所以这里使用了一个构造函数HelloInterfaceImpl()来抛出这个异常。
package Server;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import Remote_Interface.HelloInterface;
/**
* HelloInterfaceImpl 用于实现 接口HelloInterface 的远程 SayHello方法
*/
@SuppressWarnings("serial")
// 继承 UnicastRemoteObject 远程对象 这个一定要写 否则 服务端启动报异常
public class HelloInterfaceImpl extends UnicastRemoteObject implements HelloInterface{
//HelloInterfaceImpl的构造方法 用于抛出UnicastRemoteObject 远程对象里的异常
protected HelloInterfaceImpl() throws RemoteException {
}
public String sayHello(String name) throws RemoteException {
//该信息 在客户端上发出
String strHello = "你好! " + name+" 欢迎访问服务端!";
//这条信息 是在服务端上 打印出来
System.out.println(name +" 正在 访问本服务端!");
return strHello;
}
}
写服务器
下面我们来写服务端,因为RMI实现远程访问的机制是指:客户端通过在RMI注册中心上查找远程接口对象的地址(服务器地址)来达到远程访问的目的。
因此,我们需要在服务端创建一个远程对象的注册中心来绑定和注册服务端地址和远程接口对象,以便客户端在后期能够成功的找到服务端(详见代码注释)。
package Server;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import Remote_Interface.HelloInterface;
/**
* Server 类 用于 启动 注册服务端
*/
public class Server {
public static void main(String[] args) {
try {
// 定义远程接口HelloInterface 对象 用于绑定在服务端注册表上 该接口由HelloInterfaceImpl()类实现
HelloInterface hInterface = new HelloInterfaceImpl();
int port = 6666; // 定义一个端口号
// 创建一个接受对特定端口调用的远程对象注册表 注册表上需要接口一个指定的端口号
LocateRegistry.createRegistry(port);
// 定义 服务端远程地址 URL格式
String address = "rmi://localhost:" + port + "/hello";
// 绑定远程地址和接口对象
Naming.bind(address,hInterface);
// 如果启动成功 则弹出如下信息
System.out.println(">>>服务端启动成功");
System.out.println(">>>请启动客户端进行连接访问");
} catch (MalformedURLException e) {
System.out.println("地址出现错误!");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("重复绑定了同一个远程对象!");
e.printStackTrace();
} catch (RemoteException e) {
System.out.println("创建远程对象出现错误!");
e.printStackTrace();
}
}
}
写客户端
写完服务端,我们来写下访问服务端需要的客户端。
客户端还需要定义一个远程访问地址——服务器地址,
然后,通过在 RMI 注册表中查找该地址;如果找到就建立连接。
package Client;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import Remote_Interface.HelloInterface;
/**
* Client 用于连接 并访问 服务端Server
*/
public class Client {
public static void main(String[] args) {
// 定义一个端口号 该端口号必须与服务端的端口号相同
int port = 6666;
// 同样定义一个远程地址 该地址为服务端的远程地址 所以 与服务端的地址是一样的
String address = "rmi://localhost:" + port + "/hello";
// 在RMI注册表上需找 对象为HelloInterface的地址 即服务端地址
try {
HelloInterface hInterface = (HelloInterface) Naming.lookup(address);
// 一旦客户端找到该服务端地址 则 进行连接
System.out.println(">>服务端启动成功");
System.out.println(">>>请启动客户端进行连接访问");
} catch (MalformedURLException e) {
System.out.println("地址出现错误!");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("重复绑定了同一个远程对象!");
e.printStackTrace();
} catch (RemoteException e) {
System.out.println("创建远程对象出现错误!");
e.printStackTrace();
}
}
}
Data采集AndStorage 类及其 dataCollectAndStore() 方法用于采集和存储数据。
<p>DataCollectionAndStorage类
package Server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
/**
* DataCollectionAndStorage类 用于数据的收集和存储
*/
public class DataCollectionAndStorage{
/**
* dataCollectAndStore()方法 用于Html数据收集和存储
*/
public void dataCollectAndStore() {
// 首先用一个字符串 来装载网页链接
String strUrl = "http://www.footballresults.org/league.php?all=1&league=EngPrem";
String sqlLeagues = "";
try {
// 创建一个url对象来指向 该网站链接 括号里()装载的是该网站链接的路径
// 更多可以看看 http://wenku.baidu.com/view/8186caf4f61fb7360b4c6547.html
URL url = new URL(strUrl);
// InputStreamReader 是一个输入流读取器 用于将读取的字节转换成字符
// 更多可以看看 http://blog.sina.com.cn/s/blog_44a05959010004il.html
InputStreamReader isr = new InputStreamReader(url.openStream(),
"utf-8"); // 统一使用utf-8 编码模式
// 使用 BufferedReader 来读取 InputStreamReader 转换成的字符
BufferedReader br = new BufferedReader(isr);
String strRead = ""; // new 一个字符串来装载 BufferedReader 读取到的内容
// 定义3个正则 用于获取我们需要的数据
String regularDate = "(\\d{1,2}\\.\\d{1,2}\\.\\d{4})";
String regularTwoTeam = ">[^]*</a>";
String regularResult = ">(\\d{1,2}-\\d{1,2})";
//创建 GroupMethod类的对象 gMethod 方便后期调用其类里的 regularGroup方法
GroupMethod gMethod = new GroupMethod();
//创建DataStructure数据结构 类的对象 用于数据下面的数据存储
DataStructure ds = new DataStructure();
//创建MySql类的对象 用于执行MySql语句
MySql ms = new MySql();
int i = 0; // 定义一个i来记录循环次数 即收集到的球队比赛结果数
int index = 0; // 定义一个索引 用于获取分离 2个球队的数据 因为2个球队正则是相同的
// 开始读取数据 如果读到的数据不为空 则往里面读
while ((strRead = br.readLine()) != null) {
/**
* 用于捕获日期数据
*/
String strGet = gMethod.regularGroup(regularDate, strRead);
// 如果捕获到了符合条件的 日期数据 则打印出来
if (!strGet.equals("")) {
//System.out.println("Date:" + strGet);
//将收集到的日期存在数据结构里
ds.date = strGet;
// 这里索引+1 是用于获取后期的球队数据
++index; // 因为在html页面里 源代码里 球队数据是在刚好在日期之后
}
/**
* 用于获取2个球队的数据
*/
strGet = gMethod.regularGroup(regularTwoTeam, strRead);
if (!strGet.equals("") && index == 1) { // 索引为1的是主队数据
// 通过subtring方法 分离出 主队数据
strGet = strGet.substring(1, strGet.indexOf("</a>"));
//System.out.println("HomeTeam:" + strGet); // 打印出主队
//将收集到的主队名称 存到 数据结构里
ds.homeTeam = strGet;
index++; // 索引+1之后 为2了
// 通过subtring方法 分离出 客队
} else if (!strGet.equals("") && index == 2) { // 这里索引为2的是客队数据
strGet = strGet.substring(1, strGet.indexOf("</a>"));
//System.out.println("AwayTeam:" + strGet); // 打印出客队
//将收集到的客队名称 存到数据结构里
ds.awayTeam = strGet;
index = 0; //收集完客队名称后 需要将索引还原 用于收集下一条数据的主队名称
}
/**
* 用于获取比赛结果
*/
strGet = gMethod.regularGroup(regularResult, strRead);
if (!strGet.equals("")) {
// 这里同样用到了substring方法 来剔除'