用java实现网络爬虫,实时获取中国地震台网数据

用java实现网络爬虫,实时获取中国地震台网数据

    • 1.如何从网络中爬取相关数据
    • 2.怎么进行数据处理
    • 3.绘图设计
    • 4. 存在问题:
    • 5.java程序的源文件
      • 5.1 爬虫程序
      • 5.2 绘制柱状图程序
      • 5.3 与Fortran的混编程序
      • 5.4 GUI界面程序
    • 6.程序的源代码文件和外包

用Python实现网络爬虫较为常见,而用java实现网络爬虫较少,本程序尝试使用Java网络爬虫,爬取中国地震台网近一年来的地震数据,地震一直是大家比较关心的话题,而地震的分布以及在我国哪些区域地震更为强烈对于非专业人士来说可能比较模糊,所以我希望通过javaGUI的方式,将地震数据进行处理并成像,以一种直观的方式呈献给大家。

1.如何从网络中爬取相关数据

如下图是中国地震台网上的地震数据:
用java实现网络爬虫,实时获取中国地震台网数据_第1张图片

而且该网站由于数据很多,所以存在翻页现象
用java实现网络爬虫,实时获取中国地震台网数据_第2张图片

所以爬取网页数据有两点问题:如何爬去数据,以及怎么实现翻页
爬取数据,首先要知道该网页的统一资源定位符,比如这个网页的统一资源定位符为:http://www.ceic.ac.cn/speedsearch?time=5&&page=1
源代码为:
用java实现网络爬虫,实时获取中国地震台网数据_第3张图片

该文件为HTML文件,程序中利用JSOUP外包进行解析
第二个问题就是怎么实现翻页,其实这些网页都有共性,如第二页数据的统一资源定位符为:http://www.ceic.ac.cn/speedsearch?time=5&&page=2
发现只是后面的page=?发生了变化,我们可以使用循环,但是循环到多少为止,代码中出现这样一行:
用java实现网络爬虫,实时获取中国地震台网数据_第4张图片

只要我们能读出53这个数,就知道了循环的次数了,程序是这样实现的:
用java实现网络爬虫,实时获取中国地震台网数据_第5张图片

最终爬取到了地震的数据,存于大文件夹下,resources\data.dat文件中
用java实现网络爬虫,实时获取中国地震台网数据_第6张图片

2.怎么进行数据处理

关于大型数据的处理,在java中一般由数据库来完成,但是由于本人能力有限,所以采用java和FORTRAN的混编,fortran是一种专门进行科学计算的高级语言,其实面向过程的语言呢,在科学计算领域具有很强的功能和较快的运算速度,实现java和FORTRAN的混编,借助VS+IVF软件,是微软的Visual Studio和Intel fortran,该软件可以将程序编译为可供其他程序调用的动态链接库文件,即dll文件:
用java实现网络爬虫,实时获取中国地震台网数据_第7张图片

实现Java与fortran的混编,需要用到jna-4.0.0.jar和jna.platform-4.0.0.jar文件
在java程序中的体现为:
用java实现网络爬虫,实时获取中国地震台网数据_第8张图片

3.绘图设计

该程序使用了柱状图来反映地震数据的相关结果,地震数据最好的成图方法是使用世界地图进行成像,但是本人能力有限,多次尝试也未能完成。
在该程序中使用了三维柱状图,调用了gnujaxp-1.0.0.jar、jcommon-1.0.16.jar、jfreechart-1.0.13.jar这三个外包,反映了近一年来世界地震的震级分布,在图中表现为在3-4级中间比较集中,地震学上定义,三级以上为有感地震,五级以上为破坏型地震,而对于八级以上地震更为罕见,破坏力极强,同时按照里氏震级分析,截至目前,世界上没有出现过九级以上地震,最大为智利8.9级地震,图中的第二幅图是列举我国地震最为频繁的四个省份,云南、西藏、新疆、四川,从图中可以看出新疆的近一年的地震次数最多,达到了210余次,四川次之,也有125次,而云南和西藏也同样在30次以上。如图所示:
用java实现网络爬虫,实时获取中国地震台网数据_第9张图片

  1. 界面设计
    本程序界面设计较为简单,在框架上,设置一个面板,在面板上有三个按钮,第一个按钮实现数据的爬取,第二个按钮实现数据的预处理,第三个按钮实现数据的绘图,每个按钮背后都对应了一个程序,加上界面程序,所以本次项目共有四个程序来完成这个数据采集与绘图的过程。
    用java实现网络爬虫,实时获取中国地震台网数据_第10张图片

