爬虫抓取网页相似度判断

爬虫抓取网页过程中,会产生很多的问题,当然最重要的一个问题就是重复问题,网页的重复抓取.最简单的方式就是对url去重.已经抓取过的url不再抓取.但是其实在实际业务中是需要对于已经抓取过的URL进行再次抓取的.例如 BBS .bbs存在大量的更新回复,但是url不会发生改变.

一般情况下的url去重方式,就是判断url是否抓取过,如果抓取过就不再抓取,或者是在一定时间内不再抓取..

我的需求也是这样的, 所以首先做的就是url去重. 在爬虫发现链接,加入待抓取队列的时候,会对url进行验证,是否抓取过,或者当前时间是否需要再次抓取该url.   如果在条件时间内抓取到的最终内容是否需要入库呢..?

因为业务问题:

1. DM 定时拿出数据库中的数据.

2. ETL需要定时拿出数据库中的数据.

但是他们都不会对数据进行判断是否之前已经做过处理.  所以也就会造成冗余,对于爬虫来说.每天抓取的数据至少百万级的,如果不进行去重判断,DM ETL 等其他所需数据的人员每天都要处理大量的已处理过数据.

很多人的处理方式都是 MD5 或者其他的一些加密方式.  甚至几种结合... 好吧,我就说说问题..

每次访问该网页都会增加次数,网站修改的内容仅仅为千分之一,一个字符... 但是对于md5来说,却是修改了整个世界..整个加密都改变了...

这是我记录的md5. 里面的内容为原文文章..文章修改的内容见上图..

经过测试.md5加密正文用于爬虫做去重判断.适用性很低...所以就修改了方案.

使用SimHash算法对于抓取数据加密.

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class SimHash {
	private String tokens;

	public BigInteger intSimHash;

	private String strSimHash;

	private int hashbits = 64;

	public SimHash(String tokens) {
		this.tokens = tokens;
		this.intSimHash = this.simHash();
	}

	public SimHash(String tokens, int hashbits) {
		this.tokens = tokens;
		this.hashbits = hashbits;
		this.intSimHash = this.simHash();
	}

	public BigInteger simHash() {
		// 定义特征向量/数组
		int[] v = new int[this.hashbits];
		// 修改为分词
		StringTokenizer stringTokenizer = new StringTokenizer(tokens);
		while (stringTokenizer.hasMoreTokens()) {
			String temp = stringTokenizer.nextToken(); // temp
			BigInteger t = this.hash(temp);
			for (int i = 0; i < this.hashbits; i++) {
				BigInteger bitmask = new BigInteger("1").shiftLeft(i);
				if (t.and(bitmask).signum() != 0) {
					v[i] += 1;
				} else {
					v[i] -= 1;
				}
			}
		}
		BigInteger fingerprint = new BigInteger("0");
		StringBuffer simHashBuffer = new StringBuffer();
		for (int i = 0; i < this.hashbits; i++) {
			// 4、最后对数组进行判断,大于0的记为1,小于等于0的记为0,得到一个 64bit 的数字指纹/签名.
			if (v[i] >= 0) {
				fingerprint = fingerprint.add(new BigInteger("1").shiftLeft(i));
				simHashBuffer.append("1");
			} else {
				simHashBuffer.append("0");
			}
		}
		this.strSimHash = simHashBuffer.toString();
		return fingerprint;
	}

	@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
	public List subByDistance(SimHash simHash, int distance) {
		// 分成几组来检查
		int numEach = this.hashbits / (distance + 1);
		List characters = new ArrayList();
		StringBuffer buffer = new StringBuffer();
		int k = 0;
		for (int i = 0; i < this.intSimHash.bitLength(); i++) {
			// 当且仅当设置了指定的位时,返回 true
			boolean sr = simHash.intSimHash.testBit(i);

			if (sr) {
				buffer.append("1");
			} else {
				buffer.append("0");
			}

			if ((i + 1) % numEach == 0) {
				// 将二进制转为BigInteger
				BigInteger eachValue = new BigInteger(buffer.toString(), 2);
				buffer.delete(0, buffer.length());
				characters.add(eachValue);
			}
		}
		return characters;
	}

	public int getDistance(String str1, String str2) {
		int distance;
		if (str1.length() != str2.length()) {
			distance = -1;
		} else {
			distance = 0;
			for (int i = 0; i < str1.length(); i++) {
				if (str1.charAt(i) != str2.charAt(i)) {
					distance++;
				}
			}
		}
		return distance;
	}

	/**
	 * 计算Hash
	 * 
	 * @param source
	 * @return
	 */
	private BigInteger hash(String source) {
		if (source == null || source.length() == 0) {
			return new BigInteger("0");
		} else {
			char[] sourceArray = source.toCharArray();
			BigInteger x = BigInteger.valueOf(((long) sourceArray[0]) << 7);
			BigInteger m = new BigInteger("1000003");
			BigInteger mask = new BigInteger("2").pow(this.hashbits).subtract(
					new BigInteger("1"));
			for (char item : sourceArray) {
				BigInteger temp = BigInteger.valueOf((long) item);
				x = x.multiply(m).xor(temp).and(mask);
			}
			x = x.xor(new BigInteger(String.valueOf(source.length())));
			if (x.equals(new BigInteger("-1"))) {
				x = new BigInteger("-2");
			}
			return x;
		}
	}

	/**
	 * 计算海明距离
	 * 
	 * @param other
	 * @return
	 */
	public int hammingDistance(SimHash other) {
		BigInteger x = this.intSimHash.xor(other.intSimHash);
		int tot = 0;
		// 统计x中二进制位数为1的个数
		// 我们想想,一个二进制数减去1,那么,从最后那个1(包括那个1)后面的数字全都反了,对吧,然后,n&(n-1)就相当于把后面的数字清0,
		// 我们看n能做多少次这样的操作就OK了。
		while (x.signum() != 0) {
			tot += 1;
			x = x.and(x.subtract(new BigInteger("1")));
		}
		return tot;
	}

}

