IT_Programming/Java

[펌] HTML내 본문 추출 구현..

JJun ™ 2009. 4. 12. 23:40

출처: http://jakarta.tistory.com/category/Web%20by%20Agent 

 

 

 

다음, 네이버, 조선, 네이트 등등 여러 포탈의 기사들의 테스트를 해보았으나, 필터링의 정교함은 떨어지지만 그럭 저럭 기사통계 분석용도로 쓰기에는 불편함이 없어 보인다.

위와 같은 구현은 아래와 같은 단순한 방식을 사용하였다.

1. HTML 파싱후 Link가 없는 문자열중 length 값이 가장 큰값을 추출한다.

 private Node getMaxLengthNode()
 {
  TextNode maxLengthNode = null;
  boolean boolEntry = true;
  for(Node node : this.v_noAnchorNode)
  {
   if(node instanceof TextNode)
   {
    TextNode tNode = (TextNode)node;
    if(boolEntry)
    {
     maxLengthNode = tNode;
     boolEntry = false;
    }
    // -- 처리
    if(tNode.getParsedText().length() > maxLengthNode.getParsedText().length())
    {
     maxLengthNode = tNode;
    }
   }
  }
  log.println("==================================================");
  log.println("MaxLengthText>" + maxLengthNode);
  // this.extContentRange(maxLengthNode, 20);
  return maxLengthNode;
 }



2. length 큰값의 Token 기준 주변영역의 Non Anchored Text의 군집을 추출한다.

 private Vector<Node> extContentRange(Node maxNode, int range)
 {
  int minRange = 0, maxRange = 0;
  
  int maxTokenIndex = maxNode.getIndex();
  int maxIndex = this.v_noAnchorNode.indexOf(maxNode);
  log.println("Max index in the ResultVector :" + maxIndex + " ,max token index :" + maxTokenIndex);
  // this.v_noAnchorNode.
  int checkBase = maxIndex;
  boolean checkValid = true;
  while(checkValid)
  {
   Node beforeNode = this.v_noAnchorNode.get(maxIndex)
      ,node = this.v_noAnchorNode.get(--maxIndex);
   if((beforeNode.getIndex() - node.getIndex()) > range)
   {
    log.println("Before"
+ beforeNode+"");
    log.println("ext:" + (beforeNode.getIndex() - node.getIndex()));
    break;
   }
   if(maxIndex < 0)
   {
    checkValid = false;
   }
  }
  int minIdx = 0, maxIdx = 0;
  log.println("  - Min Value Node Index :" + this.v_noAnchorNode.get(maxIndex+1).getIndex());
  minIdx = this.v_noAnchorNode.get(maxIndex+1).getIndex();
  
  checkValid = true;
  while(checkValid)
  {
   Node beforeNode = this.v_noAnchorNode.get(checkBase)
      ,node = this.v_noAnchorNode.get(++checkBase);
   if((node.getIndex() - beforeNode.getIndex()) > range)
   {
    log.println("Before" + beforeNode+"");
    log.println("ext:" + (beforeNode.getIndex() - node.getIndex()));
    break;
   }
   if(checkBase >= this.v_noAnchorNode.size()-1)
   {
    checkValid = false;
   }
  }
  log.println("  - Max Value Node Index :" + this.v_noAnchorNode.get(checkBase).getIndex());
  maxIdx = this.v_noAnchorNode.get(checkBase).getIndex();
  
  Vector<Node> parsedList = this.parser.getTokenList();
  Vector<Node> v_ret = new Vector<Node>();
  
  
  log.println("length:" + parsedList.size());
  for(Node node : parsedList)
  {
   if(node.getIndex() >= minIdx-topMargin && node.getIndex() <= maxIdx)
   {
    v_ret.add(node);
    if(node.getIndex() == maxIdx) break;
   }
  }
  
  return v_ret;
 }



3. 최종적으로 Non Anchored Text의 Range를 추출, List형태로 반환하여 사용한다.

 public Vector<Node> getFilteredNodes() {
  Vector<Node> extContentRange = null;
  
  this.v_noAnchorNode = new Vector<Node>();
  
  Vector<Node> pList = this.parser.getParsedList();
  log.println("List Size :" + pList.size());
  for(Node node : pList)
  {
   if(node instanceof TagNode)
   {
    TagNode tagNode = (TagNode)node;
    if(tagNode.getTagName().equalsIgnoreCase("html"))
    {
     log.println("Find root node >" + node);
     // -- extract none anchor
     
     this.getNoneAnchorNode(node);      // 1.비 anchor 처리 textNode 추출
     Node maxLengthNode = this.getMaxLengthNode();  // 2.최대 영역추출
     extContentRange = this.extContentRange(maxLengthNode, extRange);
     
     log.println("========== extracted source ==========");
     for(Node xnode : extContentRange)
     {
      log.println(""+xnode);
     }
     // -- extract node anchor
     break;
    }
   }
  }
  return extContentRange;
 }


** Non Anchored 영역 내의 Anchor Text는 Non Anchored Text로 간주

    (이 부분의 구분을 위해서는 별도의 필터가 필요함)

Demo는 아래의 사이트에서 확인 가능
- [ Demo Site 바로가기 ]

 

[ 본 기능을 이용한 응용 구현 ]

- 웹페이지 필터링, 축약, 변환(핸드폰, 모바일용 웹페이지 변환 구현)
   http://jakarta.tistory.com/entry/웹페이지-필터링-축약-변환-1

- 웹페이지 주 내용영역 추출 및 해성도 변환 Demo
   http://jakarta.tistory.com/entry/웹-페이지-주-내용영역-추출-및-해상도-변환-Demo