实现网络数据提取你需要哪些java知识

java

Ⅰ  首先对于一个java开发的项目有一个整体性的了解认知,项目开发流程:

项目阶段:

1) 项目准备:

  a) 根据开会得到会议纪要,了解客户的需求情况

  b) 需求分析(需求分析文档)

  c) 数据库设计和网站(产品)原型设计

  d) 架构设计

2) 项目开发

  a) 项目组长(PM,PL)进行项目的时间规划,并划分好每个人的工作任务

  b) 程序员主要完成项目代码编写和详细设计文档编写。(用户手册)

3) 测试

  a) 单元测试

  b) 集成测试

  c) 压力测试

  d) 回归测试

4) 上线实施

Ⅱ  三大特性(封装、继承、多态)

封装

1、  封装重点在于一个private关键字,目的是为了让类中的属性不能直接修改或取得。也就是说,建立一个类时,所有的属性都必须通过private进行封装。

      既然属性被封装了,那么如果想设置或取得属性,就必须编写getter/setter方法。

      同时,类中在创建对象时,为了方便,一般建议编写一些带参数的构造方法。

      如果不编写构造方法,程序会自动加入一个无参的构造,但是,如果自己声明了构造方法,那么必须就手工加入一个无参构造,为了让其他的框架可以通过无参数构造来创建对象。

2、  如果数据库中有一张表,则需要你能根据表编写一个这样的类。

      这种类被称为:VO(Value Object)、TO(Transfer Object)、POJO(Plain Olds Java Object)、DTO(DaTa Object)等

 1 class Person {

2 private String name;

3 private Integer age;

4 public Person() {

5 }

6 public Person(String name, Integer age) {

7 this.name = name;

8 this.age = age;

9 }

10 public String getName() {

11 return this.name;

12 }

13 public Integer getAge() {

14 return age;

15 }

16 public void setAge(Integer age) {

17 this.age = age;

18 }

19 public void setName(String name) {

20 this.name = name;

21 }

22 }

技巧:在eclipse中编写封装类,可以声明变量后,按shift+Alt+s键出现Generate  Getters  and  Setters提示创建getter和setter方法。

继承关系

继承所使用的关键字:extends,接口实现所使用的关键字是:implements。

Java开发中对于接口和抽象类区别主要是单继承和多继承。

真正开发中接口用的更多,几乎不编写抽象类。

一般都是以接口作为标准来进行声明。

这部分我们要求能够掌握接口的声明和实现方法。

 1 interface Animal {

2 public void cry();

3 public void run();

4 }

5 class Cat implements Animal {

6

7 @Override

8 public void cry() {

9 System.out.println("miao");

10 }

11 @Override

12 public void run() {

13 System.out.println("猫爬树");

14 }

15 }

多态

其实就是在继承的基础上进行方法覆写和子类转型。

 1 package org.liky.test;

2 public class InterfaceDemo {

3 public static void main(String[] args) {

4 Animal a1 = new Cat();

5 Animal a2 = new Dog();

6 a1.cry();

7 a2.cry();

8 }

9 }

10 interface Animal {

11 public void cry();

12 public void run();

13 }

14 class Cat implements Animal {

15 @Override

16 public void cry() {

17 System.out.println("miao");

18 }

19 @Override

20 public void run() {

21 System.out.println("猫爬树");

22 }

23 }

24 class Dog implements Animal {

25 @Override

26 public void cry() {

27 System.out.println("Wang");

28 }

29 @Override

30 public void run() {

31 System.out.println("狗游泳");

32 }

33 }

单例设计模式

单例模式有以下特点:

  1、单例类只能有一个实例。

  2、单例类必须自己创建自己的唯一实例。

  3、单例类必须给所有其他对象提供这一实例。

package org.liky.test;

