精华内容
下载资源
问答
  • 数据采集的分析,其中实现了断点续传,日志记录,通过放射机制得到类的实例,与数据备份等功能,是java初学者很好的借鉴学习的代码。只要懂Java基础知识和xml解析的基本可以看懂这个项目。
  • 网络数据采集技术——Java
  • JAVA调用底层库实现采集串口数据和返回数据 JAVA调用底层库实现采集串口数据和返回数据
  • 基于Java数据采集(终结篇)

    千次阅读 2021-02-12 09:44:22
    分别实现了①抓取页面信息并显示②简单采集入库存储③调用本地数据库查询④远程调用实现操作(未实现)以上这些功能都是基于本地的,有时候我们需要远程去调用这类数据,这时我们就可以用JAVA提供的RMI机制实行远程...

    关于写过关于JAVA采集入库的三篇文章:

    分别实现了

    ①抓取页面信息并显示

    ②简单采集入库存储

    ③调用本地数据库查询

    ④远程调用实现操作(未实现)

    以上这些功能都是基于本地的,有时候我们需要远程去调用这类数据,这时我们就可以用JAVA提供的RMI机制实行远程调用访问。

    什么是RMI?

    RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。可以用此方法调用的任何对象必须实现该远程接口。调用这样一个对象时,其参数为 "marshalled" 并将其从本地虚拟机发送到远程虚拟机(该远程虚拟机的参数为 "unmarshalled")上。该方法终止时,将编组来自远程机的结果并将结果发送到调用方的虚拟机。如果方法调用导致抛出异常,则该异常将指示给调用方。

    简单了解下RMI,看下简单实现吧

    1、定义远程接口

    首先,我们需要写个远程接口IHello 该接口继承了远程对象Remote.

    接口IHello里面有个hello的方法,用于客户端连接后 打招呼.

    由于IHello继承了远程Remote对象, 所以需要抛一个 RemoteException 远程异常.

    1 importjava.rmi.Remote;2 importjava.rmi.RemoteException;3

    4

    5 public interface IHello extendsRemote{6

    7 public String hello(String name) throwsRemoteException;8 }

    2、实现接口

    接下来,我们实现下 该接口里的方法, 实现接口的方法在服务端.

    这里的HelloImpl类 实现了接口IHello里的方法.

    注意:这里HelloImpl同样继承了 UnicastRemoteObject 远程对象,这个必须写,不然服务端启动后会莫名其妙报错.

    1 importjava.rmi.RemoteException;2 importjava.rmi.server.UnicastRemoteObject;3

    4 /**

    5 * UnicastRemoteObject 这个必须写,虽然不写代码也不会出错,但在运行服务器的时候会出现莫名错误6 *@authorBalla_兔子7 *8 */

    9 public class HelloImpl extends UnicastRemoteObject implementsIHello {10

    11 protected HelloImpl() throwsRemoteException {12 super();13 }14

    15 @Override16 publicString hello(String name) {17 String strHello="你好!"+name+"正在访问服务端";18 System.out.println(name+"正在访问服务端");19 returnstrHello;20 }21

    22 }

    3、编写服务端

    服务端,由于RMI实现远程访问的机制是指:客户端通过在RMI注册表上寻找远程接口对象的地址(服务端地址) 达到实现远程访问的目的,

    所以,我们需要在服务端创建一个远程对象的注册表,用于绑定和注册 服务端地址 和 远程接口对象,便于后期客户端能够成功找到服务端

    1 importjava.rmi.Naming;2 importjava.rmi.RemoteException;3 importjava.rmi.registry.LocateRegistry;4

    5

    6 public classServer {7

    8 /**

    9 *@paramargs10 */

    11 public static voidmain(String[] args) {12 try{13 IHello hello=newHelloImpl();14 int port=6666;15 LocateRegistry.createRegistry(port);16 String address="rmi://localhost:"+port+"/tuzi";17 Naming.bind(address, hello);18 System.out.println(">>>服务端启动成功");19 System.out.println(">>>请启动客户端进行连接访问..");20

    21 } catch(Exception e) {22 e.printStackTrace();23 }24 }25

    26 }

    4、编写客户端

    客户端上同样需要定义一个 远程访问的地址 - 即服务端地址,

    然后,通过在RMI注册表上寻找该地址;  如果找到 则建立连接.

    1 importjava.net.MalformedURLException;2 importjava.rmi.Naming;3 importjava.rmi.NotBoundException;4 importjava.rmi.RemoteException;5 importjava.util.Scanner;6

    7

    8 public classClient {9 public static voidmain(String[] args) {10

    11 int port=6666;12 String address="rmi://localhost:"+port+"/tuzi";13 try{14 IHello hello=(IHello) Naming.lookup(address);15 System.out.println("<<

    17 System.out.println(hello.hello("Rabbit"));18 Scanner scanner=newScanner(System.in);19 String input=scanner.next();20 } catch(MalformedURLException e) {21 //TODO Auto-generated catch block

    22 e.printStackTrace();23 } catch(RemoteException e) {24 //TODO Auto-generated catch block

    25 e.printStackTrace();26 } catch(NotBoundException e) {27 //TODO Auto-generated catch block

    28 e.printStackTrace();29 }30

    31 }32 }

    运行效果图:

    a21dd5a943c8715263694cbce2f4641f.png

    0f50d8d203d76c28f846451dcedfe519.png

    5117ba4ea0dbe38a094b91f1fe96c5f6.png

    华丽的分割线

    接下来就来看看我们的程序吧,今天换种口味来采集下《2013-2014赛季常规赛排名》

    05b1bc595c00852c5ca0d36fc763149d.png

    先上效果图:

    68700211cd51906ba60bf8ac01c892fe.png

    ece1632865eb2585ddd26fa2c79b60d9.png

    9d065bb9a936c7dcbb16662f280d5aff.png

    4f6e0718782cb07b7332fb7f33e6f4d9.png

    d6f54b5efc0d94b1714f8515fdc9dd7a.png

    293970f2c0257562c59d123def1e6741.png

    好了,剩下的上代码吧,具体看代码注释:

    IdoAction.java (功能调用接口代码)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 packagecom.lcw.rmi.collection;2

    3 importjava.rmi.Remote;4 importjava.rmi.RemoteException;5 importjava.util.List;6

    7 public interface IdoAction extendsRemote{8

    9

    10 public void initData() throwsRemoteException;11

    12 public void getAllDatas() throwsRemoteException;13

    14 public List getAllTeams() throwsRemoteException;15

    16 public List getTeamInfo(String team) throwsRemoteException;17

    18 public List getAllInfo() throwsRemoteException;19

    20 }

    IdoAction.java

    doActionImpl.java (接口实现类)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 packagecom.lcw.rmi.collection;2

    3 importjava.rmi.RemoteException;4 importjava.rmi.server.UnicastRemoteObject;5 importjava.sql.ResultSet;6 importjava.sql.SQLException;7 importjava.util.ArrayList;8 importjava.util.List;9

    10 public class doActionImpl extends UnicastRemoteObject implementsIdoAction {11

    12 /**

    13 *14 */

    15 private static final long serialVersionUID = 1L;16 privateMysql mysql;17 privateResultSet resultSet;18

    19 public doActionImpl() throwsRemoteException {20 mysql = newMysql();21 }22

    23 @Override24 public void getAllDatas() throwsRemoteException {25 //调用采集类,获取所有数据

    26 CollectData data = newCollectData();27 data.getAllDatas();28 System.out.println("数据采集成功!");29 }30

    31 @Override32 public List getAllInfo() throwsRemoteException {33 //查询所有数据

    34 String sql = "select * from data";35 resultSet =mysql.querySQL(sql);36 List list=new ArrayList();37 System.out.println("当前执行命令5,正在获取NBA(2013-2014)赛季常规赛队伍所有信息..");38 System.out.println("获取成功,已在客户端展示..");39 try{40 while(resultSet.next()) {41 for (int i = 2; i < 17; i++) {42 //System.out.println("++++++++++++++");调试

    43 list.add(resultSet.getString(i));44 }45 System.out.println();46 }47 } catch(SQLException e) {48 e.printStackTrace();49 }50 returnlist;51 }52

    53 @Override54 public List getAllTeams() throwsRemoteException {55 //查询所有队伍名称

    56 String sql = "select team from data";57 resultSet =mysql.querySQL(sql);58 List list = new ArrayList();59 System.out.println("当前执行命令3,正在获取NBA(2013-2014)赛季常规赛队伍..");60 System.out.println("获取成功,已在客户端展示..");61 try{62 while(resultSet.next()) {63 list.add(resultSet.getString("team"));64 }65 } catch(SQLException e) {66 System.out.println("数据库暂无信息,请执行自动化采集命令");67 e.printStackTrace();68 }69 returnlist;70

    71 }72

    73 @Override74 public List getTeamInfo(String team) throwsRemoteException {75 //根据队伍查询队伍信息

    76 ResultSet resultSet = mysql.querySQL("select * from data where team='"

    77 + team + "'");78 List list=new ArrayList();79 System.out.println("当前执行命令4,正在获取用户所查询队伍信息..");80 System.out.println("获取成功,已在客户端展示..");81 try{82 if(resultSet.next()) {83 for (int i = 2; i < 17; i++) {84 list.add(resultSet.getString(i));85 }86 }87 System.out.println();88 } catch(SQLException e) {89 System.out.println("数据库暂无信息,请执行自动化采集命令");90 e.printStackTrace();91 }92 returnlist;93 }94

    95 @Override96 public void initData() throwsRemoteException {97 //初始化数据库

    98 String sql = "delete from data";99 try{100 mysql.updateSQL(sql);101 System.out.println("数据库初始化成功!");102 } catch(Exception e) {103 System.out.println("数据库初始化失败!");104 }105

    106 }107

    108 }

    doActionImpl.java

    CollectData.java (采集主类)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 packagecom.lcw.rmi.collection;2

    3 importjava.io.BufferedReader;4 importjava.io.IOException;5 importjava.io.InputStream;6 importjava.io.InputStreamReader;7 importjava.net.MalformedURLException;8 importjava.net.URL;9 importjava.util.ArrayList;10 importjava.util.Arrays;11 importjava.util.List;12

    13 public classCollectData {14

    15 /**

    16 * 采集类,获取所有数据17 */

    18 public voidgetAllDatas() {19 String address = "http://nbadata.sports.qq.com/teams_stat.aspx";//要采集数据的url

    20 try{21 URL url = newURL(address);22 try{23 InputStream inputStream = url.openStream();//打开url,返回字节流

    24 InputStreamReader inputStreamReader = newInputStreamReader(25 inputStream, "gbk");//将字节流转换为字符流,编码utf-8

    26 BufferedReader reader = new BufferedReader(inputStreamReader);//提高效率,缓存

    27 String rankRegEx = ">\\d{1,2}";//排名正则

    28 String teamRegEx = ">[^<>]*";//队名正则

    29 String dataRegEx = ">\\d{1,3}(\\.)\\d{0,2}";//正常数据正则

    30 String percentRegEX = ">\\d{1,2}(\\.)*(\\d)*%";//百分比数据

    31 GetRegExData regExData = newGetRegExData();32 String temp = "";//存放临时读取数据

    33 int flag = 0;34 String tempRank = "";//存放匹配到的返回数据

    35 String tempTeam = "";//存放匹配到的返回数据

    36 String tempData = "";37 String tempPercent = "";38 List list = new ArrayList();39 Mysql mysql = newMysql();40 while ((temp = reader.readLine()) != null) {41 //匹配排名

    42 if ((tempRank = regExData.getData(rankRegEx, temp)) != "") {43 tempRank = tempRank.substring(1, tempRank44 .indexOf(""));45 //System.out.println("排名:" + tempRank);

    46 list.add(tempRank);47 flag++;48 }49 //匹配球队50 //由于该正则会匹配到其他地方的数据,需给它一个标识符,让它从"找到排名位置"才开始匹配

    51 if ((tempTeam = regExData.getData(teamRegEx, temp)) != ""

    52 && flag == 1) {53 tempTeam = tempTeam.substring(1, tempTeam54 .indexOf(""));55 //System.out.println("球队名称:" + tempTeam);

    56 list.add(tempTeam);57 flag = 0;58 }59 //匹配正常数据

    60 if ((tempData = regExData.getData(dataRegEx, temp)) != "") {61 tempData = tempData.substring(1, tempData62 .indexOf(""));63 //System.out.println(tempData);

    64 list.add(tempData);65

    66 }67 //匹配百分比数据

    68 if ((tempPercent = regExData.getData(percentRegEX, temp)) != "") {69 tempPercent = tempPercent.substring(1, tempPercent70 .indexOf(""));71 //System.out.println(tempPercent);

    72 list.add(tempPercent);73 }74

    75 }76 reader.close();77 Object[] arr = list.toArray();//将集合转换为数组

    78 int a = -15;79 int b = 0;80 String sql = "insert into data(rank,team,chushou1,mingzhong1,chushou2,mingzhong2,chushou3,mingzhong3,qianchang,houchang,zong,zhugong,shiwu,fangui,defen) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";81 for (int i = 0; i < 30; i++) {82 a += 15;83 b += 15;84 if (b <= 450) {85 Object[] arr1 =Arrays.copyOfRange(arr, a, b);86 mysql.insertNewData(sql, arr1);87 System.out.println("正在采集数据..当前采集数据:" + (i + 1) + "条");88 }89 }90

    91 } catch(IOException e) {92 e.printStackTrace();93 }94 } catch(MalformedURLException e) {95 e.printStackTrace();96 }97 }98

    99 }

    CollectData.java

    GetRegExData.java (正则过滤功能类)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 packagecom.lcw.rmi.collection;2

    3 importjava.util.regex.Matcher;4 importjava.util.regex.Pattern;5

    6 public classGetRegExData {7

    8 publicString getData(String regex, String content) {9 Pattern pattern =Pattern.compile(regex);10 Matcher matcher =pattern.matcher(content);11 if(matcher.find()) {12 returnmatcher.group();13 } else{14 return "";15 }16

    17 }18 }

    GetRegExData.java

    Mysql.java (数据库操作类)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 packagecom.lcw.rmi.collection;2

    3 importjava.sql.Connection;4 importjava.sql.DriverManager;5 importjava.sql.PreparedStatement;6 importjava.sql.ResultSet;7 importjava.sql.SQLException;8

    9 public classMysql {10

    11 private String driver = "com.mysql.jdbc.Driver";12 private String url = "jdbc:mysql://localhost:3306/nba";13 private String user = "root";14 private String password = "";15

    16 private PreparedStatement stmt = null;17 private Connection conn = null;18 private ResultSet resultSet = null;19

    20 /**

    21 *22 *@paraminsertSql23 * 采集类,插入数据操作24 *@paramarr25 */

    26 public voidinsertNewData(String insertSql, Object[] arr) {27

    28 try{29 Class.forName(driver).newInstance();30 try{31 conn =DriverManager.getConnection(url, user, password);32 stmt =conn.prepareStatement(insertSql);33 stmt.setString(1, arr[0].toString());34 stmt.setString(2, arr[1].toString());35 stmt.setString(3, arr[2].toString());36 stmt.setString(4, arr[3].toString());37 stmt.setString(5, arr[4].toString());38 stmt.setString(6, arr[5].toString());39 stmt.setString(7, arr[6].toString());40 stmt.setString(8, arr[7].toString());41 stmt.setString(9, arr[8].toString());42 stmt.setString(10, arr[9].toString());43 stmt.setString(11, arr[10].toString());44 stmt.setString(12, arr[11].toString());45 stmt.setString(13, arr[12].toString());46 stmt.setString(14, arr[13].toString());47 stmt.setString(15, arr[14].toString());48 stmt.executeUpdate();49 stmt.close();50 conn.close();51

    52 } catch(SQLException e) {53 e.printStackTrace();54 }55 } catch(InstantiationException e) {56 e.printStackTrace();57 } catch(IllegalAccessException e) {58 e.printStackTrace();59 } catch(ClassNotFoundException e) {60 e.printStackTrace();61 }62

    63 }64

    65 /**

    66 *67 *@paramsql更新数据库语句68 */

    69 public voidupdateSQL(String updateSql) {70 try{71 Class.forName(driver).newInstance();72 try{73 conn =DriverManager.getConnection(url, user, password);74 } catch(SQLException e) {75 e.printStackTrace();76 }77 try{78 stmt =conn.prepareStatement(updateSql);79 stmt.execute(updateSql);80 } catch(SQLException e) {81 e.printStackTrace();82 }83

    84 } catch(InstantiationException e) {85 e.printStackTrace();86 } catch(IllegalAccessException e) {87 e.printStackTrace();88 } catch(ClassNotFoundException e) {89 e.printStackTrace();90 }91 }92

    93 /**

    94 *95 *@paramsql一般查询96 */

    97 publicResultSet querySQL(String searchSql) {98 try{99 Class.forName(driver).newInstance();100 try{101 conn =DriverManager.getConnection(url, user, password);102 } catch(SQLException e) {103 e.printStackTrace();104 }105 try{106 stmt =conn.prepareStatement(searchSql);107 resultSet =stmt.executeQuery();108 } catch(SQLException e) {109 e.printStackTrace();110 }111

    112 } catch(InstantiationException e) {113 e.printStackTrace();114 } catch(IllegalAccessException e) {115 e.printStackTrace();116 } catch(ClassNotFoundException e) {117 e.printStackTrace();118 }119 returnresultSet;120 }121 }

    Mysql.java

    Server.java (服务端类)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 packagecom.lcw.rmi.collection;2

    3 importjava.net.MalformedURLException;4 importjava.rmi.AlreadyBoundException;5 importjava.rmi.Naming;6 importjava.rmi.RemoteException;7 importjava.rmi.registry.LocateRegistry;8

    9 public classServer {10

    11 /**

    12 *@paramargs13 */

    14 public static voidmain(String[] args) {15 try{16 int port = 9797;17 String address = "rmi://localhost:"+port+"/nba";18 IdoAction action = newdoActionImpl();19 LocateRegistry.createRegistry(port);20 try{21 Naming.bind(address, action);22 System.out.println(">>>正在启动服务端..");23 System.out.println(">>>服务端启动成功!");24 System.out.println(">>>等待客户端连接...");25 System.out.println(">>>客户端Balla_兔子已连接。");26 } catch(MalformedURLException e) {27 e.printStackTrace();28 } catch(AlreadyBoundException e) {29 e.printStackTrace();30 }31 } catch(RemoteException e) {32 e.printStackTrace();33 }34 }35

    36 }

    Server.java

    Client.java (客户端类)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 packagecom.lcw.rmi.collection;2

    3 importjava.net.MalformedURLException;4 importjava.rmi.Naming;5 importjava.rmi.NotBoundException;6 importjava.rmi.RemoteException;7 importjava.util.List;8 importjava.util.Scanner;9

    10 public classClient {11

    12 public static voidmain(String[] args) {13 int port = 9797;14 String address = "rmi://localhost:" + port + "/nba";15

    16 try{17 IdoAction action =(IdoAction) Naming.lookup(address);18 System.out.println("正在启动客户端..");19 System.out.println("客户端启动完毕,正在连接服务端..");20 System.out.println("连接成功...");21 System.out.println("---------------------------");22

    23 while (true) {24 System.out.println("①初始化数据库-请按 (1)");25 System.out.println();26 System.out.println("②自动化采集NBA(2013-2014)赛季常规赛排名数据-请按(2)");27 System.out.println();28 System.out.println("③查询NBA(2013-2014)赛季常规赛排名所有队伍-请按(3)");29 System.out.println();30 System.out.println("④查询具体球队(2013-2014)赛季常规赛排名-请按(4)");31 System.out.println();32 System.out.println("⑤查询具体详情-请按(5)");33 System.out.println();34

    35 Scanner scanner = newScanner(System.in);36 String input =scanner.next();37

    38 if (input.equals("1")) {39 System.out40 .println("---------------------------------------------------------");41 System.out.println("服务端数据已初始化,请按2进行数据自动化采集..");42 action.initData();43 System.out44 .println("---------------------------------------------------------");45 }46 if (input.equals("2")) {47 System.out48 .println("---------------------------------------------------------");49 System.out.println("数据自动化采集中,请稍后..");50 int i=0;51 while(i<10000){//延迟操作,给数据采集缓冲时间

    52 i++;53 }54 System.out.println("数据采集完毕..按3,4,5进行相关操作");55 action.getAllDatas();56 System.out57 .println("---------------------------------------------------------");58 }59 if (input.equals("3")) {60 System.out61 .println("---------------------------------------------------------");62 System.out.println("正在获取NBA(2013-2014)赛季常规赛队伍,请稍后..");63 System.out.println();64 List list =action.getAllTeams();65 for (int i = 0; i < list.size(); i++) {66 if (i % 5 == 0 && i != 0) {67 System.out.println();68 }69 System.out.print(list.get(i) + "\t");70 }71 System.out.println();72

    73 System.out74 .println("---------------------------------------------------------");75 }76 if (input.equals("4")) {77 System.out78 .println("---------------------------------------------------------");79 System.out.println("请输入你要查询的队伍名称(如:76人)");80 String team =scanner.next();81 System.out82 .print("排名\t球队\t出手\t命中率\t出手\t命中率\t出手\t命中率\t前场\t后场\t总\t助攻\t失误\t犯规\t得分");83 System.out.println();84 List list=action.getTeamInfo(team);85 for (int i = 0; i < 15; i++) {86 System.out.print(list.get(i)+"\t");87 }88 System.out.println();89 System.out90 .println("---------------------------------------------------------");91 }92 if (input.equals("5")) {93 System.out94 .println("---------------------------------------------------------");95 System.out.println("数据获取中,请稍后...");96 System.out.println();97 System.out98 .print("排名\t球队\t出手\t命中率\t出手\t命中率\t出手\t命中率\t前场\t后场\t总\t助攻\t失误\t犯规\t得分");99 System.out.println();100 List list=action.getAllInfo();101 for(int i=0;i<450;i++){102 if(i%15==0&&i!=0){103 System.out.println();104 }105 System.out.print(list.get(i)+"\t");106 }107 System.out.println();108 System.out109 .println("---------------------------------------------------------");110 }111 }112 } catch(MalformedURLException e) {113 e.printStackTrace();114 } catch(RemoteException e) {115 e.printStackTrace();116 } catch(NotBoundException e) {117 e.printStackTrace();118 }119 }120 }

    Client.java

    好了,关于JAVA采集数据文章就到此为止了~ 撤··

    展开全文
  • java web 数据采集系统

    2015-08-28 13:34:57
    实用的web采集系统,欢迎大家指点,谢谢
  • 使用Netty进行网络通信,完成分布式的数据采集任务,可以采集500以上数据节点。
  • java 数据采集

    千次阅读 2016-05-23 16:52:14
    1、首先安装java的运行环境Jre 2、配置db.properties文件,word是搜索关键词 3、运行bdzd.exe,即可采集搜索内容


                        闲着无聊,搞了个百度知道的采集程序,生成文件格式为csv,感兴趣的可以添加我的qq:657844045

    下载地址:http://pan.baidu.com/s/1jI2JY1C

    1、首先安装java的运行环境Jre


    2、配置db.properties文件,word是搜索关键词


    3、运行bdzd.exe,即可采集搜索内容


    展开全文
  • 高并发数据采集框架,可以用网络助手进行测试,后续会更新!
  • 1.hj212 2015、2017皆可以测试 2.本项目测试都可以使用,主要数据存储为mongdb数据库, 3.根据mn和站点号码绑定在一起 4.数据异常,数据超标做了一些处理 本文参考博客使用更加方便!...
  • 环保数据采集.rar

    2019-12-01 10:01:48
    基于.net core的环保协议(hj/t 212-2005)数据采集并转发到阿里云物联网平台,支持多设备采集上传,支持windows/linux系统环境
  • java数据采集

    2018-04-24 15:36:53
    这是一个java数据采集的方法,可以从其他页面抓取内容,存放到自己数据口,然后再展示到自己相应的页面。希望能帮到你们。或者你们也许会从中得到启发。
  • MDC是一套实时的机床数据采集系统,是领先的机床监控与数据采集系统。MDC 提供强大的机床数据实时采集功能,可以显示所有机床的实时状态以及生产完成情况。MDC可提供强大的数据分析能力,可以给您提供机床利用率、...
  • Java数据采集

    2019-04-16 01:26:28
    NULL 博文链接:https://xiaoss.iteye.com/blog/1779432
  • java sdk 新浪微博数据采集代码

    热门讨论 2014-08-22 09:43:18
    新浪微博最新数据采集数据采集,利用进程控制程序的采集频率,将采集的数据写进指定的文件夹中,采集的数据还进行了去重操作
  • 公司在大数据领域积累的核心关键技术,包括在海量数据采集、存储、清洗、分析挖掘、可视化、智能应用、安全与隐私保护等领域。 SDK 简介 SensorsAnalytics SDK 是国内第一家开源商用版用户行为采集 SDK,目前支持...
  • Gather java实现的数据采集系统: 采集测试类
  • 该项目需要实现人体红外传感器与温度传感器的实时数据采集从而控制工位风扇的开关首先需要打开连接设备的Zigbee以及ADAM4150然后需要采集人体红外传感器与温度传感器的数据最后需要做出判断温度以及人体红外的联动...
  • 基于Java的OPC数据采集系统的设计与实现.pdf
  • java代码视频数据和音频数据采集

    千次阅读 2017-03-10 23:15:43
    我们经常用直播,但是直播怎么做呢?前面的文章已经搭建好了推流服务器,现在就让我们先从采集数据开始吧,然后压缩数据,然后推流数据等等,一步步来,一定会成个大胖纸的。加油!

    我们经常用直播,但是直播怎么做呢?前面的文章已经搭建好了推流服务器,现在就让我们先从采集数据开始吧,然后压缩数据,然后推流数据等等,一步步来,一定会成个大胖纸的。加油!

    Activity.java

    public class MainActivity extends Activity {
    
        static final String URL = "rtmp://112.74.96.116/live/jason";
        private LivePusher live;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surface);
            //相机图像的预览
            live = new LivePusher(surfaceView.getHolder());
        }
    
        /**
         * 开始直播
         * @param btn
         */
        public void mStartLive(View view) {
            Button btn = (Button)view;
            if(btn.getText().equals("开始直播")){
                live.startPush(URL);
                btn.setText("停止直播");
            }else{
                live.stopPush();
                btn.setText("开始直播");
            }
        }
    
        /**
         * 切换摄像头
         * @param btn
         */
        public void mSwitchCamera(View btn) {
            live.switchCamera();
        }
    
    }

    Push业务

    定义接口Pusher.java

    public abstract class Pusher {
        public abstract void startPush();
        public abstract void stopPush();
        public abstract void release();
    }

    视频Push
    VideoPusher.java

    public class VideoPusher extends Pusher implements Callback, PreviewCallback{
    
        private SurfaceHolder surfaceHolder;
        private Camera mCamera;
        private VideoParam videoParams;
        private byte[] buffers;
        private boolean isPushing = false;
        private PushNative pushNative;
    
        public VideoPusher(SurfaceHolder surfaceHolder, VideoParam videoParams, PushNative pushNative) {
            this.surfaceHolder = surfaceHolder;
            this.videoParams = videoParams;
            this.pushNative = pushNative;
            surfaceHolder.addCallback(this);
        }
        @Override
        public void startPush() {
            isPushing = true;
        }
        @Override
        public void stopPush() {
            isPushing = false;
        }
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            startPreview();
        }
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
        }
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
        }
        @Override
        public void release() {
            stopPreview();
        }
        /**
         * 切换摄像头
         */
        public void switchCamera() {
            if(videoParams.getCameraId() == CameraInfo.CAMERA_FACING_BACK){
                videoParams.setCameraId(CameraInfo.CAMERA_FACING_FRONT);
            }else{
                videoParams.setCameraId(CameraInfo.CAMERA_FACING_BACK);
            }
            //重新预览
            stopPreview();
            startPreview();
        }
        /**
         * 开始预览
         */
        private void startPreview() {
            try {
                //SurfaceView初始化完成,开始相机预览
                mCamera = Camera.open(videoParams.getCameraId());
                mCamera.setPreviewDisplay(surfaceHolder);
                //获取预览图像数据
                buffers = new byte[videoParams.getWidth() * videoParams.getHeight() * 4];
                mCamera.addCallbackBuffer(buffers);
                mCamera.setPreviewCallbackWithBuffer(this);
    
                mCamera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /**
         * 停止预览
         */
        private void stopPreview() {
            if(mCamera != null){            
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
        }
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            if(mCamera != null){
                mCamera.addCallbackBuffer(buffers);
            }
    
            if(isPushing){
                //回调函数中获取图像数据,然后给Native代码编码
                pushNative.fireVideo(data);
            }
        }
    }

    音频AudioPusher.java

    public class AudioPusher extends Pusher{
    
        private AudioParam audioParam;
        private AudioRecord audioRecord;
        private boolean isPushing = false;
        private int minBufferSize;
        private PushNative pushNative;
    
        public AudioPusher(AudioParam audioParam, PushNative pushNative) {
            this.audioParam = audioParam;
            this.pushNative = pushNative;
    
            int channelConfig = audioParam.getChannel() == 1 ? 
                    AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO; 
            //最小缓冲区大小
            minBufferSize = AudioRecord.getMinBufferSize(audioParam.getSampleRateInHz(), channelConfig, AudioFormat.ENCODING_PCM_16BIT);
            audioRecord = new AudioRecord(AudioSource.MIC, 
                    audioParam.getSampleRateInHz(), 
                    channelConfig, 
                    AudioFormat.ENCODING_PCM_16BIT, minBufferSize);
        }
    
        @Override
        public void startPush() {
            isPushing = true;
            //启动一个录音子线程
            new Thread(new AudioRecordTask()).start();
        }
    
        @Override
        public void stopPush() {
            isPushing = false;
            audioRecord.stop();
        }
    
        @Override
        public void release() {
            if(audioRecord != null){
                audioRecord.release();
                audioRecord = null;
            }
        }
        class AudioRecordTask implements Runnable{
            @Override
            public void run() {
                //开始录音
                audioRecord.startRecording();
                while(isPushing){
                    //通过AudioRecord不断读取音频数据
                    byte[] buffer = new byte[minBufferSize];
                    int len = audioRecord.read(buffer, 0, buffer.length);
                    if(len > 0){
                        //传给Native代码,进行音频编码
                        pushNative.fireAudio(buffer, len);
                    }
                }
            }
    
        }
    }
    

    push总类,音频视频同时push

    
    public class LivePusher implements Callback {
    
        private SurfaceHolder surfaceHolder;
        private VideoPusher videoPusher;
        private AudioPusher audioPusher;
        private PushNative pushNative;
    
        public LivePusher(SurfaceHolder surfaceHolder) {
            this.surfaceHolder = surfaceHolder;
            surfaceHolder.addCallback(this);
            prepare();
        }
    
        /**
         * 预览准备
         */
        private void prepare() {
            pushNative = new PushNative();
    
            //实例化视频推流器
            VideoParam videoParam = new VideoParam(480, 320, CameraInfo.CAMERA_FACING_BACK);
            videoPusher = new VideoPusher(surfaceHolder,videoParam,pushNative);
    
            //实例化音频推流器
            AudioParam audioParam = new AudioParam();
            audioPusher = new AudioPusher(audioParam,pushNative);
        }
    
        /**
         * 切换摄像头
         */
        public void switchCamera() {
            videoPusher.switchCamera();
        }
        /**
         * 开始推流
         */
        public void startPush(String url) {
            videoPusher.startPush();
            audioPusher.startPush();
            pushNative.startPush(url);
        }
        /**
         * 停止推流
         */
        public void stopPush() {
            videoPusher.stopPush();
            audioPusher.stopPush();
            pushNative.stopPush();
        }
        /**
         * 释放资源
         */
        private void release() {
            videoPusher.release();
            audioPusher.release();
            pushNative.release();
        }
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
    
        }
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
        }
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            stopPush();
            release();
        }
    }

    参数的设置:

    
    public class LivePusher implements Callback {
    
        private SurfaceHolder surfaceHolder;
        private VideoPusher videoPusher;
        private AudioPusher audioPusher;
        private PushNative pushNative;
    
        public LivePusher(SurfaceHolder surfaceHolder) {
            this.surfaceHolder = surfaceHolder;
            surfaceHolder.addCallback(this);
            prepare();
        }
    
        /**
         * 预览准备
         */
        private void prepare() {
            pushNative = new PushNative();
    
            //实例化视频推流器
            VideoParam videoParam = new VideoParam(480, 320, CameraInfo.CAMERA_FACING_BACK);
            videoPusher = new VideoPusher(surfaceHolder,videoParam,pushNative);
    
            //实例化音频推流器
            AudioParam audioParam = new AudioParam();
            audioPusher = new AudioPusher(audioParam,pushNative);
        }
    
        /**
         * 切换摄像头
         */
        public void switchCamera() {
            videoPusher.switchCamera();
        }
    
        /**
         * 开始推流
         */
        public void startPush(String url) {
            videoPusher.startPush();
            audioPusher.startPush();
            pushNative.startPush(url);
        }
    
    
        /**
         * 停止推流
         */
        public void stopPush() {
            videoPusher.stopPush();
            audioPusher.stopPush();
            pushNative.stopPush();
        }
    
        /**
         * 释放资源
         */
        private void release() {
            videoPusher.release();
            audioPusher.release();
            pushNative.release();
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
    
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            stopPush();
            release();
        }
    
    }
    
    package com.dongnaoedu.live.params;
    
    /**
     * 视频数据参数
     */
    public class VideoParam {
    
        private int width;
        private int height;
        private int cameraId;
    
        public VideoParam(int width, int height, int cameraId) {
            super();
            this.width = width;
            this.height = height;
            this.cameraId = cameraId;
        }
    
        public int getWidth() {
            return width;
        }
    
        public void setWidth(int width) {
            this.width = width;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public int getCameraId() {
            return cameraId;
        }
    
        public void setCameraId(int cameraId) {
            this.cameraId = cameraId;
        }
    
    }

    当然数据有了,我们必须通过C++代码完成操作,所以如下:

    
    /**
     * 调用C代码进行编码与推流
     */
    public class PushNative {
    
        public native void startPush(String url);
    
        public native void stopPush();
    
        public native void release();
    
        /**
         * 设置视频参数
         * @param width
         * @param height
         * @param bitrate
         * @param fps
         */
        public native void setVideoOptions(int width, int height, int bitrate, int fps);
    
        /**
         * 设置音频参数
         * @param sampleRateInHz
         * @param channel
         */
        public native void setAudioOptions(int sampleRateInHz, int channel);
    
    
        /**
         * 发送视频数据
         * @param data
         */
        public native void fireVideo(byte[] data);
    
        /**
         * 发送音频数据
         * @param data
         * @param len
         */
        public native void fireAudio(byte[] data, int len);
    
        static{
            System.loadLibrary("dn_live");
        }
    }

    上面是第一节操作,我们后面的文章将慢慢介绍C++的实现,牵扯到jni的使用,可能会单独有一篇文章进行介绍,小朋友记得加关注哦。

    展开全文
  • FANUC数据采集

    2018-01-04 15:21:40
    适用于带以太网接口的FANUC数控机床,通过FANUC自带插件获取数据
  • java日志数据采集显示
  • 数据自动采集接口的实现需要依托于LabVIEW数据采集技术以及Java存储过程,在LabVIEW数据采集过程中引进Java存储过程,借助此接口可以实现实验室数据向船舶数字化平台的导入,有效节省人工操作环节。文章首先对LabVIEW...
  • 数据采集架构

    千次阅读 2020-05-05 20:03:34
    概述 一般来说,当在Hadoop集群上,有足够数据处理的时候,通常会有很多生产数据的服务器...所以这个中间系统(数据采集系统)就是将应用程序发送过来的信息转发到分布式的后台服务器集群上, ChuKwa ChuKwa是...

    概述

    一般来说,当在Hadoop集群上,有足够数据处理的时候,通常会有很多生产数据的服务器。这些服务器的数量上百甚至成千上万。小的数据还可以直接从应用程序写入HDFS,但庞大数量的服务器试着将海量数据直接写入HDFS或者HBase集群,会因为多种原因导致重大问题。

    所以这个中间系统(数据采集系统)就是将应用程序发送过来的信息转发到分布式的后台服务器集群上,

    ChuKwa

    ChuKwa是一个开源的用于监控大部分分布式系统的数据采集系统,它是构建在Hadoop的HDFS和Map/Reduce框架之上的,继承了Hadoop的可伸缩性和鲁棒性。

    但此项目已不活跃。

    Flume

    Flume是Cloudera提供一个高可用的、高可靠的、分布式的海量日志采集、聚合和传输的系统。Flume支持在日志系统中定制各类数据发送方,用于数据收集;同时,Flume提供对数据进行简单处理,并写到各种数据接收方的能力。

    数据发生器产生的数据被单个运行Flume所在服务器上的Agent所收集,然后数据收容器从各个agent上汇集数据并将采集到的数据存入到HDFS或者HBase中。

    在整个数据传输的过程中,流动的是事件(Event)。事件是Flume内部数据传输的最基本单元。它是由一个可选头部和一个负载数据的字节数组(该数据组是从数据源接入点传入,并传输给传输器(HDFS/HBase))构成。

    Flume系统首先将event进行封装,然后利用agent进行其解析,并依据规则传输给HBase或HDFS。

    扇入就是Source可以接受多个输入,扇出就是Sink可以将数据输出多个目的地。

    Flume实际上是一个分布式的管道架构,可以看做在数据源和目的地之间有一个agent的网络,并支持数据路由

    数据路由

    Flume Agent包括Source、Channel、Sink组成。

    Source

    Source负责接收数据,并将接受的数据以Flume的event格式进行封装,然后将其传递到一个或者多个通道(channel)。

    Source是可以进行配置的

    memory:内存

    avro:对象序列化的一种技术,

    port:端口是7877.例:服务器是一栋房子,这栋房子有很多窗户,端口就可以看作为窗户

    Channel

    Channel只是一个暂时的存储容器,它将从Source出接收到的event格式的数据缓存起来,在Source和Sink之间起着一个桥梁的作用。Channel是一个完整的事务,这一点保证了在收发时的一致性,并且它可以和任意数量的Source和Sink链接。

     Memory Channel:写入内存。非持久化存储,断电、宕机丢失信息

    File Channel:写入文件

    Sink

    Sink负责从管道中读出数据并发给下一个Agent或者最终目的地。

    运行机制

    Flume的核心是Agent,Agent对外有两个进行交互的地方,一个是接受数据输入的Source,一个是数据输出Sink。Source将接收到的数据发送给Channel,Channel作为一个数据缓冲区会暂时存放这些数据,随后Sink会将Channel中的数据发送给指定的地方,例如:HDFS。只有在Sink将Channel中的数据成功发送出去之后,Channel才将临时存放的数据进行删除,这保证了数据传输的可靠性和安全性。

    Flume还支持多级Flume的Agent。例如:Sink可以将数据写到下一个Agent的Source中

    为保证Flume的可靠性,Flume在Source和Channel之间采用Interceptors拦截器用来更改或者检查Flume的events数据。在多Channel情况下,Flume可以采用默认管道选择器(即,每一个管道传递的都是相同的events)或者多路复用通道选择器(依据每一个event的头部header的地址选择通道)实现Channel的选择。

    为了保证负载均衡,采用Sink线程用于激活被被选择的Sinks群中特定的sink

    Scribe

     Scribe是Facebook开发的分布式日志系统,它能够从各种日志源上收集日志,存储到一个中央存储系统上,以便于进行集中统计分析处理。它为日志的“分布式收集,统一处理”提供了一个可扩展的,高容错的方案。

    例如:当后端的存储系统崩溃时,Scribe会将数据写到本地磁盘上,当存储系统恢复正常后,Scribe将日志重新加载到存储系统中。

    Scribe由Scribe Agent、Scribe和存储系统三部分组成。

    Scribe Agent实际上是一个ThriftClient。各个数据源需要通过Thrift向Scribe传输数据,每条数据记录包含一个Category和一个Message,可以在Scribe配置中指定Thrift线程数,默认是3。

    Scribe Agent:a Thrift Client(客户端)

    Scribe:共享队列,以目录形式

    存储系统:采集信息的存储

    Thrift-远程过程调用框架

    Thrift入门

    在本地运行程序,在远端的服务器上有所感知(在客户端写代码,在服务器端执行对应代码)

    Kafka

    Kafka是一种分布式发布-订阅系统。构建实时数据管道和数据流应用程序,

    Kafka是一个作家的名字。

    Kafka类比于一个电商平台,所有信息都汇集于此

    kafka集群负责收生产者的数据,同时可能会将这些信息进行分类,分门别类管理信息。例如:topic2在broker1有,在broker2也有,当topic2都在broker的时候,海量数据过来时,系统的性能瓶颈就挺严重的。多个broker相当于我们将数据进行分布式处理,我们一个主题分布在不同的broker上边,当数据过来时我们根据实际情况进行负载均衡,来实现系统均衡。而且我们根据实际情况在cluster里边随机加入broker进行扩充。

    为避免有的broker旱的旱死,涝的涝死。Zookeeper就是一种进行协调的分布式节点的框架,提供一种机制来观察分布式节点工作的情况,从而实现比较好的负载均衡。

    Producer

    向kafka的主题(topic)提供数据。Producer决定向哪些主题发布?推送到哪些分区?以什么方式进行推送?

    Topics

    数据源可以使用Kafka按主题发布信息给订阅者

    Topics是消息的分类名。Kafka集群或Broker为每一个主题都会维护一个分区日志。每一个分区日志是有序的消息序列,并且消息是连续追加到分区日志上,且消息不可更改。分区中每条消息都会被分配顺序ID号,也被成为偏移量,它是在该分区中的唯一标识。Kafka集群保留了所有发布的消息,直至消息过期(只有过期的数据才会被自动清除以释放磁盘空间)

    一个主题可以有多个分区,这些分区可以作为并行处理单元,这样能使kafka有能力且有效的处理海量数据,这些分区日志会被分配到kafka集群中的多个服务器上进行处理,每个分区也会备份到kafka集群的多个服务器上。

    Topics消息会被均匀的分布到Partition()0、Partition1、Partition2分区日志中,每个Partition中的消息都是有序的,生产的消息被不断追加到PartitionLog上,其中的每一个消息都被赋予了一个唯一的偏移值(offset)

    Kafka为每个分区分配一台服务器作为leader,用于处理所有分区的读和写请求。且为每个分区分配另个或多个服务器作为follower。Follower服务器对leader服务器中的分区进行备份,一旦leader服务器宕机,其他的某个Follower服务器会被选为Leader。

    Consumers

    Kafka提供一种单独的消费者抽象,此抽象具有两种模式的特征消费组,Queuing和Publish-SubScribe。消费者使用相同的消费组名字来标识。Kafka支持以组的形式消费Topic,也可以各成一个。 

    Push和Pull机制

    Producer到Broker的过程是Push(有数据送到Broker);而Consumer到Broker的过程是Pull。它通过Consumer主动获取数据,而不是Broker把数据主动发送到Consumer端的。

    这种Push-and-Pull消息传输机制,这种机制,让Consumer可以自主决定是否批量的从Broker接收数据。

    Zookeeper

    作为一种分布式服务框架,提供协调和同步分布式系统各节点的资源配置等服务,是分布式系统一致性服务的软件。Kafka主要是利用Zookeeper解决分布式应用中遇到的数据管理问题,如名称服务、集群管理、分布式应用配置项的管理等。

    多个Broker协同合作、Producer和Consumer部署在各个业务逻辑中被调用都是通过Zookeeper管理协调请求和转发。

    通过Zookeeper管理实现了高性能的分布式消息发布订阅系统。

    Kafka架构核心特性

    1)压缩功能

    Kafka支持对消息进行压缩,在Producer端进行压缩之后,在Consumer端须进行解压。

    进行压缩减少传输的数据量,减轻对网络传输的压力

    为了区分消息是否进行压缩,Kafka在消息头部添加了一个描述压缩属性字节,这个字节的后两位表示消息的压缩采用的编码,如果后两位为0,则表示消息未被压缩。

    2)消息可靠性

    为保证消息传输成功,当一个消息被发送后,Producer会等待Broker成功接收到消息的反馈(可设置参数控制等待时间),如果消息在途中丢失或是其中一个Broker挂掉,Producer会重新发送;Broker记录了Partition中的一个offset值,这个值指向Consumer下一个即将消费Message。当Consumer收到了消息,但却在处理过程中挂掉,此时Consumer可以通过这个Offset值重新找到上一个消息再进行处理。

    3)备份机制

    一个备份数量为n的集群允许有n-1个节点失败。在所有备份节点中,有一个节点作为Lead节点,这个节点保存了其他备份节点列表,并维持各个备份间的状态同步。

    Kafka的核心特征保证了其能保持高可靠性、容错性、可扩展性以及并发性的处理消息。

    实例

    ELK

    ELk

    ELK-概念

    Logstash:日志收集

    Inputs

    (各种数据、各种规模、是一个插件式架构)

    采集日志时将日志文件作为Logstash的input,还可以采集Redis(缓存数据库)中的数据,采集beats过来的数据

    Filter

    • 对收集的数据进行grok切分
    • 对收集的数据进行mutate操作(rename、update、replace、split)
    • 对收集的操作进行drop操作(删除满足条件的日志)
    • 对收集的数据进行clone操作(克隆后增加、克隆后删除)
    • 对收集的数据进行geoip操作(参照的IP地址库,添加IP地址对应的经纬度)

    Output

    output为ElasticSearch(例如:采集的数据输出到es,按天进行索引),也可以直接输出到图标后台(进行可视化,供上层人员进行决策)

    ES(Elasticsearch):日志存储,索引

    ElasticSearch是一个分布式、高扩展、高实时的搜索和数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用ElasticSearch的水平伸缩性,能使数据在生产环境中变得更有价值。

    Kibana:可视化(展示)和分析

     

     

    展开全文
  • 新浪微博最新数据采集SDK,作为参考,利用进程控制程序的采集频率,将采集的数据写进指定的文件夹中,采集的数据还进行了去重操作
  • 针对JVM的CPU使用及内存占用的性能分析,已经有各种剖析...本文将介绍如何集成Perf4j到Java应用程序中并生成性能数据。系统日志是应用程序问题诊断及运行维护的重要工具。Logback、Log4j是常用于Java平台的日志记录API.
  • Java实现网页数据采集

    千次阅读 2018-05-15 21:35:08
    最近,由于某些需要,用Java制做了一个网页数据采集器,用于将网页中需要的数据采集下来。&lt;/p&gt; 这里使用的方法,是先得到要采集的网页的源代码,然后从源代码中使用正则表达式得到要采集的数据。 ...
  • 基于Java实现的Modbus通信模块电气设备数据采集.pdf
  • 采用java技术构建的一个管理系统。整个开发过程首先对系统进行需求分析,得出系统的主要功能。接着对系统进行总体设计和详细设计。总体设计主要包括系统功能设计、系统总体结构设计、系统数据结构设计和系统安全设计...
  •    1.4 网络爬虫的采集策略 13    1.5 学习网络爬虫的建议 14    1.6 本章小结 15 第二章:网络爬虫涉及的Java基础知识 16    2.1 开发环境的搭建 16       2.1.1 JDK的安装及环境变量配置 16      ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,939
精华内容 30,375
关键字:

数据采集java

java 订阅