Java爬虫实战(二):抓取一个视频网站上2015年所有电影的下载链接

简介:

一 原理简介

       其实原理都跟第一篇文章差不多,不同的是鉴于这个网站的分类列表实在太多,如果不对这些标签加以取舍的话,需要花费的时间难以想象

wKiom1aEkt2Q8pl6AAIbgtJguRY014.png

 分类链接和标签链接都不要,不通过这些链接去爬取其他页面,只通过页底的所有类型电影的分页去获取其他页面的电影列表即可。同时,对于电影详情页面,仅仅只是抓取其中的电影标题和迅雷下载链接,并不进行深层次的爬行,详情页面的一些推荐电影等链接通通不要。

wKiom1aEkynSTrpPAAIy-OrLs0k412.png

       最后就是将所有获取到的电影的下载链接保存在videoLinkMap这个集合中,通过遍历这个集合将数据保存到MySQL里

注:如果对原理还是不够清晰的话,推荐看我的上一篇文章:http://www.zifangsky.cn/2015/12/java爬虫实战(一):抓取一个网站上的全部链接/

二 代码实现

       实现原理已经在上面说了,并且代码中有详细注释,因此这里就不多说了,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package  action;
 
import  java.io.BufferedReader;
import  java.io.IOException;
import  java.io.InputStream;
import  java.io.InputStreamReader;
import  java.net.HttpURLConnection;
import  java.net.MalformedURLException;
import  java.net.URL;
import  java.sql.Connection;
import  java.sql.PreparedStatement;
import  java.sql.SQLException;
import  java.util.LinkedHashMap;
import  java.util.Map;
import  java.util.regex.Matcher;
import  java.util.regex.Pattern;
 
public  class  VideoLinkGrab {
 
     public  static  void  main(String[] args) {
         VideoLinkGrab videoLinkGrab =  new  VideoLinkGrab();
         videoLinkGrab.saveData( "http://www.80s.la/movie/list/-2015----p" );
     }
 
