PHP Client Snoopy.class.php 的扩展优化

这几天在研究Snoopy的采集程序,完成对百度文档的采集和附件下载。

其中需要使用到对HTML进行DOM模型操作,读取表单中某个字段的Value,于是在网上找了一些类,发现了HTML SQL 和 DOMDocument两个类,功能还算是比较完善,可惜并没有我想要的效果,于是决定自己动手开发。

其中要加上自己的一些想法,在离开北京的最后一天,写上此文,估计年后就能看到成品了。希望这次回家不要太贪玩了。吼吼。

首先,要实现类Javascript的操作,如document.getElementById 和document.getElementByName,分别返回一个HTML元素对象和一个数组,唯一的HTML元素可以使用对象输出HTML的参数和值。

以下给出代码片段。

[php]
/* 获取指定ID的HTML元素 */
function getElementById($Value)
{
$this->__getElement($URI, ‘id’, $Value);
if(is_array($this->results) && count($this->results) > 0)
$this->results = array_shift($this->results);
$this->results = $this->__ElementToObj($this->results);
}

/* 获取指定名称的HTML元素 */
function getElementByName($Value)
{
return $this->__getElement(‘name’, $Value);
}

/* 获取指定标记的HTML元素 */
function getElementByTag($TAG = ”)
{
$result = $this->results;

if($TAG) $TAG = "($TAG)";
else $TAG = ‘[a-z]+’;

preg_match_all("@<$TAG\s[^>]*?>@isU", $result, $Elements);
$this->Elements = $Elements[0];

return count($Elements[0]);
}

/* 获取含有某些属性或者值的HTML元素 */
function __getElement($ELE, $value=NULL)
{
if(!$this->getElementByTag()){
return false;
}else $Elements = $this->Elements;

$ELE = explode(‘|’, $ELE);
foreach ($ELE as $E)
{
$this->__matchElement($Elements, $E, $value);
}
sort($Elements);
return $Elements;
}

function __matchElement(&$Elements, $E, $value=NULL)
{
if($value !== NULL) $value = "[\"’\s]*?{$value}[\"’\s]*?\"";
else $value = ”;
if(is_array($Elements))
{
foreach ($Elements as $key=>$html)
{
if(!preg_match("@\s{$E}={$value}@is", $html)) unset($Elements[$key]);
}
}else{
if(!preg_match("@\s{$E}={$value}@is", $Elements)) unset($Elements);
}

return $Elements;

}

function __ElementToObj($Elements)
{
if( is_array($Elements) )
{
foreach ($Elements as $key=>$E)
$Elements[$key] = $this->__ElementToObj($E);
}else{
preg_match_all("@\s([a-z]+)=[\"’]*?([^\"’]*?)[\"’]*?@isU", $Elements, $Obj);

$Elements = new stdClass();
foreach ($Obj[1] as $key=>$value)
{
$Elements->$Obj[1][$key] = $Obj[2][$key];
}
}

return $Elements;
}

[/php]

使用方法也比较简单。

[php]
$this = getElementById(‘thisid’);
$this -> title;//输出title
$this -> value;//输出value
[/php]

基本工作完成了,接下来是一些扩展,准备加入以下功能。

  1. 连贯操作
  2. 类似Jquery的节点选择器功能。

先说连贯功能是什么东西。PHP类的连贯操作,在一个方法后直接调用另一个同级方法,我们习惯上称其连贯接口。在ThinkPHP2.0中,此方法使用十分普遍,逻辑清晰,效率也比较高,最重要的是,我觉得这功能很帅….

至于连贯接口,也不是那么难懂,简单来说就是把结果返回给类本身,那类就可以执行其它允许的方法了,有想入门的童鞋可以看看这个文章:http://www.raychou.com/chou/posts/334.htm。

说到这里,可以给出一个演示。在一个html页面中,有一个表单,表单中有几个域,还有不同的值。来演示一下取得这些值的操作过程。

[php]html->form->input->name->value[/php]

按DOM模型的路径,可以定位我们需要的元素和参数值,这里的选择过程非常类似Query的选择器,这里也简单模拟一个过程。

[php]
$obj = form( array(‘name’=>’testname’,’class’=>’testclass’))
//如果有多个Form,可以用数组的方式缩小选择范围
->input(‘name’=>’username’) //获取一个域
->select(); //转换成数组或者对象
[/php]

一个按Dom模型的选择过程就实现了,这里按HTML的元素类型进行选择的时候,是直接按元素名称进行方法命名的。考虑到可能在类中写不了很多HTML元素的方法,这里可以用__call方法来转载方法到另外一个操作上。
如:

[php]$this->form(array(‘name’=>’testname’,’class’=>’testclass’))[/php]

被重定向其它操作,并返回数据到$this->results中,以便其它方法或者连贯方法调用

[php]$this->getElement(‘form’, array(‘name’=>’testname’,’class’=>’testclass’))[/php]

那么,按DOM模型进行节点选择的功能规划,就算大功告成了,回家以后的工作就是把过程完善,HTML元素的选择和逻辑处理,敬请期待。

发表评论