笔记-网络爬虫实现java

目录:

1、爬虫原理

2、本地文件数据提取及分析

3、单网页数据的读取

4、运用正则表达式完成超连接的连接匹配和提取

5、广度优先遍历,多网页的数据爬取

6、多线程的网页爬取

7、总结

爬虫实现原理

网络爬虫基本技术处理

网络爬虫是数据采集的一种方法,实际项目开发中,通过爬虫做数据采集一般只有以下几种情况:

1) 搜索引擎

2) 竞品调研

3) 舆情监控

4) 市场分析

网络爬虫的整体执行流程:

1) 确定一个(多个)种子网页

2) 进行数据的内容提取

3) 将网页中的关联网页连接提取出来

4) 将尚未爬取的关联网页内容放到一个队列中

5) 从队列中取出一个待爬取的页面,判断之前是否爬过。

6) 把没有爬过的进行爬取,并进行之前的重复操作。

7) 直到队列中没有新的内容,爬虫执行结束。

这样完成爬虫时,会有一些概念必须知道的:

1) 深度(depth):一般来说,表示从种子页到当前页的打开连接数,一般建议不要超过5层。

2) 广度(宽度)优先和深度优先:表示爬取时的优先级。建议使用广度优先,按深度的层级来顺序爬取。

Ⅰ  在进行网页爬虫前,我们先针对一个飞机事故失事的文档进行数据提取的练习,主要是温习一下上一篇的java知识,也是为了下面爬虫实现作一个热身准备。

首先分析这个文档,,关于美国历来每次飞机失事的数据,包含时间地点、驾驶员、死亡人数、总人数、事件描述,一共有12列,第一列是标题,下面一共有5268条数据。

现在我要对这个文件进行数据提取,并实现一下分析:

根据飞机事故的数据文档来进行简单数据统计。

1) 哪年出事故次数最多

2) 哪个时间段(上午 8 -- 12,下午 12 -- 18,晚上 18 -- 24,凌晨 0 -- 8 )事故出现次数最多。

3) 哪年死亡人数最多

4)哪条数据的幸存率最高。

代码实现:(一切知识从源码获取!)