同样对于刚才的网站进行测试..

结果:

可以看出,对于网站进行简单的修改不会影响最终生成的hash值. 但是如果网站更新,会直接修改结果.适用于爬虫抓取去重更新. 所以建议使用该方式做去重方案

时间: 2025-01-07 07:04:47

爬虫抓取网页相似度判断的相关文章

Python3简单爬虫抓取网页图片

现在网上有很多python2写的爬虫抓取网页图片的实例,但不适用新手(新手都使用python3环境,不兼容python2),所以我用Python3的语法写了一个简单抓取网页图片的实例,希望能够帮助到大家,并希望大家批评指正. 1 import urllib.request 2 import re 3 import os 4 import urllib 5 #根据给定的网址来获取网页详细信息,得到的html就是网页的源代码 6 def getHtml(url): 7 page = urllib.r

Python爬虫抓取网页图片

本文通过python 来实现这样一个简单的爬虫功能,把我们想要的图片爬取到本地. 下面就看看如何使用python来实现这样一个功能. # -*- coding: utf-8 -*- import urllib import re import time import os #显示下载进度 def schedule(a,b,c): ''''' a:已经下载的数据块 b:数据块的大小 c:远程文件的大小 ''' per = 100.0 * a * b / c if per > 100 : per =

【转载】python抓取网页时候,判断网页编码格式

在web开发的时候我们经常会遇到网页抓取和分析,各种语言都可以完成这个功能.我喜欢用python实现,因为python提供了很多成熟的模块,可以很方便的实现网页抓取.但是在抓取过程中会遇到编码的问题,那今天我们来看一下如何判断网页的编码:网上很多网页的编码格式都不一样,大体上是GBK,GB2312,UTF-8等.我们在获取网页的的数据后,先要对网页的编码进行判断,才能把抓取的内容的编码统一转换为我们能够处理的编码,避免乱码问题的出现. 使用chardet模块 1 #如果你的python没有安装c

Python爬虫-抓取网页数据并解析,写入本地文件

之前没学过Python,最近因一些个人需求,需要写个小爬虫,于是就搜罗了一批资料,看了一些别人写的代码,现在记录一下学习时爬过的坑. 如果您是从没有接触过Python的新手,又想迅速用Python写出一个爬虫,那么这篇文章比较适合你. 首先,我通过: https://mp.weixin.qq.com/s/ET9HP2n3905PxBy4ZLmZNw 找到了一份参考资料,它实现的功能是:爬取当当网Top 500本五星好评书籍 源代码可以在Github上找到: https://github.com/

C# 使用 Abot 实现 爬虫 抓取网页信息 源码下载

下载地址 ** dome **

关于Python3爬虫抓取网页Unicode

import urllib.requestresponse = urllib.request.urlopen('http://www.baidu.com')html = response.read()print(html) 上面的代码正常但是运行的时候结果遇到中文会以\xe7\x99\xbe\xe5\xba\xa6\xe4\xb8\x80代替,这是一种byte字节. python3 输出位串,而不是可读的字符串,需要对其进行转换 使用str(string[, encoding])对数组进行转换

nodejs爬虫抓取数据 -- html 实体编码处理办法

cheerio DOM化并解析的时候 1.假如使用了 .text()方法,则一般不会有html实体编码的问题出现 2.如果使用了 .html()方法,则很多情况下都会出现,这时,可能就需要转义一番了 类似这些 因为需要作数据存储,所有需要转换 Халк крушит. Новый способ исполнен 大多数都是&#(x)?\w+的格式 所以就用正则转换一番 var body = ....//这里就是请求后获得的返回数据,或者那些 .html()后获取的 //一般可以先转换为标准uni

[Python]网络爬虫(一):抓取网页的含义和URL基本构成

一.网络爬虫的定义 网络爬虫,即Web Spider,是一个很形象的名字. 把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛.网络蜘蛛是通过网页的链接地址来寻找网页的. 从网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址, 然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止. 如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来. 这样看来,网络爬虫就是一个爬行程序,一个抓取

[转载]爬虫的自我解剖(抓取网页HtmlUnit)

网络爬虫第一个要面临的问题,就是如何抓取网页,抓取其实很容易,没你想的那么复杂,一个开源HtmlUnit包,4行代码就OK啦,例子如下: 1 2 3 4 final WebClient webClient=new WebClient(); final HtmlPage page=webClient.getPage("http://www.yanyulin.info"); System.out.println(page.asText()); webClient.closeAllWindo