java多线程-爬电影天堂上的电影下载地址
获取网页html
刚开始做的时候,在网上搜了一下资料。然后找到了一个获取网页最简单的dome,如下。
public static String getHtml(String urlstring) throws IOException {//得到地址URL url = new URL(urlstring);//建立连接URLConnection conn = url.openConnection();//获得数据BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "gbk"));StringBuilder html = new StringBuilder();String line;//正则表达式匹配
// String reg = "\\w+@\\w+";
// Pattern pattern = Pattern.compile(reg);while ((line = bufferedReader.readLine()) != null) {html.append(line);}return html.toString();}
于是就按照这个开始编写我自己的爬虫。
如何爬url
获取电影详情URL
我发现电影天堂的网址是很有规律的。比如它的最新电影列表的url是:”http://www.ygdy8.net/html/gndy/dyzz/list_23_NUM.html“,NUM是1到258
所以我就没有用爬虫爬url,直接就循环NUM来获取它页面下电影详情的url。因为这个url数量不多,我就没有考虑用多线程。直接其爬完,然后序列化到文件中保存起来。
public class SpiderForMovies extends Spider{private static Vector<String> urlList = new Vector<String>();@Overridepublic void execute(String url) throws IOException {//根据Url地址获取网页内容String html = HttpUtils.getHtml(url);if (html == null){throw new RuntimeException("无法获取url网址内容");}//对网页内容进行分析和提取Document doc = Jsoup.parse(html);Elements tables = doc.select("table.tbspan");//class等于tbspan的table标签Elements links = tables.select("a[href]"); //带有href属性的a元素for (Element link : links) {String linkHref = link.attr("href");
// String linkHref = homepage + Href;//加入到Url队列urlList.add(linkHref);}}public Vector<String> getUrllist() {return urlList;}
}public static void getMovieUrl() throws IOException, InstantiationException, IllegalAccessException {Integer i = 1;while(i <= 258) {String url = url1.replace("NUM", i.toString());SpiderForMovies spiderForMovies = new SpiderForMovies();spiderForMovies.execute(url);Vector<String> temp = spiderForMovies.getUrllist();//合并两个hashseturlList.addAll(temp);i++;System.out.println(i);}Util.OutPut("E:\\ling\\url.txt",urlList);}
获取电影下载地址
上面总共爬到了八十万的电影详情地址。那么肯定要使用多线程来爬取每个地址下的电影下载地址。在编写多线程获取的时候碰到了很多问题。
现在在爬下载地址了,又发现了很多问题。太大了不能一下子保存,看来还是要放到数据库中。
首先来看代码吧
//获取电影详情
public static void getMovieParticular() throws InterruptedException {int N = 8;CountDownLatch doneSignal = new CountDownLatch(N);CountDownLatch startSignal = new CountDownLatch(1);// 开始执行信号urlList = Util.InPut("E:\\ling\\url.txt");SpiderThread spiderThread = new SpiderThread(urlList,doneSignal,startSignal);for (int i = 1; i <= N; i++) {new Thread(spiderThread).start();// 线程启动了}System.out.println("begin------------");startSignal.countDown();// 开始执行啦doneSignal.await();// 等待所有的线程执行完毕movieList = spiderThread.getMovies();Util.OutPutMovie("E:\\ling\\Movie.txt", movieList);
// System.out.println(movieList);System.out.println("Ok");
}/*** 获取电影详情爬虫* Created by ling on 2015/5/25.*/
public class SpiderForMovParticular extends Spider {private Movie movie;@Overridepublic void execute(String url) throws IOException {movie = new Movie();//根据Url地址获取网页内容String homepage = "http://www.ygdy8.net";String html = HttpUtils.getHtml(homepage + url);if (html == null){throw new RuntimeException("无法获取url网址内容");}//对网页内容进行分析和提取Document doc = Jsoup.parse(html);//提取标题Element link = doc.select("div.title_all").last();//class等于title_all的div标签String title = link.text();//提取链接Elements elements = doc.select("div#Zoom");Element element = elements.select("a[href]").first();String href = element.attr("href");//加入到Movie中movie.setTitle(title);movie.setDownlodeUrl(href);}public Movie getMovie() {return movie;}
}/*** 爬虫线程* Created by ling on 2015/5/27.*/public class SpiderThread implements Runnable{//线程开始结束的信号private final CountDownLatch doneSignal;private final CountDownLatch startSignal;private static Vector<String> urlList;private static Set<Movie> movieSet = new HashSet<Movie>();private static int i = 0;public SpiderThread(Vector<String> urlList, CountDownLatch doneSignal,CountDownLatch startSignal) {SpiderThread.urlList = urlList;this.doneSignal = doneSignal;this.startSignal = startSignal;}@Overridepublic void run() {try {startSignal.await(); // 等待开始执行信号的发布SpiderForMovParticular spider = new SpiderForMovParticular();while (!urlList.isEmpty()) {//得到UrlString tmp = getAurl();if (tmp != null) {try {System.out.println(i + ":" + tmp);i++;spider.execute(tmp);movieSet.add(spider.getMovie());
// System.out.println(movieSet);} catch (IOException e) {e.printStackTrace();}}}} catch (InterruptedException e) {e.printStackTrace();}finally {doneSignal.countDown();}// SpiderForMovParticular spider = new SpiderForMovParticular();
// while (!urlList.isEmpty()) {// //得到Url
// String tmp = getAurl();
//
// if (tmp != null) {// try {// spider.execute(tmp);
// movieSet.add(spider.getMovie());
// } catch (IOException e) {// e.printStackTrace();
// }
// }
//
// }}public synchronized String getAurl() {if (urlList.isEmpty()){return null;}String tmpAUrl;tmpAUrl = urlList.get(0);urlList.remove(0);return tmpAUrl;}public Set<Movie> getMovies() {return movieSet;}
}
首先是几个线程一起来爬存在UrlList中的地址。一开始就是用实现Runnable接口。
在run方法中:取出一个Url地址,执行爬虫的execute方法获取电影名称和下载地址,存在Movie对象中,再将此对象,加入MovieSet中。然后将MovieSet序列化到文件中。接下来可以将其放到数据库中。
过程就是这么简单,但是当用多线程方式将其实现时,碰到了如下几个问题:
1、从urlList中取url的时,同一个url多次被取出。
因为当多个线程同时去访问urlList取数据,就可能会取出相同的url。
所以应该在取出一条数据后将其删除,并保证其他线程不会同时取到别的线程去到的url。那么就要将取url这步同步。
public synchronized String getAurl() {if (urlList.isEmpty()){return null;}String tmpAUrl;tmpAUrl = urlList.get(0);urlList.remove(0);return tmpAUrl;}
2、多个线程如何在所有线程结束后将整个movieSet序列化
一开始我使用了 thread.join() 命令 ,看起来好像也可以使几个线程运行完以后再执行下面的步骤。但是这样做不规范。
后来我上网查了资料,使用了开始信号和结束信号作为线程开始和结束的标志。
//线程开始结束的信号private final CountDownLatch doneSignal;private final CountDownLatch startSignal;public SpiderThread(Vector<String> urlList, CountDownLatch doneSignal,CountDownLatch startSignal) {SpiderThread.urlList = urlList;this.doneSignal = doneSignal;this.startSignal = startSignal;}@Overridepublic void run() {try {startSignal.await(); // 等待开始执行信号的发布SpiderForMovParticular spider = new SpiderForMovParticular();while (!urlList.isEmpty()) {//得到UrlString tmp = getAurl();if (tmp != null) {try {System.out.println(i + ":" + tmp);i++;spider.execute(tmp);movieSet.add(spider.getMovie());synchronized (this) {if (movieSet.size() >= (10000)) {//储存movieSetsaveSet();}}
// System.out.println(movieSet);} catch (IOException e) {e.printStackTrace();}}}} catch (InterruptedException e) {e.printStackTrace();}finally {doneSignal.countDown();}//获取电影详情
public static void getMovieParticular() throws InterruptedException {int N = 8;CountDownLatch doneSignal = new CountDownLatch(N);CountDownLatch startSignal = new CountDownLatch(1);// 开始执行信号urlList = Util.InPut("E:\\ling\\url.txt");
// urlList = Util.InPut("G:\\test.txt");SpiderThread spiderThread = new SpiderThread(urlList,doneSignal,startSignal);for (int i = 1; i <= N; i++) {new Thread(spiderThread).start();// 线程启动了}System.out.println("begin------------");startSignal.countDown();// 开始执行啦doneSignal.await();// 等待所有的线程执行完毕//只有所有线程执行完毕后才执行接下来的几部movieList = spiderThread.getMovies();Util.OutPutMovie("E:\\ling\\Movie\\MovieLast.txt", movieList);
// System.out.println(movieList);System.out.println("Ok");}
3、在一开始每次在movieSet中开几个线程,才有几个数据,前面的数据会被覆盖掉。找了很多,最后才发现原来是在SpiderForMovParticular类中,我将Movie 直接实例化了。就像:
private Movie movie = new Movie();
这样就不能每次都将不同的movie加入到movieSet中。
应该只创建一个引用,然后在方法中再实例化。
如:
public class SpiderForMovParticular extends Spider {private Movie movie;@Overridepublic void execute(String url) throws IOException {movie = new Movie();//根据Url地址获取网页内容String homepage = "http://www.ygdy8.net";String html = HttpUtils.getHtml(homepage + url);if (html == null){throw new RuntimeException("无法获取url网址内容");}//对网页内容进行分析和提取Document doc = Jsoup.parse(html);//提取标题String title = null;Element link = doc.select("div.title_all").last();//class等于title_all的div标签if (link != null){title = link.text();}//提取链接String href = null;Elements elements = doc.select("div#Zoom");Element element = elements.select("a[href]").first();if (element != null) {href = element.attr("href");}//加入到Movie中movie.setTitle(title);movie.setDownlodeUrl(href);}public Movie getMovie() {return movie;}
}
最后
总共爬到了825694条电影地址,现在还在爬电影的下载地址。应该很快就能爬完。
java多线程-爬电影天堂上的电影下载地址相关推荐
- 2020-10-18 今天来说说如何爬取猫眼上的电影信息
今天来说说如何爬取猫眼上的电影信息 最近小编试图使用requests+BeautifulSoup取去抓取猫眼上的电影信息,但尝试一番后,发现输出的电影评分.评分人数和票房都是乱码.案例见下面代码.之后 ...
- python3爬虫系列16之多线程爬取汽车之家批量下载图片
python3爬虫系列16之多线程爬取汽车之家批量下载图片 1.前言 上一篇呢,python3爬虫系列14之爬虫增速多线程,线程池,队列的用法(通俗易懂),主要介绍了线程,多线程,和两个线程池的使用. ...
- Java+Jsoup: 爬取二次元妹子图片并下载到本地(完整代码)
简介 这是一个基于Jsoup的用来爬取网页上图片并下载到本地的Java项目. 完整项目见 https://github.com/AsajuHuishi/CrawlByJsoup exe文件见getIm ...
- Java ftp实现文件的上传和下载ftp,sftp sun.net.ftp.FtpProtocolException:Welcome message: SSH-2.0-OpenSSH_5.1
Java ftp实现文件的上传和下载 ftp,sftp 运行后发现很长时间没有反应,很久以后抛出如下异常:sun.net.ftp.FtpProtocolException:Welcome messag ...
- Python 爬取电影天堂top最新电影
Python爬虫有他无可比拟的优势:语法简单,经常几十行代码就能轻松解决问题,相比于JAVA,C,PHP;第三方库丰富,Python强大而又丰富的第三方库使他几乎可以无所不能.今天我们就来用用Pyth ...
- [Java] 用java实现的电影天堂,飘花电影网的电影的下载地址抓取
1.之前看了一些论坛上有一个坛友用python写的抓取电影下载链接的,于是心血来潮的我也打算用java来写一个!其实并不是很难,下面附上代码 这是对电影天堂的电影的抓取的方法,(在此期间尝试设置代{过 ...
- 怎么用python爬豆瓣_python爬虫16 | 你,快去试试用多进程的方式重新去爬取豆瓣上的电影...
我们在之前的文章谈到了高效爬虫 在 python 中 多线程下的 GIL 锁会让多线程显得有点鸡肋 特别是在 CPU 密集型的代码下 多线程被 GIL 锁搞得效率不高 特别是对于多核的 CPU 来说 ...
- 利用python与requests爬取猫眼上的电影数据
@利用requests与pycharm爬取猫眼上排名前100的电影数据 首先是requests导包 源代码 import csv import reimport requests from reque ...
- [python爬虫之路day5]:实战之电影天堂2019精选电影爬取
**前言:**通过本次学习新掌握以下函数用法. map(lambda x:x+3,5) .startswith("ads ") .strip() 除去前后空格 a.format(1 ...
最新文章
- 最近公共祖先 LCA Tarjan算法
- 详解Java中的注解
- php无刷新分页插件,jQuery插件jPaginate实现无刷新分页_jquery
- python新闻管理系统_python项目——新闻管理系统
- python真正实现多线程_python多线程实现
- java简述垃圾回收原理及算法_Java垃圾回收原理和算法
- ABP入门系列(18)—— 使用领域服务
- 【ClickHouse 技术系列】- 在 ClickHouse 中处理实时更新
- 真正拿大厂offer的人,都赢在这一点
- 转载:做了5年运维,靠着这份监控知识体系,我从3K变成了40K
- linux有名管道 复用,关于LINUX有名管道的多路复用有关问题
- python画散点图
- ApowerREC v1.5.6.2 最佳屏幕录像机
- HFSS - 侧馈矩形微带天线设计与仿真
- word文档如何设置四级标题
- CentOS 7.3安装详解
- php 问号乱码,如何解决php问号乱码的问题
- 微信小程序游戏开发介绍,微信互动游戏有哪些?
- 基于FPGA的数字钟(四)——时钟控制模块
- 计算机网络 与信息安全专业就业,信息安全专业是学什么的 毕业后的就业方向有哪些...