java 复制代码
 1 package com.plane;
  2 
  3 import java.io.*;
  4 import java.text.ParseException;
  5 import java.text.SimpleDateFormat;
  6 import java.util.*;
  7 /**
  8  * 飞机事故统计
  9  * @author k04
 10  *sunwengang    
 11  *2017-08-11
 12  */
 13 public class planeaccident {
 14         //数据获取存取链表
 15         private static List<String>  alldata=new ArrayList<>();
 16         
 17         public static void main(String args[]){            
 18             getData("飞行事故数据统计_Since_1908.csv");
 19             alldata.remove(0);
 20             //System.out.println(alldata.size());
 21             //死亡人数最多的年份
 22             MaxDeadYear();
 23             //事故发生次数最多的年份
 24             MaxAccidentsYear();
 25             //事故各个时间段发生的次数
 26             FrequencyPeriod();
 27             //幸村率最高的一条数据
 28              MaximumSurvival();        
 29         }
 30         
 31         /**
 32          * 从源文件爬取数据
 33          * getData(String filepath)
 34          * @param filepath
 35          */
 36         public static void getData(String filepath){
 37             File f=new File(filepath);
 38             //行读取数据
 39             try{
 40                 BufferedReader br=new BufferedReader(new FileReader(f));
 41                 String line=null;
 42                 while((line=(br.readLine()))!=null){
 43                     alldata.add(line);
 44                 }
 45                 br.close();
 46             }catch(Exception e){
 47                 e.printStackTrace();
 48             }
 49         }
 50         /**
 51          * 记录每年对应的死亡人数
 52          * @throws  
 53          * 并输出死亡人数最多的年份,及该年死亡人数
 54          */
 55         public static void MaxDeadYear(){
 56             //记录年份对应死亡人数
 57             Map<Integer,Integer> map=new HashMap<>();
 58             //时间用date显示
 59             SimpleDateFormat sdf=new SimpleDateFormat("MM/dd/YYYY");
 60             //循环所有数据
 61             for(String data:alldata){
 62                 //用逗号将数据分离,第一个是年份,第11个是死亡人数
 63                 String[] strs=data.split(",");
 64                 if(strs[0]!=null){
 65                     //获取年份
 66                     try {
 67                         Date date=sdf.parse(strs[0]);
 68                         int year=date.getYear();
 69                         //判断map中是否记录过这个数据
 70                         if(map.containsKey(year)){
 71                             //已存在,则记录数+该年死亡人数
 72                             map.put(year, map.get(year)+Integer.parseInt(strs[10]));
 73                         }else{
 74                             map.put(year, Integer.parseInt(strs[10]));
 75                         }
 76                         
 77                     } catch (Exception e) {
 78                         // TODO Auto-generated catch block
 79                         
 80                     }
 81                     
 82                 }
 83             }
 84             //System.out.println(map);
 85             
 86             //记录死亡人数最多的年份
 87             int max_year=-1;
 88             //记录死亡人数
 89             int dead_count=0;
 90             //用set无序获取map中的key值,即年份
 91             Set<Integer> keyset=map.keySet();
 92             //
 93             for(int year:keyset){
 94                 //当前年事故死亡最多的年份,记录年和次数
 95                 if(map.get(year)>dead_count&&map.get(year)<10000){
 96                     max_year=year;
 97                     dead_count=map.get(year);
 98                 }
 99             }
100             
101             System.out.println("死亡人数最多的年份:"+(max_year+1901)+"   死亡人数:"+dead_count);
102         }
103         /**
104          * 记录事故次数最多的年份
105          * 输出该年及事故次数
106          */
107         public static void MaxAccidentsYear(){
108             //存放年份,该年的事故次数
109             Map<Integer,Integer> map=new HashMap<>();
110             SimpleDateFormat sdf =new SimpleDateFormat("MM/dd/YYYY");
111             //循环所有数据
112             for(String data:alldata){
113                 String[] strs=data.split(",");
114                 if(strs[0]!=null){
115                     try {
116                         Date date=sdf.parse(strs[0]);
117                         //获取年份
118                         int year=date.getYear();
119                         //判断是否存在记录
120                         if(map.containsKey(year)){
121                             //已存在记录,+1
122                             map.put(year, map.get(year)+1);
123                         }else{
124                             map.put(year, 1);
125                         }
126                     } catch (Exception e) {
127                         // TODO Auto-generated catch block                        
128                     }                                                
129                 }
130             }
131             //记录事故次数最多的年份
132             int max_year=0;
133             //该年事故发生次数
134             int acc_count=0;
135             //循环所有数据,获取事故次数最多的年份
136             Set<Integer> keyset=map.keySet();
137             for(int year:keyset){
138                 if(map.get(year)>acc_count){
139                     max_year=year;
140                     acc_count=map.get(year);
141                 }
142             }
143             //输出结果
144             System.out.println("事故次数最多的年份"+(max_year+1901)+"  该年事故发生次数:"+acc_count);
145         }
146         /**
147          * FrequencyPeriod()
148          * 各个时间段发生事故的次数
149          */
150         public static void FrequencyPeriod(){
151             //key为时间段,value为发生事故次数
152             Map<String,Integer>  map=new HashMap<>();
153             //String数组存放时间段
154             String[] strsTime={"上午(6:00~12:00)","下午(12:00~18:00)","晚上(18:00~24:00)","凌晨(0:00~6:00)"};
155             //小时:分钟
156             SimpleDateFormat sdf=new SimpleDateFormat("HH:mm");
157             
158             for(String data:alldata){
159                 String[] strs=data.split(",");
160                 //判断时间是否记录,未记录则忽略
161                 if(strs[1]!=null){
162                     try {
163                         Date date=sdf.parse(strs[1]);
164                         //取得小时数
165                         int hour=date.getHours();
166                         //判断小时数在哪个范围中
167                         int index=0;
168                         if(hour>=12&&hour<18){
169                             index=1;
170                         }else if(hour>=18){
171                             index=2;
172                         }else if(hour<6){
173                             index=3;
174                         }
175                         //记录到map中
176                         if(map.containsKey(strsTime[index])){
177                             map.put(strsTime[index], map.get(strsTime[index])+1);
178                         }else{
179                             map.put(strsTime[index], 1);
180                         }                                                            
181                     } catch (ParseException e) {                        
182                     }                
183                 }
184                 
185             }
186             /*
187             System.out.println("各时间段发生事故次数:");
188             for(int i=0;i<strsTime.length;i++){        
189             System.out.println(strsTime[i]+" : "+map.get(strsTime[i]));
190             }        
191             */
192             // 记录出事故最多的时间范围
193             String maxTime = null;
194             // 记录出事故最多的次数
195             int maxCount = 0;
196 
197             Set<String> keySet = map.keySet();
198             for (String timeScope : keySet) {
199                 if (map.get(timeScope) > maxCount) {
200                     // 当前年就是出事故最多的年份,记录下年和次数
201                     maxTime = timeScope;
202                     maxCount = map.get(timeScope);
203                 }
204             }
205             System.out.println("发生事故次数最多的时间段:");
206             System.out.println(maxTime+" : "+maxCount);                            
207         }
208         /**
209          * 获取幸村率最高的一条数据的内容
210          * 返回该内容及幸存率
211          */
212         public static void MaximumSurvival(){
213             //存放事故信息以及该事故的幸村率
214             Map<String,Float> map=new HashMap<>();
215             //SimpleDateFormat sdf =new SimpleDateFormat("MM/dd/YYYY");
216             //事故幸存率=1-死亡率,第十一个是死亡人数,第十个是总人数
217             float survial=0;        
218             //循环所有数据
219             for(String data:alldata){
220                 try{
221                 String[] strs=data.split(",");
222                 //计算幸存率
223                 float m=Float.parseFloat(strs[10]);
224                 float n=Float.parseFloat(strs[9]);
225                 survial=1-m/n;
226                 map.put(data, survial);
227                 }catch(Exception e){
228                     
229                 }
230             }
231             //记录事故次数最多的年份
232             float max_survial=0;    
233             //幸存率最高的数据信息
234             String this_data="null";
235             //循环所有数据,获取事故次数最多的年份
236             Set<String> keyset=map.keySet();
237             for(String data:keyset){
238                 if(map.get(data)>max_survial){
239                     this_data=data;
240                     max_survial=map.get(data);
241                 }
242             }
243             System.out.println("幸存率最高的事故是:"+this_data);
244             System.out.println("幸存率为:"+survial);
245         }    
246 }

Ⅱ  接下来我们就可以在网页的数据上下手了。

下面先实现一个单网页数据提取的功能。

使用的技术可以有以下几类:

1) 原生代码实现:

a) URL类

2) 使用第三方的URL库

a) HttpClient库

3) 开源爬虫框架

a) Heritrix

b) Nutch

相关推荐
Abladol-aj14 分钟前
并发和并行的基础知识
java·linux·windows
清水白石00814 分钟前
从一个“支付状态不一致“的bug,看大型分布式系统的“隐藏杀机“
java·数据库·bug
xiaoyalian5 小时前
R语言绘图过程中遇到图例的图块中出现字符“a“的解决方法
笔记·r语言·数据可视化
吾日三省吾码6 小时前
JVM 性能调优
java
弗拉唐7 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
Red Red7 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全
oi777 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
贰十六7 小时前
笔记:Centos Nginx Jdk Mysql OpenOffce KkFile Minio安装部署
笔记·nginx·centos
少说多做3438 小时前
Android 不同情况下使用 runOnUiThread
android·java