JAVA 多线程爬虫实例详解

2025-05-29 0 78

JAVA 多线程爬虫实例详解

前言

以前喜欢Python的爬虫是出于他的简洁,但到了后期需要更快,更大规模的爬虫的时候,我才渐渐意识到Java的强大。Java有一个很好的机制,就是多线程。而且Java的代码效率执行起来要比python快很多。这份博客主要用于记录我对多线程爬虫的实践理解。

线程

线程是指一个任务从头至尾的执行流。线程提供了运行一个任务的机制。对于Java而言,可以在一个程序中并发地启动多个线程。这些线程可以在多处理器系统上同时运行。

runnable接口

任务类必须实现runnable接口,它只包含一个run方法。需要实现这个方法来告诉系统线程将如何运行。

Thread类

包含为任务而创建的线程的构造方法,以及控制线程的方法。

synchronized关键字

为避免竞争状态,防止多个线程同时进入程序的某个特定部分,即临界区,以便一次只有一个线程可以访问临界区。

利用加锁同步

Java可以显式加锁,一个锁是一个Lock接口的实例,它定义了加锁和释放锁的方法。

线程池

线程池是管理开发执行任务个数的理想方法。Java提供Executor接口来执行线程池中的任务,提供ExecutorService接口管理和控制任务。

使用线程池的方法获取url列表

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76
import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/*

* 获取京东评论url列表

*/

public class MyThreading {

private static String p_id = null;

private static Url urls = null;

public MyThreading(String p_id){

this.p_id = p_id ; // 京东商品的id

urls = new Url(p_id);

}

public List<String> getUriList(){

ExecutorService executor = Executors.newCachedThreadPool();

for (int i = 0 ; i < 600 ; i ++){

executor.execute(new AddUrl(i)); // 添加任务到线程池

}

executor.shutdown();

while (!executor.isTerminated()){}

return urls.getList();

}

public static class AddUrl implements Runnable{

int page;

public AddUrl(int page){

this.page = page;

}

public void run(){

urls.addList(page); // 启动多线程任务

}

}

public static class Url {

private static Lock lock = new ReentrantLock(); // 开启显式家锁

private static List<String> urlList = new ArrayList();

private String p_id;

public Url(String p_id ){

this.p_id = p_id ;

}

public List<String> getList(){

return urlList;

}

public void addList(int page){

lock.lock();

try{

String url = "http://club.jd.com/productpage/p-" + p_id + "-s-0-t-0-p-" + String.valueOf(page) + ".html";

// Thread.sleep(5);

urlList.add(url); //添加url到url列表

}catch(Exception ex ){

}

finally {

lock.unlock(); // 解锁

}

}

}

public static void main(String[] args) {

String p_id = "2441288";

MyThreading myThreading = new MyThreading(p_id);

List <String> urlList = myThreading.getUriList();

for(String url : urlList){

System.out.println(url);

}

System.out.println(urlList.size());

}

}

代码分析

  • 代码的作用:获取京东评论的url列表
  • 类的说明:MyThreading是主类, AddUrl和Url是它的内部类,AddUrl实现了runnable的接口,主要启动多线程服务运行Url的addList方法。而Url是最内核的部分 ,他提供addList任务和多线程的共享区域urlList,所以在实现添加url的步骤中,需要对urlList加锁。
  • 线程池主要有两种类型,一个是固定线程池,即newFixedThreadPool;另一个是newCachedThreadPool,这个主要利用了缓冲机制,能动态地添加线程。在上述代码中,我主要使用了newCachedthreadPool.

使用线程池的方法根据url列表爬取网页元素

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112
import java.io.BufferedReader;

import java.io.InputStreamReader;

import java.net.URL;

import java.net.URLConnection;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

public class ThreadingCrawel {

private static Content content = null;

private static List<String> urlList = null;

public ThreadingCrawel(List<String> urlList){

this.urlList = urlList;

content = new Content();

}

public List<String> getContent(){

ExecutorService executor = Executors.newCachedThreadPool();

for (String url : urlList){

executor.execute(new AddContent(url));

}

executor.shutdown();

while(!executor.isTerminated()){}

return content.getContent();

}

public static class AddContent implements Runnable{

String url;

public AddContent(String url){

this.url = url;

}

public void run(){

content.addContent(url);

}

}

public static class Content {

private static Lock lock = new ReentrantLock();

private static List<String> contentList = new ArrayList();

public void addContent(String url){

String content = "";

BufferedReader in = null;

try{

URL realUrl = new URL(url);

URLConnection connection = realUrl.openConnection();

in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "gbk"));

String line;

while( (line = in.readLine()) != null){

content += line +"\\n";

}

}catch(Exception e){

e.printStackTrace();

}

finally{

try{

if (in != null){

in.close();

}

}catch(Exception e2){

e2.printStackTrace();

}

}

Pattern p = Pattern.compile("content\\":\\".*?\\"");

Matcher match = p.matcher(content);

String tmp;

lock.lock();

while(match.find()){

tmp = match.group();

tmp = tmp.replaceAll("\\"", "");

tmp = tmp.replace("content:", "");

tmp = tmp.replaceAll("<.*?>", "");

contentList.add(tmp);

try {

Thread.sleep(1);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

lock.unlock();

}

public List getContent(){

return contentList;

}

}

public static void main(String[] args){

long start = System.currentTimeMillis();

String p_id = "2441288";

MyThreading myThreading = new MyThreading(p_id);

List <String> urlList = myThreading.getUriList();

ThreadingCrawel threadingCrawel = new ThreadingCrawel(urlList);

List <String> contentList = threadingCrawel.getContent();

for(String content : contentList){

System.out.println(content);

}

long end = System.currentTimeMillis();

System.out.println(end - start);

}

}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

原文链接:http://blog.csdn.net/qq_30843221/article/details/52486735

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 JAVA 多线程爬虫实例详解 https://www.kuaiidc.com/117159.html

相关文章

发表评论
暂无评论