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列表爬取网页元素
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); } }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
本文向大家介绍python支持多线程的爬虫实例,包括了python支持多线程的爬虫实例的使用技巧和注意事项,需要的朋友参考一下 python是支持多线程的, 主要是通过thread和threading这两个模块来实现的,本文主要给大家分享python实现多线程网页爬虫 一般来说,使用线程有两种模式, 一种是创建线程要执行的函数, 把这个函数传递进Thread对象里,让它来执行. 另一种是直接从Th
主要内容:多线程使用流程,Queue队列模型,多线程爬虫案例网络爬虫程序是一种 IO 密集型程序,程序中涉及了很多网络 IO 以及本地磁盘 IO 操作,这些都会消耗大量的时间,从而降低程序的执行效率,而 Python 提供的多线程能够在一定程度上提升 IO 密集型程序的执行效率。 如果想学习 Python 多进程、多线程以及 Python GIL 全局解释器锁的相关知识,可参考《Python并发编程教程》。 多线程使用流程 Python 提供了两个支持多线
本文向大家介绍python爬虫中多线程的使用详解,包括了python爬虫中多线程的使用详解的使用技巧和注意事项,需要的朋友参考一下 queue介绍 queue是python的标准库,俗称队列.可以直接import引用,在python2.x中,模块名为Queue。python3直接queue即可 在python中,多个线程之间的数据是共享的,多个线程进行数据交换的时候,不能够保证数据的安全性和一致性
本文向大家介绍python 中xpath爬虫实例详解,包括了python 中xpath爬虫实例详解的使用技巧和注意事项,需要的朋友参考一下 案例一: 某套图网站,套图以封面形式展现在页面,需要依次点击套图,点击广告盘链接,最后到达百度网盘展示页面。 这一过程通过爬虫来实现,收集百度网盘地址和提取码,采用xpath爬虫技术 1、首先分析图片列表页,该页按照更新先后顺序暂时套图封面,查看HTML结构。
本文向大家介绍python3爬虫中多线程进行解锁操作实例,包括了python3爬虫中多线程进行解锁操作实例的使用技巧和注意事项,需要的朋友参考一下 生活中我们为了保障房间里物品的安全,所以给门进行上锁,在我们需要进入房间的时候又会重新打开。同样的之间我们讲过多线程中的lock,作用是为了不让多个线程运行是出错所以进行锁住的指令。但是鉴于我们实际运用中,因为线程和指令不会只有一个,如果全部都进行lo
本文向大家介绍python实现爬虫统计学校BBS男女比例之多线程爬虫(二),包括了python实现爬虫统计学校BBS男女比例之多线程爬虫(二)的使用技巧和注意事项,需要的朋友参考一下 接着第一篇继续学习。 一、数据分类 正确数据:id、性别、活动时间三者都有 放在这个文件里file1 = 'ruisi\\correct%s-%s.txt' % (startNum, endNum) 数据格式为293