php实现的网页正文提取算法
作者: 郑晓 分类: PHP 发布于: 2014-11-20 19:49 浏览:17,308 评论(16)
Html2Article-php实现的提取网页正文部分,最近研究百度结果页的资讯采集,其中关键环节就是从采集回的页面中提取出文章。
有网友回复说不会用或不能用,郑晓特意贴上测试代码…做为一个程序员,有问题请先自己找原因
#采集我们新闻网的一个新闻页
$content = file_get_contents("<a href="http://news.qingdaonews.com/qingdao/2016-12/26/content_11882489.htm">http://news.qingdaonews.com/qingdao/2016-12/26/content_11882489.htm</a>");
$r = new Readability($content);
print_r($r->getContent());
因为难点在于如何去识别并保留网页中的文章部分,而且删除其它无用的信息,并且要做到通用化,不能像火车头那样根据目标站来制定采集规则,因为搜索引擎结果中有各种的网页。
这个类是从网上找到的一个php实现的提取网页正文部分的算法,郑晓在本地也测试了下,准确率非常高。
<?php</p>
<p>class Readability {
// 保存判定结果的标记位名称
const ATTR_CONTENT_SCORE = "contentScore";</p>
<pre><code>// DOM 解析类目前只支持 UTF-8 编码
const DOM_DEFAULT_CHARSET = "utf-8";
// 当判定失败时显示的内容
const MESSAGE_CAN_NOT_GET = "Readability was unable to parse this page for content.";
// DOM 解析类(PHP5 已内置)
protected $DOM = null;
// 需要解析的源代码
protected $source = "";
// 章节的父元素列表
private $parentNodes = array();
// 需要删除的标签
// Note: added extra tags from https://github.com/ridcully
private $junkTags = Array("style", "form", "iframe", "script", "button", "input", "textarea",
"noscript", "select", "option", "object", "applet", "basefont",
"bgsound", "blink", "canvas", "command", "menu", "nav", "datalist",
"embed", "frame", "frameset", "keygen", "label", "marquee", "link");
// 需要删除的属性
private $junkAttrs = Array("style", "class", "onclick", "onmouseover", "align", "border", "margin");
/**
* 构造函数
* @param $input_char 字符串的编码。默认 utf-8,可以省略
*/
function __construct($source, $input_char = "utf-8") {
$this->source = $source;
// DOM 解析类只能处理 UTF-8 格式的字符
$source = mb_convert_encoding($source, 'HTML-ENTITIES', $input_char);
// 预处理 HTML 标签,剔除冗余的标签等
$source = $this->preparSource($source);
// 生成 DOM 解析类
$this->DOM = new DOMDocument('1.0', $input_char);
try {
//libxml_use_internal_errors(true);
// 会有些错误信息,不过不要紧 :^)
if (!@$this->DOM->loadHTML('<?xml encoding="'.Readability::DOM_DEFAULT_CHARSET.'">'.$source)) {
throw new Exception("Parse HTML Error!");
}
foreach ($this->DOM->childNodes as $item) {
if ($item->nodeType == XML_PI_NODE) {
$this->DOM->removeChild($item); // remove hack
}
}
// insert proper
$this->DOM->encoding = Readability::DOM_DEFAULT_CHARSET;
} catch (Exception $e) {
// ...
}
}
/**
* 预处理 HTML 标签,使其能够准确被 DOM 解析类处理
*
* @return String
*/
private function preparSource($string) {
// 剔除多余的 HTML 编码标记,避免解析出错
preg_match("/charset=([\w|\-]+);?/", $string, $match);
if (isset($match[1])) {
$string = preg_replace("/charset=([\w|\-]+);?/", "", $string, 1);
}
// Replace all doubled-up
tags with
tags, and remove fonts.
$string = preg_replace(“/
[ \r\n\s]*
/i”, “
“, $string); $string = preg_replace(“/]*>/i”, “”, $string); // @see https://github.com/feelinglucky/php-readability/issues/7 // – from http://stackoverflow.com/questions/7130867/remove-script-tag-from-html-content $string = preg_replace(“#(.*?)#is”, “”, $string); return trim($string); } /** * 删除 DOM 元素中所有的 $TagName 标签 * * @return DOMDocument */ private function removeJunkTag($RootNode, $TagName) { $Tags = $RootNode->getElementsByTagName($TagName); //Note: always index 0, because removing a tag removes it from the results as well. while($Tag = $Tags->item(0)){ $parentNode = $Tag->parentNode; $parentNode->removeChild($Tag); } return $RootNode; } /** * 删除元素中所有不需要的属性 */ private function removeJunkAttr($RootNode, $Attr) { $Tags = $RootNode->getElementsByTagName(“*”); $i = 0; while($Tag = $Tags->item($i++)) { $Tag->removeAttribute($Attr); } return $RootNode; } /** * 根据评分获取页面主要内容的盒模型 * 判定算法来自:http://code.google.com/p/arc90labs-readability/ * 这里由郑晓博客转发 * @return DOMNode */ private function getTopBox() { // 获得页面所有的章节 $allParagraphs = $this->DOM->getElementsByTagName(“p”); // Study all the paragraphs and find the chunk that has the best score. // A score is determined by things like: Number of
本文采用知识共享署名-非商业性使用 3.0 中国大陆许可协议进行许可,转载时请注明出处及相应链接。
本文永久链接: https://www.zh30.com/html2article-php.html
php实现的网页正文提取算法:目前有16 条留言
博主,这个太好了,可以加你了解一下吗,正需要抽取正文的算法
这个类我也是从其它地方找的,并不是我写的,我也没研究过这种算法。
blog.sciencenet.cn/blog-76913-903050.html
这篇网站抓下来的内容为什么是乱码呀??
为什么我解析网页调用方法 不是超时就是 内存不足 有什么解决办法吗 是什么原因引起的呢 希望帮帮忙 谢谢博主!
测试抓取新浪博客文章不行,抓取163博客内容失败,抓取普通网站页面成功,还是有待改进。
非常抱歉,我实在是个小白,请问[实例化时传入网页的html源码和相应的编码,然后直接调用其getContent方法即可返回提取到的正文部分]可以麻烦您解释下具体怎么操作吗?
比如你用file_get_contents()打开一个网页,它的返回值就是网页的html源码,我们把它保存到$content变量中, 然后就可以实例化这个正文提取类,如$obj=new Readability($content); 因为编码是默认的可以不传(这里假设我的目标站是utf8编码), 最后调用$obj->getContent(); 可以获取到正文内容。可以把它的返回值保存到你需要的变量中。
太感谢了!我再试试!谢谢您的回复
我这样写了,没有内容显示
收到你的评论后我直接测试了一遍,是没问题的,文章上面已经贴出测试代码。
我换了很多网站··可是结果只有出现一个Array,请问您知道原因么?谢谢
你这是基础不过关啊… echo不能输出数组,你想打印数组需要用print_r。
文章很不错 欢迎访问 逍遥网xywos.com
博主怎么最近没更新了
这两天懒了,哈哈
感觉博主蛮厉害的样子