SEO如何处理采集内容(5)

【GOGO闯】:后台留了一堆问题,本篇是对其中两个问题的答疑

正文抽取

在【SEO如何处理采集内容 ①】中的“泛采集”部分提到过正文抽取,然后有一些人依旧表示不知道怎么搞。

这东西用网上开源的就可以,Google搜索“{编程语言}正文提取算法”便能找到一大堆的解决方案,如:Readability、Boilerpipe、Diffbot……大部分算法已经打包好了,拿过来就可以直接用,用不着自己写。我们是做网站的,不是搞技术的,有现成的轮子用就OK了。

那么一些人又有一个问题:我该用哪个好呢?

No No No,这不是用轮子的思维,首先不可能每个算法都能提取所有的网页,其次,算法不止一个。

那这件事就简单了,一个算法没有将当前网页的正文提取出来,好办,不用做别的,直接切下一个算法接着试,这个不行再换下一个,如果网页正常,总有一个能将正文提取出来。除非这个页面模板乱七八糟什么都有,比如网站首页,没有明显的主体内容区块,这个另算。

所以,如果泛采集过程中需要提取正文的链接中,最好先将首页url过滤掉。

如果非要纠结用哪个好,请参考:https://tomazkovacic.com/blog/2011/06/09/evaluating-text-extraction-algorithms/

内容去重

另一个问题,采集到重复的内容咋办?

本渣渣之前用过两个办法。

第一种

首先我们已经限定有效内容需要满足哪些指标,比如字数必须大于150字,才算有效内容,小于150字的删除不入库。那么大于150字的内容一般都有4个以上标点符号。

XXXXXXX,XXXXXXXXX。XXX:“XXXXXX,XXXXXXXXXXXX。XXXXXX,XXXXXXXXXX,XXXXXXXX,XXXXXX。XXX?”

XXXX,XXXXXXX。XXXXXXX;XXXX;XXXXXXXX;XXXXXX,XXXXXXXXXX,XXXXXXXX,XXXXXX – XXX!
所以每篇文章,从第2个标点符号开始,连续提取两个标点符号之间的文本,且字数大于7的,直至提取3个文本段。

然后将这3个文本段合并成一个,将文本段重复的文章去重,只保留一个。因为连续3个文本段相同的文章基本都是重复的,而且是完全重复,改都没改的。

第二种

用现成的文本去重算法,依旧Google搜索,一堆现成的解决方案,如simhash、Shingling…..

首先对所有抓回来的文本清洗,去除无关词汇,如停止词、助词(的地得..)什么的,然后再通过上述的解决方案来计算相似文档。

哪个好?本渣渣觉得都一般,没觉得哪个好,但都可以凑活用。。。

但都有个问题,一旦文章量大起来,比如上了几百万,程序跑起来很慢,巨烧CPU,怎么办??

于是就沿用第一种办法的思路,不分析全文了,直接找出每篇文章的最长的n句话,做一遍hash签名,然后还是用上述现成的算法去跑,n一般取3。不但运行速度快了很多,找相似文章的最终效果貌似也比之前好了。

以上是从闯爷微信公众号【流量贩子】趴过来的内容

那么本渣渣从python技术实现手段上,用过的提取正文的python模块Readability、github上有!不多说,也就是三行代码

smihash算法python实现,可以直接拿过来跑跑!再加上中文分词库,可以比较好的对中文文章计算hash,中文分词可以使用结巴;github上有!

#!/usr/bin/python
# coding=utf-8
class simhash:
    
    #构造函数
    def __init__(self, tokens='', hashbits=128):        
        self.hashbits = hashbits
        self.hash = self.simhash(tokens);
    
    #toString函数    
    def __str__(self):
        return str(self.hash)
    
    #生成simhash值    
    def simhash(self, tokens):
        v = [0] * self.hashbits
        for t in [self._string_hash(x) for x in tokens]: #t为token的普通hash值           
            for i in range(self.hashbits):
                bitmask = 1 << i
                if t & bitmask :
                    v[i] += 1 #查看当前bit位是否为1,是的话将该位+1
                else:
                    v[i] -= 1 #否则的话,该位-1
        fingerprint = 0
        for i in range(self.hashbits):
            if v[i] >= 0:
                fingerprint += 1 << i
        return fingerprint #整个文档的fingerprint为最终各个位>=0的和
    
    #求海明距离
    def hamming_distance(self, other):
        x = (self.hash ^ other.hash) & ((1 << self.hashbits) - 1)
        tot = 0;
        while x :
            tot += 1
            x &= x - 1
        return tot
    
    #求相似度
    def similarity (self, other):
        a = float(self.hash)
        b = float(other.hash)
        if a > b : return b / a
        else: return a / b
    
    #针对source生成hash值   (一个可变长度版本的Python的内置散列)
    def _string_hash(self, source):        
        if source == "":
            return 0
        else:
            x = ord(source[0]) << 7
            m = 1000003
            mask = 2 ** self.hashbits - 1
            for c in source:
                x = ((x * m) ^ ord(c)) & mask
            x ^= len(source)
            if x == -1:
                x = -2
            return x
             

if __name__ == '__main__':
    s = 'This is a test string for testing'
    # s=open('test1.txt').read()
    hash1 = simhash(s.split())
    
    s = 'This is a test string for testing also'
    # s=open('test2.txt').read()
    hash2 = simhash(s.split())
    
    s = 'nai nai ge xiong cao'
    # s=open('test3.txt').read()
    hash3 = simhash(s.split())
    
    print(hash1.hamming_distance(hash2) , "   " , hash1.similarity(hash2))
    print(hash1.hamming_distance(hash3) , "   " , hash1.similarity(hash3))

Leave a Comment