public class TestSingleton {

public static void main(String[] args) {

Singleton s1 = Singleton.getInstance();

Singleton s2 = Singleton.getInstance();

Singleton s3 = Singleton.getInstance();

//其实只创建了一个对象

System.out.println(s1 + " --> " + s2 + " --> " + s3);

}

}

class Singleton {

private static final Singleton instance = new Singleton();

private Singleton() {

}

public static Singleton getInstance() {

return instance;

}

}

Ⅲ  IO操作

文件内容读取:

File、FileReader、FileWriter、BufferedReader、BufferedWriter、Scanner、InputStreamReader

文件夹遍历:

File 

文件复制操作

如果想操作文件的内容(对内容进行写出和读取),需要使用到的就是IO流中的输入输出操作。

这种输入和输出的操作流有两种:

1) 字符流:主要操作文本文件(编写爬虫操作时,肯定要使用字符流来完成)

a) 读:FileReader

b) 写:FileWriter

2) 字节流:所有文件都可以使用这种流操作

a) 读:InputStream

b) 写:OutputStream

需要能够通过我们这里的FileReader和FileWriter配合文件类:File,完成内容的读取和写出。

/**

* IO流操作的演示类,用来演示文本文件的写出和读取

*

* @author Liky

*

*/

public class FileTest {

public static void main(String[] args) {

// 写出内容

// writeData(

// "D:/test.txt",

// "这是“吉林一号”视频卫星 8月9日11时25分拍摄的 九寨沟县视频 显示了九寨沟县的地形地貌 县城呈狭长分布 周边山体有明显滑坡痕迹 视频中还可见县城道路大部分完好 有车辆通行 一架飞机飞过 地面与空中交通并未中断 图像提供:长光卫星技术有限公司 技术支持:北京爱太空科技发展有限公司");

System.out.println(readData("D:/test.txt"));

}

/**

* 写出数据

*

* @param filePath

* 文件保存的位置

* @param data

* 要保存的文件内容数据

*/

public static void writeData(String filePath, String data) {

// 先有一个文件,来保存要写出的数据

File file = new File(filePath);

// 建立输出流对象

try {

FileWriter writer = new FileWriter(file);

// 开始完成内容的输出

writer.write(data);

// 资源必须回收,也就是必须将流关闭

writer.close();

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 读取数据

*

* @param filePath

* 要读取的文件所在的完整路径

* @return 读取出来的文档内容

*/

public static String readData(String filePath) {

// 也要建立文件对象

File file = new File(filePath);

// 建立读取的输入流对象

try {

FileReader reader = new FileReader(file);

// 每次调用read可以读取一个字符,

// 按照int类型返回,返回的是字符的编码,

// 需要通过强制类型转换,变为char类型

// Java中对于String这个类一般不建议反复修改,因为会占用内存。

StringBuilder builder = new StringBuilder();

// 因为文件中有很多的字符,因此需要循环来进行内容的读取。

// 就需要判断是否还有字符进行读取

int value = -1;

// 每次读取时,如果读到内容,则会返回 0 - 65535 的char类型字符

// 如果没有读取到内容,则返回 -1 ,因此我们可以根据这个 -1 来判断后面是否还有内容

while ((value = reader.read()) != -1) {

// 将读取到的内容保存下来

char c = (char) value;

// 把字符放入到StringBuilder里

builder.append(c);

}

// 没有读取到内容,说明循环结束,已经到了文件的末尾

return builder.toString();

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

}

目前这样编写已经可以实现内容的输入和输出操作了。

但是还不支持换行操作,如果想换行,需要人工进行\r\n的编写。

如果不想人工编写换行,就可以使用以下两个类来完成输入。

PrintWriter(打印流)

BufferedWriter(缓冲流)

 1     public static void writeData(String filePath, String... data) {

2 // 先有一个文件,来保存要写出的数据

3 File file = new File(filePath);

4 // 建立输出流对象

5 try {

6 // FileWriter writer = new FileWriter(file);

7 PrintWriter pw = new PrintWriter(file);

8 // 开始完成内容的输出

9 for (String str : data) {

10 pw.println(str);

11 }

12 // 资源必须回收,也就是必须将流关闭

13 pw.close();

14 } catch (IOException e) {

15 e.printStackTrace();

16 }

17 }

使用时,注意我们这里加入了可变参数来动态传入多个字符串(即String...  data)。

当读取数据时,如果我们使用普通的读取方式,对于换行的处理不方便。

如果想按行读取内容,可以使用BufferedReader,Scanner

Scanner是JDK1.5新的

BufferedReader是JDK1.0就有的,所以使用BufferedReader。

为什么现在还使用BufferedReader,因为Scanner不支持编码的转换。

 1     public static String readData(String filePath) {

2 // 也要建立文件对象

3 File file = new File(filePath);

4 // 建立读取的输入流对象

5 try {

6 FileReader reader = new FileReader(file);

7 BufferedReader bw = new BufferedReader(reader);

8 // 每次调用read可以读取一个字符,

9 // 按照int类型返回,返回的是字符的编码,

10 // 需要通过强制类型转换,变为char类型

11 // Java中对于String这个类一般不建议反复修改,因为会占用内存。

12 StringBuilder builder = new StringBuilder();

13 // 因为文件中有很多的字符,因此需要循环来进行内容的读取。

14 // 就需要判断是否还有字符进行读取

15 String line = null;

16 // 每次读取时,如果读到内容,则会返回 0 - 65535 的char类型字符

17 // 如果没有读取到内容,则返回 -1 ,因此我们可以根据这个 -1 来判断后面是否还有内容

18 while ((line = bw.readLine()) != null) {

19 // 将读取到的内容保存下来

20 // 把字符放入到StringBuilder里

21 builder.append(line);

22 System.out.println(line);

23 }

24 // 没有读取到内容,说明循环结束,已经到了文件的末尾

25 return builder.toString();

26 } catch (Exception e) {

27 e.printStackTrace();

28 }

29

30 return null;

31 }

例如,将一个D盘的test.txt的内容读取出来,再写出到E盘的test.txt中

 

 1     public static void copyFile(String inputFile, String outputPath) {

2 // 首先建立输入和输出的文件

3 File input = new File(inputFile);

4 File output = new File(outputPath);

5 // 建立输入和输出流

6 try {

7 BufferedReader br = new BufferedReader(new FileReader(input));

8 PrintWriter pw = new PrintWriter(output);

9 // 每次读入一行,所以准备一个变量来接收

10 String line = null;

11 while ((line = br.readLine()) != null) {

12 pw.println(line);

13 }

14 pw.close();

15 br.close();

16 } catch (Exception e) {

17 e.printStackTrace();

18 }

19 }

 

文件夹迭代

这里只需要用到一个File类,但需要用里面的一些方法来判断是文件还是文件夹

isFile():是否是文件

isDirectory():是否是文件夹

还需要通过递归操作,将目录下的所有子目录也进行迭代。

多线程处理

使用多线程的目的肯定是为了提升程序的效率。

因为在进行网络数据爬取时,一般都是同时爬取多个网页的数据,而不是单个网页,因此在项目开发中我们需要通过多线程,来让程序同时完成多个操作。

多线程有两种实现方式:

1) 继承Thread类

2) 实现Runnable接口

使用多线程时,还有两个必须注意的方法:

1) start()启动线程

2) run()编写线程执行的主体。

