Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 266|回复: 0

[网络编程学习]用Java编写HTML文件分析程序

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-31 00:00:13 | 显示全部楼层 |阅读模式
    一、概述

    Web服务器的核心是对HTML文件中的各标记(Tag)作出正确的分析,一种编程语言的解释程序也是对源文件中的保留字进行分析再做解释的。实际应用中,我们也常常会遇到需要对某一特定类型文件进行关键字分析的情况,比如,需要将某个HTML文件下载并同时下载与之相关的. gif、.class等文件,此时就要求对HTML文件中的标记进行分离,找出所需的文件名及目录。在java出现以前,类似工作需要对文件中的每个字符进行分析,从中找出所需部分,不仅编程量大,且易出错。笔者在近期的项目中利用Java的输入流类StreamTokenizer进行HTML文件的分析,效果较好。在此,我们要实现从已知的Web页面下载HTML文件,对其进行分析后,下载该页面中包含的HTML文件(如果在Frame中)、图像文件和Class(Java Applet)文件。

    二、StreamTokenizer类

    StreamTokenizer即令牌化输入流的作用是将一个输入流变成令牌流。令牌流中的令牌实体有三类:单词(即多字符令牌)、单字符令牌和空白(包括Java和C/C++中的说明语句)。
       
      
       
      
      StreamTokenizer类的构造器为: StreamTokenizer(InputStream in)
    该类有一些公有实例变量:ttype、sval和nval ,分别表示令牌类型、当前字符串值和当前数字值。当我们需要取得令牌(即HTML中的标记)之间的字符时,应访问变量sval,而读向下一个令牌的方法是调用nextToken()。方法nextToken()的返回值是int型,共有四种可能的返回:
    StreamTokenizer.TT_NUMBER: 表示读到的令牌是数字,数字的值是double型,可以从实例变量nval中读取。
    StreamTokenizer.TT_WORD: 表示读到的令牌是非数字的单词(其他字符也在其中),单词可以从实例变量sval中读取。
    StreamTokenizer.TT_EOL: 表示读到的令牌是行结束符。
    如果已读到流的尽头,则nextToken()返回TT_EOF。
    开始调用nextToken()之前,要设置输入流的语法表,以便使分析器辨识不同的字符。WhitespaceChars(int low,  int hi)方法定义没有意义的字符的范围。WordChars(int low, int hi)方法定义构造单词的字符范围。

    三、程序实现

    1.HtmlTokenizer类的实现
    对某个令牌流进行分析之前,首先应对该令牌流的语法表进行设置,在本例中,即是让程序分出哪个单词是HTML的标记。下面给出针对我们需要的HTML标记的令牌流类定义,它是StreamTokenizer的子类:
    import java.io.*;
    import java.lang.String;

    class HtmlTokenizer extends StreamTokenizer {
    //定义各标记,这里的标记仅是本例中必须的,
      可根据需要自行扩充
    static int HTML_TEXT=-1;
    static int HTML_UNKNOWN=-2;
    static int HTML_EOF=-3;
    static int HTML_IMAGE=-4;
    static int HTML_FRAME=-5;
    static int HTML_background=-6;
    static int HTML_APPLET=-7;

    boolean outsideTag=true; //判断是否在标记之中

    //构造器,定义该令牌流的语法表。
    public HtmlTokenizer(BufferedReader r) {
    super(r);
    this.resetSyntax(); //重置语法表
    this.wordChars(0,255); //令牌范围为全部字符
    this.ordinaryChar("<"); //HTML标记两边的分割符
    this.ordinaryChar(">");
    } //end of constructor
    public int nextHtml(){
    int token; //令牌
    try{
    switch(token=this.nextToken()){
    case StreamTokenizer.TT_EOF:
      //如果已读到流的尽头,则返回TT_EOF
    return HTML_EOF;
    case "<":  //进入标记字段
    outsideTag=false;
    return nextHtml();
    case ">": //出标记字段
    outsideTag=true;
    return nextHtml();
    case StreamTokenizer.TT_WORD:
      //若当前令牌为单词,判断是哪个标记
    if (allWhite(sval))
    return nextHtml();//过滤其中空格
    else if(sval.toUpperCase().indexOf("FRAME")!=-1 &&!outsideTag) //标记FRAME
    return HTML_FRAME;
    else if(sval.toUpperCase().indexOf("IMG")!=-1 &&!outsideTag) //标记IMG
    return HTML_IMAGE;
    else if(sval.toUpperCase().indexOf("BACKGROUND")!=-1 &&!outsideTag)
      //标记BACKGROUND
    return HTML_BACKGROUND;
    else if(sval.toUpperCase().indexOf("APPLET")!=-1 &&!outsideTag) //标记APPLET
    return HTML_APPLET;
    default:
    System.out.println ("Unknown tag: "+token);
    return HTML_UNKNOWN;
    } //end of case
    }catch(IOException e){
    System.out.println("Error:"+e.getMessage());}
    return HTML_UNKNOWN;
    } //end of nextHtml
    protected boolean allWhite(String s){ //过滤所有空格
    //实现略
    }// end of allWhite

    }  //end of class
    2.HTML文件分析和下载程序
    利用上面自行编写的令牌化流,下面即可对HTML文件加以分析,并下载所有相关文件。本例中使用以字节为单位下载文件的方法,而非按字符下载,目的是可以下载不同类型的文件(如JPG或CLASS类型的文件)。限于篇幅,仅给出部分实现方法。
    //分析HTML文件
    void getIt(){
    String filename;
    String theUrl; // HTML文件的URL地址

    String tmpFileName;
    StringTokenizer st;
    String tmp=null;
    FileInputStream fin;
    InputStreamReader in;
    BufferedReader reader=null;
    int tagType;

    //变量theUrl表示该HTML页面的位置
    if(theUrl.toUpperCase().endsWith("HTML") ||theUrl.toUpperCase().endsWith("HTM")){
      try{
    fin=new FileInputStream(theCurrentPath+filename);
    //读入该HTML文件
    in=new InputStreamReader(fin);
    reader=new BufferedReader(in);
      }catch(FileNotFoundException e){
    System.out.println(e.getMessage());
                }
    HtmlStream=new HtmlTokenizer(reader);
    //生成类HtmlTokenizer的实例读该令牌流,并做分析
    while((tagType=HtmlStream.nextHtml())!=HtmlStream.HTML_EOF){
    if(tagType==HtmlStream.HTML_IMAGE){ // 标记<IMG>
    st=new StringTokenizer(HtmlStream.sval,“”);
    //sval即“<IMG”之后直到下一标记之间的字符
    while(st.hasMoreTokens()){
    tmp=st.nextToken();
        if(tmp.toUpperCase().trim().startsWith(“SRC")){
           tmpPath=tmp.substring(tmp.indexOf(“")+1,
           tmp.lastIndexOf(‘/")); //取该图形文件存放的相对目录
           tmpFileName=tmpPath.substring(tmpPath.indexOf(‘/")+1);
           //取文件名
           catchHtmlFile(theUrl,tmpPath,tmpFileName); //下载该文件
        } //end of if
    } //end of while
    } //end of if
    else if(tagType==HtmlStream.HTML_FRAME){
    // 处理同上,取出各框架中的HTML文件名,分别下载。
    } //end of else if
    else if(tagType==HtmlStream.HTML_BACKGROUND){
    //略
    } //end of the first while
    }//end of first if
    } //end of getIt

    //下载HTML文件,并存放在相应的本地目录下
    private void catchHtmlFile(String currentUrl,String thePath,String theFileName){
    FileOutputStream fs=null;
    InputStream in=null;
    DataOutputStream ds=null;
    File dir;
    int ch;
    final int BUFFER=2048; //输入缓冲区长度
    byte buff[]=new byte[BUFFER];
    try{
    url=new url(/currentUrl); //建立与目标文件的连接
    uc=url.openConnection();
    }catch(MalformedURLException e){
    System.out.println(“Malformed URL String!");}
    catch(IOException e){
    System.out.println(e.getMessage());}

    try{
    in=uc.getInputStream();
    }catch(IOException e){
    System.out.println(e.getMessage());}
    try{
    dir=new File(thePath);
    if(!dir.exists()) //判断本地目录是否存在
    dir.mkdir();
    File file=new File(thePath,theFileName);
    fs=new FileOutputStream((thePath+theFileName),false);
    }catch(FileNotFoundException e){
    System.out.println
    (“File cannot be set up:"+thePath+theFileName);}
    catch(IOException e){
    System.out.println(e.getMessage());}
    ds=new DataOutputStream(fs);
    try{
    while((ch=in.read(buff))!=-1) //读入字节,并写入本地文件
    ds.write(buff,0,ch);
    }catch(IOException e){
    System.out.println(e.getMessage());}
    try{
    in.close();
    ds.close();
    }catch(IOException e){
    System.out.println(“Error in closing I/O Stream!");}
    }//end of catchHtmlFile
      

      
      
       
       

         
       

         
       
      
      
      

      










    源码下载:http://www.hnzz3z.com:8103/zz3zcwb/cwb/dir2/no
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-19 01:55 , Processed in 0.383386 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表