hujin1979 发表于 2013-1-27 05:31:23

打造一个全能的解析器好像是比较困难的事情

  我们尝试用org.cyberneko.html.parsers.DOMParser来全面细致的分析互联网上的网站,但事实上由于各种技术流派的盛行导致了千变万化的网站技术,也导致了我们想细致分析每个页面成了一种理想状态的事情。
  但是,我们在能里和了解范围内还是希望把工作做得更周到,页面解析的类我写在一个叫ParseDocument.java的文件中,目前它能做到事情就是把取得的HTML代码进行分析,获取我们希望获得的数据并保存在对象中以供使用。我们还是先看看代码。 

import java.io.StringReader; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.HashMap; import org.cyberneko.html.parsers.DOMParser; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import com.ue.browser.Browser; import com.ue.browser.core.ElementCode; import com.ue.browser.core.HTMLElement; import com.ue.browser.Frame; import com.ue.browser.Iframe; public class ParseDocument { private ArrayList<HTMLElement> elements = new ArrayList<HTMLElement>(); private Browser browser; private HTMLElement element; private String text; private InputSource source; private static DOMParser parser = new DOMParser(); public boolean haveIframe = false; public boolean haveFrame = false; public ParseDocument(Browser browser) { super(); this.browser = browser; } public ArrayList<HTMLElement> getElements() { return elements; } public void setElements(ArrayList<HTMLElement> elements) { this.elements = elements; } public Browser getBrowser() { return browser; } public void setBrowser(Browser browser) { this.browser = browser; } public HTMLElement getElement() { return element; } public void setElement(HTMLElement element) { this.element = element; }    private static HashMap<String, String> elementMap = ElementCode.getElements(); private static String thePack = "com.ue.browser.html."; public void parse(String body){ try{ source = new InputSource(new StringReader(body)); //是否允许命名空间 parser.setFeature("http://xml.org/sax/features/namespaces", false); //是否允许增补缺失的标签。如果要以XML方式操作HTML文件,此值必须为真 parser.setFeature("http://cyberneko.org/html/features/balance-tags", true); //是否剥掉<script>元素中的<!-- -->等注释符 parser.setFeature("http://cyberneko.org/html/features/scanner/script/strip-comment-delims", true); parser.setFeature("http://cyberneko.org/html/features/augmentations", true); parser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower"); //解析HTML片段时是否作标签增补,此功能不要用在DOMParser上,而要用在DOMFragmentParser上 //parser.setFeature("http://cyberneko.org/features/document-fragment",true); //添加管道过滤器 /*XMLDocumentFilter noop = new DefaultFilter(); XMLDocumentFilter[] filters = { noop }; parser.setProperty("http://cyberneko.org/html/properties/filters", filters);*/ parser.parse(source); //cyberneko解析:将httpclien读取的数据source解析成w3c的Document对象 this.buildElements(parser.getDocument()); }catch(Exception e){ e.printStackTrace(); } }   //从w3c的Document节点对象中获取节点的属性放入对应的类中 public void buildElements(Node node){ int type = node.getNodeType(); switch (type) { // print the document element case Node.DOCUMENT_NODE: { this.buildElements(((org.w3c.dom.Document) node).getDocumentElement()); break; } // print element with attributes case Node.ELEMENT_NODE: { String name = node.getNodeName(); String clazz = elementMap.get(name); try{ if(clazz!=null){ Class<?> tt = Class.forName(thePack+clazz);             Constructor<?> c = tt.getConstructor(Browser.class);             element = (HTMLElement)c.newInstance(this.getBrowser());             NamedNodeMap attrs = node.getAttributes(); for (int i = 0; i < attrs.getLength(); i++) { Node attr = attrs.item(i); element.setAttribute(attr.getNodeName(), attr.getNodeValue()); }               elements.add(element); } }catch(Exception e){ e.printStackTrace(); } //查询子节点表,并构建子节点属性 NodeList children = node.getChildNodes(); if (children != null) { int len = children.getLength(); for (int i = 0; i < len; i++) this.buildElements(children.item(i)); } break; } // handle entity reference nodes case Node.ENTITY_REFERENCE_NODE: { break; } // print cdata sections case Node.CDATA_SECTION_NODE: { break; } // print text case Node.TEXT_NODE: { text = node.getNodeValue(); break; } /*//print script 注释节点<!--   -->   case Node.COMMENT_NODE: { script = node.getNodeValue(); System.out.println(script); break; }*/ // print processing instruction case Node.PROCESSING_INSTRUCTION_NODE: { break; } }   if (type == Node.ELEMENT_NODE) {    if(node.getNodeName().equals("TEXTAREA")){ element.setAttribute("value", text); } if (type == Node.ELEMENT_NODE) { if(node.getNodeName().equals("IFRAME")){ //如果有IFRAME节点,进行IFRAME处理 haveIframe = true; } } if (type == Node.ELEMENT_NODE) { if(node.getNodeName().equals("FRAME")){                   //如果有FRAME节点,进行FRAME处理 haveFrame = true; } }   if(node.getNodeName().equals("SCRIPT")){ if(text!=null){ element.setAttribute("daima", text); } } } } //获得当前节点的父节点名称 public String getParentNodeName(Node node){ Node parent = node.getParentNode(); String name = parent.getNodeName(); return name; } public boolean isHaveFrame() { return haveFrame; } public void setHaveFrame(boolean haveFrame) { this.haveFrame = haveFrame; } public boolean isHaveIframe() { return haveIframe; } public void setHaveIframe(boolean haveIframe) { this.haveIframe = haveIframe;   } } 
  重要的部分我都有中文注释,其实我觉得我还只能用中文注释会比较准确,英文对我来说,可能还不能把我想表达的意思正确告诉中国程序员。
  Class<?> tt = Class.forName(thePack+clazz);
  Constructor<?> c = tt.getConstructor(Browser.class);
  element = (HTMLElement)c.newInstance(this.getBrowser());
  可能这里对刚开始用java写程序的人来说要费劲理解一下,大家可以好好了解java的型别控制机制,然后对照实际的代码进行思考,这种设计模式其实在java应用中到处都在使用。
 
页: [1]
查看完整版本: 打造一个全能的解析器好像是比较困难的事情