先来完成一个倒计时功能:

public class ThreadDemo {

public static void main(String[] args) {

// new MyThread().start();

// new Thread() {

// public void run() {

// for (int i = 10; i >= 0; i--) {

// System.out.println("剩余时间:" + i);

// try {

// Thread.sleep(100);

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

// }

// }

// }.start();

// new Thread(new MyRunnable()).start();

}

}

//继承Thread类必须重写run类

class MyThread extends Thread {

@Override

public void run() {

for (int i = 10; i >= 0; i--) {

System.out.println("剩余时间:" + i);

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

class MyRunnable implements Runnable {

@Override

public void run() {

for (int i = 10; i >= 0; i--) {

System.out.println("剩余时间:" + i);

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

 

类集处理

List:允许重复,可以根据下标来取得数据,会按照放入的顺序来存储数据。

    ArrayList:以数组的形式存储,适合不经常变动,但经常查询的数据集。

    LinkedList:以链表的形式存储,适合经常变动的数据集,但是不经常查询

 1 public class ListDemo {

2 public static void main(String[] args) {

3 LinkedList<Integer> list1 = new LinkedList<>();

4 for (int i = 0; i <= 100000; i++) {

5 list1.add(i);

6 }

7 long start = System.currentTimeMillis();

8 for (int i = 0; i <= 100000; i++) {

9 list1.get(i);

10 }

11 long end = System.currentTimeMillis();

12 System.out.println("ArrayList: " + (end - start) + " ms");

13 }

14 }

Set:不允许重复,存储顺序看心情,没办法根据下标取得数据

    HashSet:散列排序(没有顺序)

    TreeSet:二叉树排序,按照固定的规则来排序,TreeSet中的内容必须实现一个Comparable的接口,并且必须覆写compareTo的方法,根据给定的规则来排序。

 1 public class SetDemo {

2 public static void main(String[] args) {

3 Set<Person> set = new TreeSet<>();

4 set.add(new Person("张三", 12));

5 set.add(new Person("李四", 22));

6 set.add(new Person("王五", 42));

7 set.add(new Person("王八", 42));

8 set.add(new Person("赵六", 32));

9 System.out.println(set);

10 }

11 }

12

13 class Person implements Comparable<Person> {

14 private String name;

15 private Integer age;

16

17 public Person() {

18 super();

19 }

20

21 public Person(String name, Integer age) {

22 super();

23 this.name = name;

24 this.age = age;

25 }

26

27 public String getName() {

28 return name;

29 }

30

31 public void setName(String name) {

32 this.name = name;

33 }

34

35 public Integer getAge() {

36 return age;

37 }

38

39 public void setAge(Integer age) {

40 this.age = age;

41 }

42

43 @Override

44 public String toString() {

45 return "Person [name=" + name + ", age=" + age + "]";

46 }

47 @Override

48 public int compareTo(Person o) {

49 if (this.age > o.age) {

50 return 1;

51 } else if (this.age < o.age) {

52 return -1;

53 }

54 if (this.name.equals(o.name)) {

55 return 0;

56 }

57 return 1;

58 }

59 }

Map:key-value形式,可以根据key取得value,key按照Set集合的模式来保存。

    HashMap:散列

    TreeMap:有顺序

对于Map集合,要求能够循环迭代出里面的所有数据。

所以必须掌握Map的循环方法。

 1 public class MapDemo {

2 public static void main(String[] args) {

3 Map<String, Integer> map = new HashMap<>();

4 map.put("方便面", 20);

5 map.put("火腿肠", 120);

6 map.put("矿泉水", 20);

7 map.put("可乐", 30);

8

9 // Map集合如果想迭代必须先按照key来进行迭代,

10 // 再根key查找value

11 Set<String> keySet = map.keySet();

12 for (String key : keySet) {

13 System.out.println(key + " ---> " + map.get(key));

14 }

15 }

16 }

小结:

本篇对于java封装、继承、多态三大特性,IO操作,线程管理,类集处理(List、Set、Map)进行了阐述以及代码实现。

到此,对于网页数据的爬写的知识准备的可以了,下一篇我会先对一个文件进行数据爬取,然后再对网页上的数据代码实现爬虫功能。

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是 实现网络数据提取你需要哪些java知识 的全部内容, 来源链接: utcz.com/z/389769.html

回到顶部