PHP通过MYSQL的全文检索实现利用样式和ID特征码识别抓取网页的研究

丰富的内容是一个网站赖以生存和SEO必备的条件。抓取其它网站的优质内容几乎是每一个希望做大做强的网站每时每刻都在做的事。但是,互联网海量的网页的结构千差万别,除了基于HTML标签外,似乎再无相似之处。没有一个正则表达式能够放之四海而皆准的分析出每个页面的结构。这为广大程序员自动化抓取网页带来了极大的困难与复杂度。本文就是做“使用PHP语言通过MYSQL的全文检索功能实现利用特征码来识别网页”的研究。

既然没有万能的正则表达式来匹配千差万别的网页,就只能缩小范围,针对每一组结构相同的文章分别分析。例如,我们可以把新华网下所有的财经新闻作为“新华网财经页”一个规则,因为这些文章的机构都是相同的,只是内容不同而已,所有该组下的文章都用同样的代码来分析。而“凤凰网新闻”用“凤凰网新闻页”代码分析。

现在问题出来了,如何判断一篇文章是符合“新华网财经页”规则,还是符合“凤凰网新闻页”的规则?一个直接的办法是,利用URL的相关,所有新华网财经首页 http://www.xinhuanet.com/fortune/ 下的文章都是新华网财经页,而所有凤凰网新闻首页 http://news.ifeng.com/ 下的文章都属于“凤凰网新闻页”。更多的问题出现了,新华网财经首页下的文章有N多不同结构,也包括非财经类型的文章。如果细化到只有唯一类型的文章的列表,一来工作量成几何式的增长,儿来大多数的网站不存在这样纯化的列表供我们使用。

那么,如何有效区别出这些千差万别的文章类型呢?判断?再判断?复杂,很复杂!

换一个角度,网页结构的不同大可以说是因为样式的不同。同一个规则下的网页都是使用相同的样式。没有长的像的两个网页用的样式是一样的。所以,我们可以通过HTML里使用的样式来区分一组网页。而不同网页的标签的ID更是不同。结合样式和ID,我们完全可以区分出每一个规则的样式来。

希望就这样出现了!

首先我们可以将一个规则下的页面使用到的样式和ID都保存到MYSQL的一个表里。当随机出现一个页面时,把这个页面里的样式和ID和表里的内容通过MYSQL的全文检索功能匹配,如果该规则已经存在,则该规则匹配的系数是最高的。该文章的规则就知道了。

接下来,针对每一个规则,开发不同的代码来分析文章中的标题、内容和来源等信息。

下面是匹配匹配的具体操作。其中用到了一个非常有用的类:simple_html_dom。该类是将HTML代码解析成一个一个的HTML标签。进而可以像DHTML中的getElementById等函数来获取每一个标签。
创建数据表:

— 表的结构 `articletypes`

CREATE TABLE IF NOT EXISTS `articletypes` (
`typeid` int(11) NOT NULL auto_increment,
`typename` varchar(32) NOT NULL COMMENT ‘类型名’,
`typetag` varchar(32) NOT NULL COMMENT ‘类型标记’,
`typeids` text NOT NULL COMMENT ‘包含关键字’,
`typestyles` text NOT NULL COMMENT ‘类型包含的样式’,
PRIMARY KEY? (`typeid`),
FULLTEXT KEY `typeids` (`typeids`,`typestyles`)
) ENGINE=MyISAM DEFAULT CHARSET=gbk COMMENT=’文章类型表’;

构建 dimple_html_dom对象:

$dom = str_get_html("http://news.xinhuanet.com/fortune/2009-08/12/content_11867682.htm");

分析出样式和ID的方法:

$styles = array();
foreach ($dom->find("[class]") as $e){

$style = trim($e->class);
 if($style){
 $styles[] = $style;
 }
}
$styles = array_unique($styles);

$ids = array();
foreach ($dom->find("[id]") as $e){
 $id = trim($e->id);
 if($id){
 $ids[] = $id;
 }
}
$ids = array_unique($ids);

保存到数据库中:

$ids = join(" ", $ids);
$styles = join(" ", $styles);
$sql = "Insert Into articletypes Set typename='新华网财经页', typetag='xinhuacaijing', typeids='$ids'";
mysql_query($sql);

再找另外一篇新华网财经来匹配
http://news.xinhuanet.com/fortune/2009-08/12/content_11869045.htm
依以上同样的方法获取styles和ids后,检索

$characteristic = $ids . ' ' . $styles;
$sql = "Select typetag, Match(typeids, typestyles) Against('$characteristic') As m From articletypes Order By m Desc";
list($type, $match) = mysql_fetch_array(mysql_query($sql));
if(!$match){
 throw new HTMLException('没有找到对应的类型');
}
echo "$type";

这时,根据匹配来的$type,就可以用对应的分析程序来分析页面了。
再列一下分析页面的程序。

//标题
$e = $dom->find('#Title', 0);
if($e){
 $title = $e->plaintext;
 echo $title . "<br/>";
}
//来源
$e = $dom->find("font[color=000066]", 0);
if($e){
 $source = $e->plaintext;
 echo $source . "<br/>";
}
//内容
$e = $dom->getElementById('Content');
if($e){
 //去除其中的表格
 foreach ($e->find("table") as $table){
 $table->outertext = '';
 }
 $content = $e->innertext;
 echo $content;
}

注意:MYSQL全文检索的限制,必须要求至少添加三行规则后才能匹配到。你可以加一个后随便再写几个规则就好。

通过这种方式的分析,可以完全抛弃地址、域名等的判断,可以专心在文章结构的分析。使分析列表获得文章URL和分析文章结构内容的程序完全分开而没有一点关系。

我们可以自己写几个程序,监控任意多的页面,获取更新的文章然后统一交到页面分析程序来分析文章。

想要获取完整面向对象化的源代码,请回复时留下EMAIL。

5 Replies to “PHP通过MYSQL的全文检索实现利用样式和ID特征码识别抓取网页的研究

发表评论

电子邮件地址不会被公开。

*