4. 存在问题:

由于本人能力有限,程序中存在的问题还是有很多,比如调用了Windows操作系统的dll文件,所以该程序不具有跨平台性,而且界面设计过于简单,同时在按下第一个按钮是,确保计算机连接网络,不然程序会报错,同时会停滞,希望在以后能完善这个程序。

5.java程序的源文件

5.1 爬虫程序

package homework;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
/**
 * 程序功能:该程序用于从中国地震台网中心爬取近一年的地震数据
 * @author 陈浩
 * @version 1.0
 * */
public class URLdata {
     
	public void getdata() throws Exception {
     
   	 String str = "http://www.ceic.ac.cn/speedsearch?time=5&&page=";
   	 //添加字符输出缓冲流
   	 BufferedWriter bw = new BufferedWriter(new FileWriter("resources//data.dat"));
   	 //定义统一资源标识符
   	 URL url = null;
   	 //定义字符缓冲类
   	 StringBuffer sb = new StringBuffer();
   	 //定义字节输入流
   	 InputStream is = null;
   	 //定义字符输入流,可修改编码表
   	 InputStreamReader isr =null;
   	 //定义字符输入缓冲流
   	 BufferedReader bf =null;
   	 //定义文件类
   	 Document document = null;
   	 Elements element =null;
     url = new URL(str+""+1);
   	 is = url.openStream();
   	 isr = new InputStreamReader(is,"UTF-8");//使用"UTF-8"编码
   	 bf = new BufferedReader(isr);
   	 String line =null;
   	 while((line = bf.readLine())!= null){
     
   	     //System.out.println(line);
   	     sb.append(line+"\n");  //数据写入缓冲流中
   	 }
   	 //使用Jsoup进行html的解析
   	 document = Jsoup.parse(sb.toString()) ;
	    element = document.select("tr");//网页节点
	    for(int i=1;i<element.size();i++){
     
	    	bw.write(element.get(i).text()); //将数据写入文件中
  		    bw.newLine(); //写换行
  		    bw.flush();   //刷新
	    	//System.out.println();
	    }
	    Element ele = document.getElementById("pagenum");//网页节点
	    //目的为了读取翻页网页的数量,即该数据在很多相似的网页上
	    String string = ele.text().toString();
	    String[] arraystr = string.split(":");//分割字符串
	    Integer isign = new Integer(arraystr[2]);//字符变数组
	    int intsign = isign.intValue();   
	    bf.close();
	    sb.delete(0, sb.length());  
    //利用上面读到的翻页数量,进行网页的循环读取
   	for(int sign=2; sign<=intsign; sign++){
     
       	url = new URL(str+""+sign);
       	is = url.openStream();
       	isr = new InputStreamReader(is,"UTF-8");
       	bf = new BufferedReader(isr);
       	line =null;
       	while((line = bf.readLine())!= null){
     
       	     //System.out.println(line);
       	     sb.append(line+"\n");
       	}
   	    document = Jsoup.parse(sb.toString()) ;
   	    element =document.select("tr");
   	    for(int i=1;i<element.size();i++){
     
   	    	bw.write(element.get(i).text());
      		    bw.newLine();
      		    bw.flush();
   	    	//System.out.println(element.get(i).text());
   	    }
   	    bf.close();
   	    sb.delete(0, sb.length());
   	   
	     }
   	bw.close();
   	System.out.println("已全部加载完");
	     
    }

	
}

