当前位置: 移动技术网 > IT编程>开发语言>Java > JAVA 多线程爬虫实例详解

JAVA 多线程爬虫实例详解

2019年07月22日  | 移动技术网IT编程  | 我要评论

java 多线程爬虫实例详解

前言

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

线程

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

runnable接口

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

thread类

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

synchronized关键字

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

利用加锁同步

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

线程池

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

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

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列表爬取网页元素

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);
  }
}

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网