     /**
      * 将获取到的数据保存在数据库中
     
      * @param baseUrl
      *            爬虫起点
      * @return null
      * */
     public  void  saveData(String baseUrl) {
         Map<String, Boolean> oldMap =  new  LinkedHashMap<String, Boolean>();  // 存储链接-是否被遍历
 
         Map<String, String> videoLinkMap =  new  LinkedHashMap<String, String>();  // 视频下载链接
         String oldLinkHost =  "" // host
 
         Pattern p = Pattern.compile( "(https?://)?[^/\\s]*" ); // 比如:http://www.zifangsky.cn
         Matcher m = p.matcher(baseUrl);
         if  (m.find()) {
             oldLinkHost = m.group();
         }
 
         oldMap.put(baseUrl,  false );
         videoLinkMap = crawlLinks(oldLinkHost, oldMap);
         // 遍历,然后将数据保存在数据库中
         try  {
             Connection connection = JDBCDemo.getConnection();
             for  (Map.Entry<String, String> mapping : videoLinkMap.entrySet()) {
                 PreparedStatement pStatement = connection
                         .prepareStatement( "insert into movie(MovieName,MovieLink) values(?,?)" );
                 pStatement.setString( 1 , mapping.getKey());
                 pStatement.setString( 2 , mapping.getValue());
                 pStatement.executeUpdate();
                 pStatement.close();
//              System.out.println(mapping.getKey() + " : " + mapping.getValue());
             }
             connection.close();
         catch  (SQLException e) {
             e.printStackTrace();
         }
     }
 
     /**
      * 抓取一个网站所有可以抓取的网页链接,在思路上使用了广度优先算法 对未遍历过的新链接不断发起GET请求, 一直到遍历完整个集合都没能发现新的链接
      * 则表示不能发现新的链接了,任务结束
     
      * 对一个链接发起请求时,对该网页用正则查找我们所需要的视频链接,找到后存入集合videoLinkMap
     
      * @param oldLinkHost
      *            域名,如:http://www.zifangsky.cn
      * @param oldMap
      *            待遍历的链接集合
     
      * @return 返回所有抓取到的视频下载链接集合
      * */
     private  Map<String, String> crawlLinks(String oldLinkHost,
             Map<String, Boolean> oldMap) {
         Map<String, Boolean> newMap =  new  LinkedHashMap<String, Boolean>();  // 每次循环获取到的新链接
         Map<String, String> videoLinkMap =  new  LinkedHashMap<String, String>();  // 视频下载链接
         String oldLink =  "" ;
 
         for  (Map.Entry<String, Boolean> mapping : oldMap.entrySet()) {
             // System.out.println("link:" + mapping.getKey() + "--------check:"
             // + mapping.getValue());
             // 如果没有被遍历过
             if  (!mapping.getValue()) {
                 oldLink = mapping.getKey();
                 // 发起GET请求
                 try  {
                     URL url =  new  URL(oldLink);
                     HttpURLConnection connection = (HttpURLConnection) url
                             .openConnection();
                     connection.setRequestMethod( "GET" );
                     connection.setConnectTimeout( 2500 );
                     connection.setReadTimeout( 2500 );
 
                     if  (connection.getResponseCode() ==  200 ) {
                         InputStream inputStream = connection.getInputStream();
                         BufferedReader reader =  new  BufferedReader(
                                 new  InputStreamReader(inputStream,  "UTF-8" ));
                         String line =  "" ;
                         Pattern pattern =  null ;
                         Matcher matcher =  null ;
                         //电影详情页面,取出其中的视频下载链接,不继续深入抓取其他页面
                         if (isMoviePage(oldLink)){
                             boolean  checkTitle =  false ;
                             String title =  "" ;
                             while  ((line = reader.readLine()) !=  null ) {
                                 //取出页面中的视频标题
                                 if (!checkTitle){
                                     pattern = Pattern.compile( "([^\\s]+).*?</title>" );
                                     matcher = pattern.matcher(line);
                                     if (matcher.find()){
                                         title = matcher.group( 1 );
                                         checkTitle =  true ;
                                         continue ;
                                     }
                                 }
                                 // 取出页面中的视频下载链接
                                 pattern = Pattern
                                         .compile( "(thunder:[^\"]+).*thunder[rR]es[tT]itle=\"[^\"]*\"" );
                                 matcher = pattern.matcher(line);
                                 if  (matcher.find()) {
                                     videoLinkMap.put(title,matcher.group( 1 ));
                                     System.out.println( "视频名称: "
                                             + title +  "  ------  视频链接:"
                                             + matcher.group( 1 ));
                                     break ;   //当前页面已经检测完毕
                                 }
                             }  
                         }
                         //电影列表页面
                         else  if (checkUrl(oldLink)){
                             while  ((line = reader.readLine()) !=  null ) {
 
                                 pattern = Pattern
                                         .compile( "<a href=\"([^\"\\s]*)\"" );
                                 matcher = pattern.matcher(line);
                                 while  (matcher.find()) {
                                     String newLink = matcher.group( 1 ).trim();  // 链接
                                     // 判断获取到的链接是否以http开头
                                     if  (!newLink.startsWith( "http" )) {
                                         if  (newLink.startsWith( "/" ))
                                             newLink = oldLinkHost + newLink;
                                         else
                                             newLink = oldLinkHost +  "/"  + newLink;
                                     }
                                     // 去除链接末尾的 /
                                     if  (newLink.endsWith( "/" ))
                                         newLink = newLink.substring( 0 ,
                                                 newLink.length() -  1 );
                                     // 去重,并且丢弃其他网站的链接
                                     if  (!oldMap.containsKey(newLink)
                                             && !newMap.containsKey(newLink)
                                             && (checkUrl(newLink) || isMoviePage(newLink))) {
                                         System.out.println( "temp: "  + newLink);
                                         newMap.put(newLink,  false );
                                     }
                                 }
                             }
                         }
 
                         reader.close();
                         inputStream.close();
                     }
                     connection.disconnect();
                 catch  (MalformedURLException e) {
                     e.printStackTrace();
                 catch  (IOException e) {
                     e.printStackTrace();
                 }
 
                 try  {
                     Thread.sleep( 1000 );
                 catch  (InterruptedException e) {
                     e.printStackTrace();
                 }
                 oldMap.replace(oldLink,  false true );
             }
         }
         // 有新链接,继续遍历
         if  (!newMap.isEmpty()) {
             oldMap.putAll(newMap);
             videoLinkMap.putAll(crawlLinks(oldLinkHost, oldMap));  // 由于Map的特性,不会导致出现重复的键值对
         }
         return  videoLinkMap;
     }
     
     /**
      * 判断是否是2015年的电影列表页面
      * @param url 待检查URL
      * @return 状态
      * */
     public  boolean  checkUrl(String url){
         Pattern pattern =  Pattern.compile( "http://www.80s.la/movie/list/-2015----p\\d*" );
         Matcher matcher = pattern.matcher(url);
         if (matcher.find())
             return  true ;   //2015年的列表
         else
             return  false ;
     }
     
     /**
      * 判断页面是否是电影详情页面
      * @param url  页面链接
      * @return 状态
      * */
     public  boolean  isMoviePage(String url){
         Pattern pattern =  Pattern.compile( "http://www.80s.la/movie/\\d+" );
         Matcher matcher = pattern.matcher(url);
         if (matcher.find())
             return  true ;   //电影页面
         else 
             return  false ;
     }
     
}

注:如果想要实现抓取其他网站的一些指定内容的话,需要将其中的一些正则表达式根据实际情况进行合理修改

三 测试效果

wKioL1aEk5LiQA3pAAFZpcGgbdU210.png

wKioL1aEk5Pz7FDYAAFQcrEAnqY514.png



本文转自 pangfc 51CTO博客,原文链接:http://blog.51cto.com/983836259/1730243,如需转载请自行联系原作者

相关文章
|
1月前
|
数据采集 JSON Java
Java爬虫获取1688店铺所有商品接口数据实战指南
本文介绍如何使用Java爬虫技术高效获取1688店铺商品信息,涵盖环境搭建、API调用、签名生成及数据抓取全流程,并附完整代码示例,助力市场分析与选品决策。
|
1月前
|
数据采集 数据挖掘 测试技术
Go与Python爬虫实战对比:从开发效率到性能瓶颈的深度解析
本文对比了Python与Go在爬虫开发中的特点。Python凭借Scrapy等框架在开发效率和易用性上占优,适合快速开发与中小型项目;而Go凭借高并发和高性能优势,适用于大规模、长期运行的爬虫服务。文章通过代码示例和性能测试,分析了两者在并发能力、错误处理、部署维护等方面的差异,并探讨了未来融合发展的趋势。
148 0
|
4天前
|
数据采集 Web App开发 机器学习/深度学习
Selenium爬虫部署七大常见错误及修复方案:从踩坑到避坑的实战指南
本文揭秘Selenium爬虫常见“翻车”原因,涵盖浏览器闪退、元素定位失败、版本冲突、验证码识别等七大高频问题,结合实战案例与解决方案,助你打造稳定高效的自动化爬虫系统,实现从“能用”到“好用”的跨越。
109 0
|
1月前
|
数据采集 存储 Rust
Rust爬虫实战:用reqwest+select打造高效网页抓取工具
在数据驱动时代,本文详解如何用Rust构建高效稳定爬虫系统。基于reqwest与select库,以books.toscrape.com为例,演示HTTP请求、HTML解析、分页抓取及数据存储全流程,涵盖同步与异步实现、反爬应对及性能优化,助你掌握Rust爬虫开发核心技能。
76 2
|
1月前
|
数据采集 存储 JSON
地区电影市场分析:用Python爬虫抓取猫眼/灯塔专业版各地区票房
地区电影市场分析:用Python爬虫抓取猫眼/灯塔专业版各地区票房
|
1月前
|
数据采集 存储 Web App开发
Python爬虫库性能与选型实战指南:从需求到落地的全链路解析
本文深入解析Python爬虫库的性能与选型策略,涵盖需求分析、技术评估与实战案例,助你构建高效稳定的数据采集系统。
246 0
|
1月前
|
数据采集 存储 XML
Python爬虫XPath实战:电商商品ID的精准抓取策略
Python爬虫XPath实战:电商商品ID的精准抓取策略
|
2月前
|
数据采集 存储 监控
Python爬虫实战:批量下载亚马逊商品图片
Python爬虫实战:批量下载亚马逊商品图片
|
2月前
|
数据采集 监控 网络协议
基于aiohttp的高并发爬虫实战:从原理到代码的完整指南
在数据驱动时代,传统同步爬虫效率低下,而基于Python的aiohttp库可构建高并发异步爬虫。本文通过实战案例解析aiohttp的核心组件与优化策略,包括信号量控制、连接池复用、异常处理等,并探讨代理集成、分布式架构及反爬应对方案,助你打造高性能、稳定可靠的网络爬虫系统。
177 0
|
2月前
|
数据采集 机器学习/深度学习 边缘计算
Python爬虫动态IP代理报错全解析:从问题定位到实战优化
本文详解爬虫代理设置常见报错场景及解决方案,涵盖IP失效、403封禁、性能瓶颈等问题,提供动态IP代理的12种核心处理方案及完整代码实现,助力提升爬虫系统稳定性。
180 0