5.2 绘制柱状图程序

package homework;

import java.awt.Font;
import java.awt.GridLayout;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import javax.swing.JFrame;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;


public class BarChart {
     

	/**
	 * 程序功能:实现数据的绘图,本程序绘制了两张柱状图
	 */
	int[] barchart = new int[7];
	/**
	 * 调用改方法实现绘图
	 * */
	public static void Plot() {
     
		JFrame frame=new JFrame("数据绘图");
		   frame.setLayout(new GridLayout(2,2));//设置网格布局
		   frame.add(new BarChart().getChartPanel1()); //添加ChartPanel类
		   frame.add(new BarChart().getChartPanel2());
		   frame.setBounds(200,20, 900, 700);
		   
		   frame.setVisible(true);
		   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	ChartPanel frame1,frame2;
	CategoryDataset dataset =null;
	JFreeChart chart = null;
	public  BarChart(){
     
	
	   dataset = getDataSet1();//将获得的数据传递给CategoryDataset类的对象
       chart = ChartFactory.createBarChart3D(
      		                 "近一年地震震级分布", // 图表标题
                           "地震震级", // 目录轴的显示标签
                           "地震数量", // 数值轴的显示标签
                           dataset, // 数据集
                           PlotOrientation.VERTICAL, // 图表方向:水平、垂直
                           true, // 是否显示图例(对于简单的柱状图必须是false)
                           false,  // 是否生成工具
                           false  // 是否生成URL链接
                           );
      
       CategoryPlot plot=chart.getCategoryPlot();//获取图表区域对象
       CategoryAxis domainAxis=plot.getDomainAxis();         //水平底部列表
        domainAxis.setLabelFont(new Font("黑体",Font.BOLD,14));         //水平底部标题
        domainAxis.setTickLabelFont(new Font("宋体",Font.BOLD,12));  //垂直标题
        ValueAxis rangeAxis=plot.getRangeAxis();//获取柱状
        rangeAxis.setLabelFont(new Font("黑体",Font.BOLD,15));
         chart.getLegend().setItemFont(new Font("黑体", Font.BOLD, 15));
         chart.getTitle().setFont(new Font("宋体",Font.BOLD,20));//设置标题字体

        frame1=new ChartPanel(chart,true);  //这里也可以用chartFrame,可以直接生成一个独立的Frame
        
        dataset = getDataSet2();//将获得的数据传递给CategoryDataset类的对象
        chart = ChartFactory.createBarChart3D(
       		                 "中国地震多发地区数据分析", // 图表标题
                            "省份", // 目录轴的显示标签
                            "地震数量", // 数值轴的显示标签
                            dataset, // 数据集
                            PlotOrientation.VERTICAL, // 图表方向:水平、垂直
                            true, // 是否显示图例(对于简单的柱状图必须是false)
                            false,  // 是否生成工具
                            false  // 是否生成URL链接
                            );
       
        CategoryPlot plot1=chart.getCategoryPlot();//获取图表区域对象
        CategoryAxis domainAxis1=plot1.getDomainAxis();         //水平底部列表
         domainAxis1.setLabelFont(new Font("黑体",Font.BOLD,14));         //水平底部标题
         domainAxis1.setTickLabelFont(new Font("宋体",Font.BOLD,12));  //垂直标题
         ValueAxis rangeAxis1=plot1.getRangeAxis();//获取柱状
         rangeAxis1.setLabelFont(new Font("黑体",Font.BOLD,15));
          chart.getLegend().setItemFont(new Font("黑体", Font.BOLD, 15));
          chart.getTitle().setFont(new Font("宋体",Font.BOLD,20));//设置标题字体

         frame2=new ChartPanel(chart,true);  //这里也可以用chartFrame,可以直接生成一个独立的Frame
	}
	  
	/**
	 * 调用该方法实现从文件中获取近一年地震震级分布数据
	 * */
	   private  CategoryDataset getDataSet1() {
     
		   BufferedReader bw =null;
		   try {
     
				FileReader fr = new FileReader("resources\\summag.txt");
			    bw = new BufferedReader(fr);
				int i=0;
				String line = null;
				while( (line = bw.readLine()) != null ){
     
					//System.out.println(line);
					Integer dd = new Integer(line);
				    barchart[i] = dd.intValue();
				    //System.out.println(barchart[i]);
				    i++;
				}

			} catch (FileNotFoundException e) {
     
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
     
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
     
			    try {
     
			    	if(bw!=null)
					bw.close();
				} catch (IOException e) {
     
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		   
          DefaultCategoryDataset dataset = new DefaultCategoryDataset();
          dataset.addValue(barchart[0], "3级", "3");
          dataset.addValue(barchart[1], "4级", "4");
          dataset.addValue(barchart[2], "5级", "5");
          dataset.addValue(barchart[3], "6级", "6");
          dataset.addValue(barchart[4], "7级", "7");
          dataset.addValue(barchart[5], "8级", "8");
          dataset.addValue(barchart[6], "9级", "9");
          return dataset;   //返回dataset数据
	   }
		/**
		 * 调用该方法实现从文件中获取中国地震多发地区数据
		 * */
	   private  CategoryDataset getDataSet2() {
     
		   try {
     
				FileReader fr = new FileReader("resources\\sumarea.txt");
				BufferedReader bw = new BufferedReader(fr);
				int i=0;
				String line = null;
				while( (line = bw.readLine()) != null ){
     
					//System.out.println(line);
					Integer dd = new Integer(line);
				    barchart[i] = dd.intValue();
				    //System.out.println(barchart[i]);
				    i++;
				}

			} catch (FileNotFoundException e) {
     
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
     
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		   
          DefaultCategoryDataset dataset = new DefaultCategoryDataset();
          dataset.addValue(barchart[0], "云南", "云南");
          dataset.addValue(barchart[1], "西藏", "西藏");
          dataset.addValue(barchart[2], "新疆", "新疆");
          dataset.addValue(barchart[3], "四川", "四川");
          
          return dataset;
	   }

	public ChartPanel getChartPanel1(){
     
		   return frame1;
	
	   	}
	public ChartPanel getChartPanel2(){
     
		   return frame2;
	
	   	}

}

5.3 与Fortran的混编程序

package homework;

import com.sun.jna.Library;
/**
 * 接口功能:用于实现Java和FORTRAN的混编,Java调用动态链接库
 * */
public interface DLL extends Library{
     
	//定义一个抽象方法,该方法是在fortran程序下所写的子例行程序
	public abstract void READDATA();
}

附上Fortran源代码:

!************************************
!  程序功能:将java程序从网络爬取的数据进行相关处理
!-------------------------------------------------------c

    Subroutine readdata()
    !DEC$ ATTRIBUTES DLLEXPORT::readdata
    Implicit none
    integer i,j
    integer sum,sum3,sum4,sum5,sum6,sum7,sum8,sum9
    integer sumyn,sumxz,sumxj,sumsc
    integer intdatem,intdated
    real,allocatable::emag(:),latitude(:),longtitude(:)
    character*30,allocatable::area(:),date(:),time(:)
    character*30 str,carea,cdate
    sum=0
    open(10,file='resources\data.dat',status='old')
    do while(.not.eof(10))
        read(10,*)
        sum=sum+1
    end do
    rewind 10
    allocate(emag(sum),latitude(sum),longtitude(sum),area(sum),date(sum),time(sum))
    do i=1,sum
        read(10,*) emag(i),date(i),time(i),latitude(i),longtitude(i),str,area(i)
    end do
    close(10)
    
    sum3=0
    sum4=0
    sum5=0
    sum6=0
    sum7=0
    sum8=0
    sum9=0
    do i=1,sum,1
        if(emag(i)>=9) then
            sum9=sum9+1
        elseif(emag(i)>=8) then
            sum8=sum8+1
        elseif(emag(i)>=7) then
            sum7=sum7+1
        elseif(emag(i)>=6) then
            sum6=sum6+1
        elseif(emag(i)>=5) then
            sum5=sum5+1  
        elseif(emag(i)>=4) then
            sum4=sum4+1
        else
            sum3=sum3+1
        end if
    end do
    
    sumyn=0
    sumxz=0
    sumxj=0
    sumsc=0
    do i=1,sum,1
        carea=trim(adjustl(area(i)))
        if(carea(1:4)=='云南') then
            sumyn=sumyn+1
        elseif(carea(1:4)=='西藏') then
            sumxz=sumxz+1
        elseif(carea(1:4)=='新疆') then
            sumxj=sumxj+1
        elseif(carea(1:4)=='四川') then
            sumsc=sumsc+1
        end if
    end do    
    
    open(20,file='resources\summag.txt')
    write(20,100) sum3
    write(20,100) sum4
    write(20,100) sum5
    write(20,100) sum6
    write(20,100) sum7
    write(20,100) sum8
    write(20,100) sum9
    close(20)
100 format(g0)    
    open(30,file='resources\sumarea.txt')
    write(30,100) sumyn
    write(30,100) sumxz
    write(30,100) sumxj
    write(30,100) sumsc
    close(30)
    
    
    
    end subroutine

5.4 GUI界面程序

package homework;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.sun.jna.Native;


/**
 * 程序功能:总程序的入口,用于进行GUI设计*/
public class MyFrame {
     
    public MyFrame(){
     
    //定义一个框架
	final JFrame frame = new JFrame("中国地震台网信息实时获取系统");
	frame.setSize(400, 300);  //框架尺寸
	frame.setBounds(300, 100, 600, 500); //边界范围
	frame.setVisible(true);  //可显示
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置框架关闭方式
	JPanel panel = new JPanel(); //定义一个面板
	panel.setLayout(null);  //设置格局
	
	//设置三个按钮
	JButton button1 = new JButton("数据爬取");
	button1.setBounds(50,70 , 100,50 );
	button1.setFont(new Font("Dialog",1,15));
	//第一个按钮设置监听器,用于数据爬取程序的开启
	button1.addActionListener(new ActionListener() {
     
		
		@Override
		public void actionPerformed(ActionEvent e) {
     
			URLdata url = new URLdata();
			try {
     
				url.getdata();
			} catch (Exception e1) {
     
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	});
	
	JButton button2 = new JButton("数据预处理");
	button2.setBounds(200,70 , 120,50 );
	button2.setFont(new Font("Dialog",1,15));
	//按钮2设置监听器,用于调用FORTRAN程序,进行数据预处理
	button2.addActionListener(new ActionListener() {
     
		
		@Override
		public void actionPerformed(ActionEvent e) {
     
			DLL dll = (DLL) Native.loadLibrary("dlldata.dll", DLL.class);
			dll.READDATA();
		}
	});
	
	JButton button3 = new JButton("数据绘图");
	button3.setBounds(370,70 , 100,50 );
	button3.setFont(new Font("Dialog",1,15));
	//按钮三设置监听器,用于进行绘图程序调用
	button3.addActionListener(new ActionListener() {
     
		
		@Override
		public void actionPerformed(ActionEvent e) {
     
			BarChart.Plot();
		}
	});
	
	
	panel.add(button1);
	panel.add(button2);
	panel.add(button3);
    
	
	
	
	
	frame.add(panel);
	
    }
    
	@SuppressWarnings("unused")
	public static void main(String[] args) {
     
       MyFrame myframe = new MyFrame();
	}

}

6.程序的源代码文件和外包

源代码文件和外包
提取码:pbhg

你可能感兴趣的:(Java绘图,Java爬虫,Java与Fortran混编,java,编程语言)