网络爬虫-url索引
网络爬虫-url索引
http://www.cnblogs.com/yuandong/archive/2008/08/28/Web_Spider_Url_Index.html
url索引的作用是判断一个url是否被抓取过,采用的算法主要是MD5数字签名。
假设一共要抓取的url不超过1亿条,用一个二进制的位表示一个url是否被抓取过,则至少需要1亿个位,我们管每一个位叫一个“槽”。考虑到MD5的算法是可能出现冲突(即不同的url算出来的MD5可能相同,这种概率很小),槽越少,冲突越明显,所以槽越多越好。但另一方面,还要考虑到占用内存的大小,因为在抓取的过程中,为了保证效率,所有的槽都需要载入内存。目前我使用的是2的28次方,即32M,相当于268435456(2.6亿)个槽。
当要判断一个url是否已经抓取过的时候,只要判断该url经过MD5签名后的值所对应的槽是否标记为1即可。例如给出的url是:http://www.ouc.edu.cn/,经过128位的MD5签名后,得出的1073542761,则需要判断的就是第1073542761个槽是0还是1。同样的道理,当完成一个url的抓取后,要将对应的槽标记为1。
存储槽的32M空间在内存是不连续的,因为操作系统很难划分出32M的连续内存空间,所以将其分为4096个段Segment,每段2048个32位整数,32*2048*4096=268435456。相当于一个整型的二维数组。
![]()
我们使用32位的MD5作为签名,表示为一个整数。这个整数分为三部分,分别是段地址、段偏移和值地址。第5-16位表示段地址,17-27位表示段偏移,28-32位(最后5位,取值范围为2的5次方,即0-31)表示在整形值中的位置、即值地址。
![]()
当给定一个url的MD5值时,通过以下函数计算出其段地址:
1: unsigned short get_segment_index(unsigned int md5) {
2:
3: //5-16位表示段地址
4:
5: unsigned short result;
6: bzero(&result, sizeof(unsigned short));
7: memcpy(&result, ((char*)&md5) + 2, sizeof(unsigned short));
8:
9: return result & 0x0FFF;
10: }
通过以下函数计算出其段偏移:
1: unsigned short get_segment_offset(unsigned int md5) {
2:
3: //17-27位表示段偏移
4:
5: unsigned short result;
6: bzero(&result, sizeof(unsigned short));
7: memcpy(&result, ((char*)&md5), sizeof(unsigned short));
8:
9: return result >> 5;
10: }
通过以下函数计算其值偏移:
1: unsigned int get_value(unsigned int md5) {
2:
3: //28-32(最后5位)为表示值
4:
5: unsigned int result = 1;
6: return result << (md5 & 0x0000001F);
7: }
再得到段地址、段偏移和值偏移后,就通过一下函数判定该Url是否已被抓取:
1: bool is_url_crawled(char* url) {
2:
3: //将给出的url进行md5运算,取得对应的Value,于储存的Value按位与
4:
5: unsigned int url_md5 = md5(url);
6: unsigned short segment_index = get_segment_index(url_md5);
7: unsigned short segment_offset = get_segment_offset(url_md5);
8: unsigned int value = get_value(url_md5);
9:
10: unsigned int result = (unsigned int)
(url_index[segment_index][segment_offset] & value);
11:
12: return result > 0 ? TRUE : FALSE;
13: }
如果未被抓取,在完成抓取后,通过以下函数标记为已抓取:
1: int mark_url_as_crawled(char* url) {
2:
3: //取得段地址、段偏移和url对应的值
4: unsigned int url_md5 = md5(url);
5: unsigned short segment_index = get_segment_index(url_md5);
6: unsigned short segment_offset = get_segment_offset(url_md5);
7: unsigned int value = get_value(url_md5);
8:
9: //通过按位或标记url对应的位为已抓取
10: url_index[segment_index][segment_offset] |= value;
11:
12: //同步写入索引文件
13: value = url_index[segment_index][segment_offset];
14: long offset = (((long)segment_index) * SEGMENT_LENGTH + segment_offset)
* sizeof(unsigned int);
15: if(fseek(index_file, offset, SEEK_SET) != 0)
16: return -1;
17:
18: if(fwrite(&value, sizeof(unsigned int), 1, index_file) != 1)
19: return -1;
20:
21: fflush(index_file);
22: return 0;
23: }
网络爬虫-url索引的更多相关文章
- 网络爬虫url跳转代码
from bs4 import BeautifulSoup from urllib.request import urlopen import re import random base_url = ...
- python网络爬虫(一):网络爬虫科普与URL含义
1. 科普 通用搜索引擎处理的对象是互联网的网页,目前网页的数量数以亿计,所以搜索引擎面临的第一个问题是如何设计出高效的下载系统,已将海量的网页下载到本地,在本地形成互联网网页的镜像.网络爬虫 ...
- Python 网络爬虫 008 (编程) 通过ID索引号遍历目标网页里链接的所有网页
通过 ID索引号 遍历目标网页里链接的所有网页 使用的系统:Windows 10 64位 Python 语言版本:Python 2.7.10 V 使用的编程 Python 的集成开发环境:PyChar ...
- 【Python网络爬虫一】爬虫原理和URL基本构成
1.爬虫定义 网络爬虫,即Web Spider,是一个很形象的名字.把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛.网络蜘蛛是通过网页的链接地址来寻找网页的.从网站某一个页面(通常 ...
- [Python]网络爬虫(一):抓取网页的含义和URL基本构成
一.网络爬虫的定义 网络爬虫,即Web Spider,是一个很形象的名字. 把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛.网络蜘蛛是通过网页的链接地址来寻找网页的. 从网站某一个 ...
- python 网络爬虫(二) BFS不断抓URL并放到文件中
上一篇的python 网络爬虫(一) 简单demo 还不能叫爬虫,只能说基础吧,因为它没有自动化抓链接的功能. 本篇追加如下功能: [1]广度优先搜索不断抓URL,直到队列为空 [2]把所有的URL写 ...
- [原创]手把手教你写网络爬虫(7):URL去重
手把手教你写网络爬虫(7) 作者:拓海 摘要:从零开始写爬虫,初学者的速成指南! 封面: 本期我们来聊聊URL去重那些事儿.以前我们曾使用Python的字典来保存抓取过的URL,目的是将重复抓取的UR ...
- Python 网络爬虫 009 (编程) 通过正则表达式来获取一个网页中的所有的URL链接,并下载这些URL链接的源代码
通过 正则表达式 来获取一个网页中的所有的 URL链接,并下载这些 URL链接 的源代码 使用的系统:Windows 10 64位 Python 语言版本:Python 2.7.10 V 使用的编程 ...
- 开源的49款Java 网络爬虫软件
参考地址 搜索引擎 Nutch Nutch 是一个开源Java 实现的搜索引擎.它提供了我们运行自己的搜索引擎所需的全部工具.包括全文搜索和Web爬虫. Nutch的创始人是Doug Cutting, ...
随机推荐
- stl中的map数据类型
1.1 STL map 1.1.1 背景 关联容器使用键(key)来存储访问读取元素,而顺序容器则通过元素在容器中的位置存储和访问元素. 常见的顺序容器有:vector.list.deque.stac ...
- Oracle数据类型对应Java类型
SQL数据类型 JDBC类型代码 标准的Java类型 Oracle扩展的Java类型 1.0标准的JDBC类型: CHAR java.sql.Types.CHAR java.lang.St ...
- c#基础学习汇总----------继承
封装,继承,多态.这是面向对象的思想,也可以说是最基本的东西.说到继承,直接的说他就是面向对象中类与类之间的一种关系.通过继承,使得子类具有父类公有的受保护访问权限的属性和方法,同时子类可以通过加入新 ...
- 一些常用sqlite语句
1,如果表不存在就新建一个 CComBSTR bstrCreatBat(L”CREATE TABLE IF NOT EXISTS tb_Name (\ rowIdIndex INTEGER PRIM ...
- Mysql创建函数时报错
先去查询 show variables like '%func%' ; 这个语句,如果该语句最后输出的值是OFF 那么就用下面的语句去修改就可以:set global log_bin_trust_f ...
- 汇编语言-打印部分ASCII表
用表格形式显示字符 1. 题目:用表格形式显示ASCII字符 2.要求:按15行×16列的表格形式显示ASCII码为10H-100H的所有字符,即以行为主的顺序及ASCII码递增的次序依次显示对应的字 ...
- python(四)数据持久化操作 文件存储
1.写入 导入pickle包 然后组织一个列表my_list,保存为pkl格式,可以是任意格式 在磁盘下回出现一个保存的文件 2.读取
- [译]线程生命周期-理解Java中的线程状态
线程生命周期-理解Java中的线程状态 在多线程编程环境下,理解线程生命周期和线程状态非常重要. 在上一篇教程中,我们已经学习了如何创建java线程:实现Runnable接口或者成为Thread的子类 ...
- laravel方法汇总详解
1.whereRaw() 用原生的SQL语句来查询,whereRaw('select * from user') 就和 User::all()方法是一样的效果 2.whereBetween() 查询时 ...
- Redis的PHP操作手册
String 类型操作 string是redis最基本的类型,而且string类型是二进制安全的.意思是redis的string可以包含任何数据.比如jpg图片或者序列化的对象 $redis-> ...