Web-Harvest学习札记

Web-Harvest学习笔记
文章来源http://mxsfengg.blog.163.com/blog/static/2637021820085522154653/
这一章,我们来学习scraper的源码。

          首先,我们来看下scrape的构造函数,

public Scraper(ScraperConfiguration configuration, String workingDir) {
        this.configuration = configuration;
        this.runtimeConfig = new RuntimeConfig();
        this.workingDir = CommonUtil.adaptFilename(workingDir);

        this.httpClientManager = new HttpClientManager();

        this.context = new ScraperContext(this);
        this.scriptEngine = configuration.createScriptEngine(this.context);
        this.usedScriptEngines.put(configuration.getDefaultScriptEngine(), this.scriptEngine);
    }

传入的参数有两个,一个scraper的配置类,一个工作目录。其中下面是实例化ScraperConfiguration 的代码

        ScraperConfiguration config = new ScraperConfiguration("G:/web_harvest/crawlerSinger.xml");

其实就是向系统加载这个xml配置文件,这个配置文件中包括了抓取的流程,以及一些细节。

        当然,这个构造函数,还做了一些其他的事情:

         1     初始化了runtimeConfig

         2     初始化了workingDir

         3     初始化了httpClientManager

         4     初始化了context

         5     初始化了scriptEngine

         6     将scriptEngine 放进usedScriptEngines

上面出现了许多没有新类,为了下一步更好的对这个源码的理解,我觉得有必要对这些类进行一些探讨。

       一、ScraperConfiguration ,以下是ScraperConfiguration 的部分源码,

    public class ScraperConfiguration {

    //以下是四个常量的声明,从这里我们也可以看出web-harvest支持的动态语言有三种包括beanshell, javascript
    //和groovy。默认的编码是utf-8

    public static final String BEANSHELL_SCRIPT_ENGINE = "beanshell";
    public static final String JAVASCRIPT_SCRIPT_ENGINE = "javascript";
    public static final String GROOVY_SCRIPT_ENGINE = "groovy";

    public static final String DEFAULT_CHARSET = "UTF-8";

    // map of function definitions
    private Map functionDefs = new Catalog();//其实就是一个hashmap

    // sequence of operationDefs
    private List operations = new ArrayList();
   
    private String charset = DEFAULT_CHARSET;

    //可以看到默认情况下是支持beanshell的
    private String defaultScriptEngine = BEANSHELL_SCRIPT_ENGINE;

    private File sourceFile;
    private String url;

    /**
     *构造函数,从流中构造配置

     */
    public ScraperConfiguration(InputSource in) {
        createFromInputStream(in);

    }

/* 一个比较重要的方法,供构造函数调用,构造函数的主要的工作就是它做的*/  

private void createFromInputStream(InputSource in) {
        // loads configuration from input stream to the internal structure
        XmlNode node = XmlNode.getInstance(in);//xmlNode 是一个对xml的封装类,在此我们并不打算对它进行深 
                                                                          //究,只需记得它封装了对xml的操作。

        //设置charset,默认情况下是utf-8

        String charsetString = node.getString("charset");
        this.charset = charsetString != null ? charsetString : DEFAULT_CHARSET;

       //设置动态语言引擎类型,默认情况下支持beanshell

       String scriptEngineDesc = node.getString("scriptlang");
        if ( "javascript".equalsIgnoreCase(scriptEngineDesc) ) {
            this.defaultScriptEngine = JAVASCRIPT_SCRIPT_ENGINE;
        } else if ( "groovy".equalsIgnoreCase(scriptEngineDesc) ) {
            this.defaultScriptEngine = GROOVY_SCRIPT_ENGINE;
        } else {
            this.defaultScriptEngine = BEANSHELL_SCRIPT_ENGINE;
        }

        //遍历根元素的所有的子节点,将这些子结点放进operations中。这样初始化工作就基本ok了,下面就是对operations中的这些xml节点进行解析、执行。具体的细节后面我们分析

        List elementList = node.getElementList();
        Iterator it = elementList.iterator();
        while (it.hasNext()) {
            Object element = it.next();
            if (element instanceof XmlNode) {
                XmlNode currElementNode = (XmlNode) element;
                operations.add( DefinitionResolver.createElementDefinition(currElementNode) );
            } else {
                operations.add( new ConstantDef(element.toString()) );
            }
        }
    }

    //构造函数,具体的实现同上

     public ScraperConfiguration(File sourceFile) throws FileNotFoundException {
        this.sourceFile = sourceFile;
        createFromInputStream( new InputSource(new FileReader(sourceFile)) );
    }

    //构造函数,具体的实现同上
    public ScraperConfiguration(String sourceFilePath) throws FileNotFoundException {
        this( new File(sourceFilePath) );
    }

    //构造函数,具体的实现同上

    public ScraperConfiguration(URL sourceUrl) throws IOException {
        this.url = sourceUrl.toString();
        createFromInputStream( new InputSource(new InputStreamReader(sourceUrl.openStream())) );
    }

    //创建动态语言引擎   

    public ScriptEngine createScriptEngine(Map context, String engineType) {
        if ( JAVASCRIPT_SCRIPT_ENGINE.equalsIgnoreCase(engineType) ) {
            return new JavascriptScriptEngine(context);
        } else if ( GROOVY_SCRIPT_ENGINE.equalsIgnoreCase(engineType) ) {
            return new GroovyScriptEngine(context);
        } else {
            return new BeanShellScriptEngine(context);
        }
    }

    public ScriptEngine createScriptEngine(Map context) {
        return createScriptEngine(context, this.defaultScriptEngine);
    }

}

  由于篇幅原因,我们在下面几张分别讨论httpClientManager ,runtimeConfig ,context