Web-Harvest学习笔记
郎欣然
2023-12-01
文章来源[url]http://mxsfengg.blog.163.com/blog/static/2637021820085522154653/[/url]
这一章,我们来学习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