关于JAVA的多线程爬虫

来源:互联网 发布:怎么开启mysql服务 编辑:程序博客网 时间:2024/04/30 03:32

前言

以前喜欢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);    }}
0 0
原创粉丝点击