笔记-网络爬虫实现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

相关推荐
hx8622714 分钟前
Java MySQL 连接
java·mysql·adb
lpfasd12316 分钟前
Kubernetes (K8s) 底层早已不再直接使用 Docker 引擎了
java·docker·kubernetes
aq553560020 分钟前
SpringBoot有几种获取Request对象的方法
java·spring boot·后端
CHENJIAMIAN PRO1 小时前
3D Tiles 2.0 技术审查整理笔记
笔记·3d
Detachym1 小时前
InsightFlow 服务配置优化与部署实践
java·spring boot·tomcat·maven·状态模式·jar
y = xⁿ1 小时前
【LeetCodehot100】T23:合并k个升序链表
java·数据结构·链表
kinl20181 小时前
cs2385_note0 (lec2-lec5)
笔记
NGC_66111 小时前
网络爬虫解析
爬虫
流水武qin1 小时前
SpringAI多模态的基本使用
java·spring boot·spring·ai
共享家95271 小时前
Java入门(多态)
java·开发语言