获取网页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多线程-爬电影天堂上的电影下载地址相关推荐

  1. 2020-10-18 今天来说说如何爬取猫眼上的电影信息

    今天来说说如何爬取猫眼上的电影信息 最近小编试图使用requests+BeautifulSoup取去抓取猫眼上的电影信息,但尝试一番后,发现输出的电影评分.评分人数和票房都是乱码.案例见下面代码.之后 ...

  2. python3爬虫系列16之多线程爬取汽车之家批量下载图片

    python3爬虫系列16之多线程爬取汽车之家批量下载图片 1.前言 上一篇呢,python3爬虫系列14之爬虫增速多线程,线程池,队列的用法(通俗易懂),主要介绍了线程,多线程,和两个线程池的使用. ...

  3. Java+Jsoup: 爬取二次元妹子图片并下载到本地(完整代码)

    简介 这是一个基于Jsoup的用来爬取网页上图片并下载到本地的Java项目. 完整项目见 https://github.com/AsajuHuishi/CrawlByJsoup exe文件见getIm ...

  4. 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 ...

  5. Python 爬取电影天堂top最新电影

    Python爬虫有他无可比拟的优势:语法简单,经常几十行代码就能轻松解决问题,相比于JAVA,C,PHP;第三方库丰富,Python强大而又丰富的第三方库使他几乎可以无所不能.今天我们就来用用Pyth ...

  6. [Java] 用java实现的电影天堂,飘花电影网的电影的下载地址抓取

    1.之前看了一些论坛上有一个坛友用python写的抓取电影下载链接的,于是心血来潮的我也打算用java来写一个!其实并不是很难,下面附上代码 这是对电影天堂的电影的抓取的方法,(在此期间尝试设置代{过 ...

  7. 怎么用python爬豆瓣_python爬虫16 | 你,快去试试用多进程的方式重新去爬取豆瓣上的电影...

    我们在之前的文章谈到了高效爬虫 在 python 中 多线程下的 GIL 锁会让多线程显得有点鸡肋 特别是在 CPU 密集型的代码下 多线程被 GIL 锁搞得效率不高 特别是对于多核的 CPU 来说 ...

  8. 利用python与requests爬取猫眼上的电影数据

    @利用requests与pycharm爬取猫眼上排名前100的电影数据 首先是requests导包 源代码 import csv import reimport requests from reque ...

  9. [python爬虫之路day5]:实战之电影天堂2019精选电影爬取

    **前言:**通过本次学习新掌握以下函数用法. map(lambda x:x+3,5) .startswith("ads ") .strip() 除去前后空格 a.format(1 ...

最新文章

  1. 最近公共祖先 LCA Tarjan算法
  2. 详解Java中的注解
  3. php无刷新分页插件,jQuery插件jPaginate实现无刷新分页_jquery
  4. python新闻管理系统_python项目——新闻管理系统
  5. python真正实现多线程_python多线程实现
  6. java简述垃圾回收原理及算法_Java垃圾回收原理和算法
  7. ABP入门系列(18)—— 使用领域服务
  8. 【ClickHouse 技术系列】- 在 ClickHouse 中处理实时更新
  9. 真正拿大厂offer的人,都赢在这一点
  10. 转载:做了5年运维,靠着这份监控知识体系,我从3K变成了40K
  11. linux有名管道 复用,关于LINUX有名管道的多路复用有关问题
  12. python画散点图
  13. ApowerREC v1.5.6.2 最佳屏幕录像机
  14. HFSS - 侧馈矩形微带天线设计与仿真
  15. word文档如何设置四级标题
  16. CentOS 7.3安装详解
  17. php 问号乱码,如何解决php问号乱码的问题
  18. 微信小程序游戏开发介绍,微信互动游戏有哪些?
  19. 基于FPGA的数字钟(四)——时钟控制模块
  20. 计算机网络 与信息安全专业就业,信息安全专业是学什么的 毕业后的就业方向有哪些...

热门文章

  1. BW项目随手记:数据源无法激活使用问题,需同步至ODP数据源
  2. BZOJ P1856 字符串
  3. 解忧杂货店札记:回答在牛奶箱里
  4. 取带runas的一些优秀小工具介绍
  5. linux内核snat分析,Linux2.6.29.6内核netfilter代码中SNAT的过程跟踪
  6. python培训价格苏州
  7. 全球BT下载网站排名
  8. [ACW]826.单链表
  9. vue 请求后台数据
  10. 直播APP开发:直播源码流媒体技术介绍!