写这么一个算法,能够从过滤html标签后的文本中找到正文文本的起止行号,行号之间的文本就是网页正文部分。
有一个规律:正文部分的文本密度要高出非正文部分很多。我们按照这个特性就可以很容易将算法实现,那就是基于阈(读音:yu)值去分析正文所在的位置。
那么接下来就需要解决一些问题:
- 如何确定阈值?
- 如何分析,一行行的分析?还是?
阈值的确定可以通过统计分析得出一个比较好的值,我在实际处理过程中,发现这个值取180是比较合适的,也就是分析文本的时候,如果所分析的文本超过了180,那么就可以认为到达了正文部分。
再有就是如何分析的问题,这个其实比较容易确定,一行行的分析效果肯定不好,如果在按行分析的过程中往下在分析几行作为一次分析效果比较好。也就是一次性分析上5行左右,将字符累加起来,看看有没有达到设定的阈值,如果达到了,那么认为已经进入正文部分了。
嗯,主要的处理逻辑就是这样。
原作者的代码:
int preTextLen = 0; // 记录上一次统计的字符数量(lines就是去除html标签后的文本,_limitCount是阈值,_depth是我们要分析的深度,sb用于记录正文)
int startPos = -1; // 记录文章正文的起始位置
for (int i = 0; i < lines.Length - _depth; i++)
{
int len = 0;
for (int j = 0; j < _depth; j++)
{
len += lines[i + j].Length;
}
if (startPos == -1) // 还没有找到文章起始位置,需要判断起始位置
{
if (preTextLen > _limitCount && len > 0) // 如果上次查找的文本数量超过了限定字数,且当前行数字符数不为0,则认为是开始位置
{
// 查找文章起始位置, 如果向上查找,发现2行连续的空行则认为是头部
int emptyCount = 0;
for (int j = i - 1; j > 0; j--)
{
if (String.IsNullOrEmpty(lines[j]))
{
emptyCount++;
}
else
{
emptyCount = 0;
}
if (emptyCount == _headEmptyLines)
{
startPos = j + _headEmptyLines;
break;
}
}
// 如果没有定位到文章头,则以当前查找位置作为文章头
if (startPos == -1)
{
startPos = i;
}
// 填充发现的文章起始部分
for (int j = startPos; j <= i; j++)
{
sb.Append(lines[j]);
}
}
}
else
{
if (len <= _endLimitCharCount && preTextLen < _endLimitCharCount) // 当前长度为0,且上一个长度也为0,则认为已经结束
{
if (!_appendMode)
{
break;
}
startPos = -1;
}
sb.Append(lines[i]);
}
preTextLen = len;
}
自己改写成了python3的版本,感觉准确率并不是很高,同时源代码的一些部分还没看懂
_depth = 5
_limitCount = 180
preTextLen = 0
startPos = -1
_headEmptyLines = 2
sb = ''
_endLimitCharCount = 0
for i in range(len(split_list) - _depth):
lens = 0
for j in range(_depth):
lens += len(split_list[i+j])
if startPos == -1:
if preTextLen > _limitCount and lens > 0:
emptyCount = 0
for j in range(i-1, 0, -1):
if split_list[j].isspace():
emptyCount += 1
else:
emptyCount = 0
if emptyCount == _headEmptyLines:
startPos = j + _headEmptyLines
break
if startPos == -1:
startPos = i
for j in range(startPos, i, 1):
sb = sb + split_list[j]
else:
if lens <= _endLimitCharCount and preTextLen < _endLimitCharCount:
#if not _appendMode:
# break
startPos = -1
sb = sb + '\n' + split_list[i]
preTextLen = lens
print(sb)