当前位置: 首页 > 编程日记 > 正文

robots.txt文件的解析及过滤

什么是robots.txt文件?

robots.txt(统一小写)是一种存放于网站根目录下的ASCII编码的文本文件,它通常告诉网络搜索引擎的漫游器(又称网络蜘蛛),此网站中的哪些内容是不能被搜索引擎的漫游器获取的,哪些是可以被(漫游器)获取的。 因为一些系统中的URL是大小写敏感的,所以robots.txt的文件名应统一为小写。robots.txt应放置于网站的根目录下。如果想单独定义搜索引擎的漫游器访问子目录时的行为,那么可以将自定的设置合并到根目录下的robots.txt,或者使用robots元数据。Robots.txt协议并不是一个规范,而只是约定俗成的,所以并不能保证网站的隐私。 ——维基百科(http://zh.wikipedia.org/wiki/Robots.txt)

基本属性:

User-agent: 定义搜索引擎的类型
Disallow: 定义禁止搜索引擎收录的地址
Allow: 定义允许搜索引擎收录的地址
Crawl-delay:支持Crawl-delay参数,设置为多少秒,以等待同服务器之间连续请求(网络爬虫的礼貌策略)
#:一些robots.txt 会有注释,#后面都是注释内容,需要过滤掉

一些例子;

User-agent: * 这里的*代表的所有的搜索引擎种类,*是一个通配符
Disallow: /admin/ 这里定义是禁止爬寻admin目录下面的目录
Disallow: /require/ 这里定义是禁止爬寻require目录下面的目录
Disallow: /ABC/ 这里定义是禁止爬寻ABC目录下面的目录
Disallow: /cgi-bin/*.htm 禁止访问/cgi-bin/目录下的所有以".htm"为后缀的URL(包含子目录)。
Disallow: /*?* 禁止访问网站中所有的动态页面
Disallow: /jpg$ 禁止抓取网页所有的.jpg格式的图片
Disallow:/ab/adc.html 禁止爬去ab文件夹下面的adc.html文件。
Allow: /cgi-bin/ 这里定义是允许爬寻cgi-bin目录下面的目录
Allow: /tmp 这里定义是允许爬寻tmp的整个目录
Allow: .htm$ 仅允许访问以".htm"为后缀的URL。
Allow: .gif$ 允许抓取网页和gif格式图片
Crawl-delay: 10

C++实现解析robots.txt,并对url进行过滤:

robotsFilter.h

/*
* urlFilter.h
*
* Created on: 2012-3-26
* Author: xiaojay
*/
#ifndef URLFILTER_H_
#define URLFILTER_H_
#include "../urlFrontier/url.h"
#include<string.h>
#include<assert.h>
#include <iostream>
using namespace std;
#define MAXDISALLOW 100

//接口
class urlFilter
{
public:
// 当u合法时,返回true,否则返回false
virtual bool filter(url * u) = 0;
virtual bool filter(const char * url_text) = 0;
};
//robots.txt过滤
class robotsFilter : public urlFilter
{
public:
robotsFilter(const char * host_name , const char * robots_txt);
~robotsFilter();
virtual bool filter(url * u);
virtual bool filter(const char * url_text);
void parseRobots();
void printDisallow();
bool robotsMatch(char * match , char * file);
private:
char * strlwr(char *); //辅助函数,大写转小写
char * disallow [MAXDISALLOW];
int disallow_size;
char * allow[MAXDISALLOW];
int allow_size;
char * hostname;
char * robotstxt;
int crawldelay ;
};

#endif /* URLFILTER_H_ */

robotsFilter.cpp

/*
* robotFilter.cpp
*
* Created on: Mar 31, 2012
* Author: mayday
*/
#include "urlFilter.h"

// 初始化相关参数
robotsFilter::robotsFilter(const char * host_name , const char * robots_txt)
{
assert(host_name!=NULL && robots_txt!=NULL);
int len = strlen(host_name);
hostname = new char [len + 1];
strcpy(hostname,host_name);

len = strlen(robots_txt);
robotstxt = new char [len + 1];
strcpy(robotstxt,robots_txt);

disallow_size = 0;
allow_size = 0;
crawldelay = 0;
}
robotsFilter::~robotsFilter()
{
delete [] hostname;
delete [] robotstxt;
for(int i=0;i<disallow_size;i++)
{
delete [] disallow[i];
}
for(int i=0;i<allow_size;i++)
{
delete [] allow[i];
}
}

char* robotsFilter::strlwr( char* str )
{
char* orig = str;
// process the string
for (;*str != '\0'; str++ )
*str = tolower(*str);
return orig;
}
//解析robots文本
void robotsFilter::parseRobots()
{
//cout<<robotstxt<<endl;
//key:value
char key [32];
char value [100];
int i,j;
int posl = 0, posm = 0 ,posr =0;
int len = strlen(robotstxt);
bool hasAgent = false;
//总体思路,确定三个标志的位置,然后分割字符串. ——>posl( key )posm( value )posr
while(posl<len && posm<len && posr<len)
{
//找到第一个不为空格和换行符的字符位置,确定posl
while(posl<len && (robotstxt[posl]==' '
|| robotstxt[posl]=='\n' || robotstxt[posl]=='\r')) posl++;
//以#开头的,直接过滤掉该行
if(robotstxt[posl]=='#')
{
while(posl<len && robotstxt[posl]!='\n') posl++;
continue;
}
//找‘:’,确定posm
posm = posl+1;
while(posm<len && robotstxt[posm]!=':') posm++;
//找换行符位置,确定posr
posr = posm+1;
while(posr<len && robotstxt[posr]!='\n') posr++;

for(j=0,i=posl;i<posm;i++)
{
if(robotstxt[i]!=' '&&robotstxt[i]!='\t'&&robotstxt[i]!='\r'&&robotstxt[i]!='\n')
key[j++] = robotstxt[i];
}
key[j] = '\0';
for(j=0,i=posm+1;i<posr;i++)
{
if(robotstxt[i]!=' '&&robotstxt[i]!='\t'&&robotstxt[i]!='\r'&&robotstxt[i]!='\n')
value[j++] = robotstxt[i];
}
value[j]='\0';
posl = posr;
//cout<<key<<"\t"<<value<<endl;
//确定user-agent,是否针对本爬虫
if(strcmp(strlwr(key),"user-agent")==0){
if(strcmp(value,"*")==0||strcmp(value,"webcrawler")==0)
{
hasAgent = true;
}
else hasAgent = false;
}
if(hasAgent)
{
int len_val = strlen(value);
if(len_val<=0) continue;
if(strcmp(strlwr(key),"disallow")==0 && disallow_size<MAXDISALLOW)
{
disallow[disallow_size] = new char [len_val+1];
strcpy(disallow[disallow_size],strlwr(value));
disallow_size++;
}
else if (strcmp(strlwr(key),"allow")==0 && allow_size<MAXDISALLOW)
{
allow[allow_size] = new char [len_val+1];
strcpy(allow[allow_size],strlwr(value));
allow_size++;
}
else if(strcmp(strlwr(key),"craw-delay")==0)
{
crawldelay = 0;
int len_val = strlen(value);
for(int i=0;i<len_val;i++)
{
crawldelay = crawldelay * 10 + value[i]-'0';
}
}
}
}
}

void robotsFilter::printDisallow()
{
for(int i=0;i<disallow_size;i++)
{
cout<<disallow[i]<<endl;
}
}
//url->file属性与robots.txt匹配串的匹配,如果匹配成功返回true,否则返回false
bool robotsFilter::robotsMatch(char * match ,char * file)
{
int len_match = strlen(match);
if(len_match<=1) return true;
int len_file = strlen(file);
if(len_match>len_file) return false;
// ends with '$'
if(match[len_match-1]=='$')
{
int pos_match = 0;
char head [50],tail[20];
pos_match = len_match - 1;
while(pos_match>=0&&match[pos_match]!='*') pos_match --;
strncpy(head,match,pos_match);
head[pos_match] = '\0';
strncpy(tail,match+pos_match+1,len_match-pos_match-2);
tail[len_match-pos_match-2] = '\0';
int lhead = pos_match;
int ltail = len_match-pos_match-2;
int i = 0;
while(i<lhead && head[i]==file[i]) i++;
if(i!=lhead) return false;
i=0;
while(i<ltail && tail[i]==file[len_file-ltail+i]) i++;
if(i!=ltail) return false;
return true;
}
// 统计 '*'
int starlist [10] , starcount=0;
for(int i=0;i<len_match;i++)
if(match[i]=='*')
starlist[starcount++] = i;
//if have no star
if(starcount==0)
{
int i=0;
while(i<len_match && match[i]==file[i]) i++;
if(i!=len_match) return false;
else return true;
}
// if have star
/*
算法如下,首先按照'*',分割为多给子串
然后各个子串需按序匹配到file文本,且每个子串按首次匹配为准
*/
int i=0;
//test head
while(i<starlist[0]&&match[i]==file[i]) i++;
if (i!=starlist[0]) return false;
//test tail
if(match[len_match-1]!='*')
{
int length = len_match - (starlist[starcount-1] + 1);
i = 0;
while(i<length && match[len_match - i -1] == file[len_file - i -1]) i++;
if (i!=length) return false;
}

// match each star
int start_match , end_match , start_file = starlist[0];
char case_str [50];
for(int i=1;i<starcount;i++)
{
start_match = starlist[i-1]+1;
end_match = starlist[i];
strncpy(case_str,match+start_match,end_match-start_match);
case_str[end_match-start_match] = '\0';
int i = start_file;
int j = 0;
//match case_str , perhaps KMP algorithms is better than mine
while(i<len_file && j<(end_match-start_match))
{
if(file[i]==case_str[j]){
++i;++j;
}else{
i = i-j+1;
j = 0;
}
}
if(j==(end_match-start_match))
{
start_file = i;
}else return false;
}
return true;
}

// if u->file matches robots.txt ,return false ; otherwise true
bool robotsFilter::filter(url * u)
{
/*
*robots.txt里面可能有Allow,也可能有Disallow
*其实如果两个都设置的话,会有一点歧义,crawler不知道到底应不应该爬
*这里给出的方法是:两个都进行测试,只要通过一个就ok。
*/
if(disallow_size<=0 && allow_size<=0 ) return true;
bool pass_disallow = true;
if(disallow_size>0)
{
if(strcmp(disallow[0],"/")==0 || strcmp(disallow[0],"*")==0
||strcmp(disallow[0]," ")==0 ||strcmp(disallow[0],"")==0)
pass_disallow = false;
else
{
for(int i=0;i<disallow_size;i++)
{
if (robotsMatch(disallow[i],u->getFile())) {
pass_disallow = false;
break;
}
}
}
}
else pass_disallow = false;
if(pass_disallow==true) return true;

bool pass_allow = false;
if (allow_size>0)
{
if(strcmp(allow[0],"/")==0 || strcmp(allow[0],"*")==0) pass_allow = true;
else
{
for(int i=0;i<allow_size;i++)
{
if (robotsMatch(allow[i],u->getFile()))
{
pass_allow = true;
break;
}
}
}
}
return pass_allow;
}
bool robotsFilter::filter(const char * url_text)
{
char tmp [150];
strcpy(tmp,url_text);
url * u = new url(tmp,0,0);
bool res = filter(u);
delete u;
return res;
}




相关文章:

CF949C Data Center Maintenance(建图+强联通分量)

题意 有 n 个信息中心&#xff0c;第 i 个信息中心要在第 ti 个小时维护&#xff0c;维护期间信息不能被获得。 每个用户的数据都有两份备份&#xff0c;第 i 个用户的数据放在信息中心 c(i,1) 和 c(i,2)。 现在要挑选一个尽量小的信息中心集合&#xff0c;使得将这个集合的维护…

fabric 启动peer_编写 Fabric 链码的一般准则

我相信智能合约(链码)是 Hyperledger Fabric 区块链网络的核心。正确开发链码可以真正发挥一个安全区块链的优势&#xff0c;反之则会带来灾难性的后果。在这篇文章里我不打算探讨 Hyperledger Fabric 链码设计的特定模式的好与坏&#xff0c;而是希望分享我在开发若干 Hyperle…

Qt pro文件下跨平台宏的使用(windows/linux 以及x86 和 arm的区分)

#Qt pro文件下跨平台宏的使用&#xff08;windows/linux 以及x86 和 arm的区分&#xff09; 在pro文件中添加&#xff1a; #仅在linux 系统下&#xff0c; 硬件平台无关的内容 unix{HEADERS \SOURCES \Manager.cpp \ }#arm64 的编译宏 contains(QMAKE_HOST.arch, aarch64){…

数论(一)——素数,GCD,LCM

这是一个数论系列&#xff1a;&#xff09; 一、素数 费马小定理 Theorem&#xff1a; 设 p 是一个素数,a 是一个整数且不是 p 的倍数,那么 很遗憾,费马小定理的逆定理是不成立的。对 a 2,满足的非素数 n 是存在的。 比如 n 341 11 31 对于整数 a,称满足的合数为以 a 为底的…

java自学 day1

1.数据类型 基本数据类型&#xff08;存放数据本身&#xff09; 分为数值型&#xff08;int&#xff0c;double等&#xff09; 字符型&#xff08;char&#xff09;布尔型&#xff08;boolean&#xff09; 引用数据类型&#xff08;存放数据的地址&#xff09;分为类&#xff0…

Qt下一行代码就可以使用的稳定易用的日志log类

Qt下一行代码就可以使用的稳定易用的日志类 此日志类是基于Qt 自带的 扩展的一个易用的日志类&#xff0c; 使用的是Qt自带的日志输出形式&#xff0c; 已长期运行在许多实际项目中&#xff0c;稳定可靠&#xff0c;而且跨平台&#xff0c; 在windows和linux 上都能稳定运行 …

apue读书笔记-第十二章

1 可重入&#xff0c;线程安全&#xff0c;异步信号安全之间的区别&#xff1f; 可重入&#xff1a;可以重复进入&#xff0c;不会引起问题&#xff08;这个概念最宽&#xff09; 线程安全&#xff1a;被多个线程使用时&#xff0c;不会出问题&#xff0c;也就是可以被多个进程…

取出url中的字符_如何在JavaScript中解析URL:例如主机名,路径名,查询,哈希?...

统一资源定位符&#xff08;缩写URL&#xff09;是对Web资源&#xff08;网页&#xff0c;图像&#xff0c;文件&#xff09;的引用。URL指定资源位置和检索资源的机制&#xff08;http&#xff0c;ftp&#xff0c;mailto&#xff09;。例如&#xff0c;这是此博客文章的URL&am…

SQL Server 2008中的Pivot和UnPivot

SQL Server 2008中SQL应用系列--目录索引 今天给新成员讲解PIVOT 和 UNPIVOT示例&#xff0c;顺便整理了一下其用法。这是自SQL Server 2005起提供的新功能。 官方示例&#xff1a;http://msdn.microsoft.com/zh-cn/library/ms177410%28vsql.105%29.aspx 首先看PIVOT示例&#…

leetcode python 032 识别最长合法括号

# 给定一个只包含字符&#xff08;和&#xff09;的字符串&#xff0c;# 找到最长的有效&#xff08;格式良好&#xff09;括号子字符串的长度。# 对于“&#xff08;&#xff08;&#xff09;”&#xff0c;最长的有效括号子串是“&#xff08;&#xff09;”&#xff0c;其长…

Android窗口管理服务WindowManagerService计算Activity窗口大小的过程分析

在Android系统中&#xff0c;Activity窗口的大小是由WindowManagerService服务来计算的。WindowManagerService服务会根据屏幕及其装饰区的大小来决定Activity窗口的大小。一个Activity窗口只有知道自己的大小之后&#xff0c;才能对它里面的UI元素进行测量、布局以及绘制。本文…

pcl需要注意的编译问题

pcl需要注意的编译问题 不要在头文件里 using namespace pcl 这会导致编译错误,而且根本分析不到错误在哪 不要在编译选项 里加 -marchnative 这个是让编译器根据你当前的cpu类型进行特定的编译优化, 例如 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdc11 -march…

linux python版本_linux下更新Python版本并修改默认版本

linux下更新Python版本并修改默认版本&#xff0c;有需要的朋友可以参考下。很多情况下拿到的服务器python版本很低&#xff0c;需要自己动手更改默认python版本1、从官网下载python安装包(这个版本可以是任意版本3.3 2.7 2.6等等)wget http://python.org/ftp/python/2.7/Pytho…

基于HTML5的Google水下搜索

这次愚人节的时候&#xff0c;Google推出了水下搜索&#xff0c;当然&#xff0c;这只是一个愚人的小把戏&#xff0c;不过效果非常不错&#xff0c;进入页面后&#xff0c;第一眼是一个水面的效果&#xff0c;水下的鲨鱼在游来游去&#xff0c;然后Google logo和搜索框从水面上…

windows下rpc框架thrift的环境配置

windows下rpc框架thrift的环境配置 引用链接: https://www.cnblogs.com/49er/p/7193829.html 最近在弄windows下 的Facebook的rpc 框架 thrift , 网上东西看了很多, 但是大都不能一篇到位, 这里总结了一下, 也记一下自己遇到的问题和解决的方法 这里把我在实际过程中遇见的问…

CentOS 6.3 安装 samba 共享

PHP环境在linux下&#xff0c;但是开发的时候用的是windows&#xff0c;于是我用了samba将linux的一个目录共享&#xff0c;然后在windows上做映射&#xff0c;这样就可以直接在windows下编辑linux上的文件了 首先&#xff0c;安装samba软件&#xff0c;我采用的是yum安装&…

微信小程序 长按图片不出现菜单_微信更新,新功能上了热搜

微信在推出新功能方面相当克制&#xff0c;但每一次总能引起全网关注。昨天&#xff0c;微信又因为一个小功能的改进再次上了热搜&#xff0c;在安卓最新的 7.0.17 版本当中&#xff0c;微信取消了两分钟内删除功能。在新版微信中&#xff0c;发出的消息在两分钟内只有撤回功能…

windows下配置java环境jdk

Windows系统下搭建java的开发环境和配置环境变量 具体步骤打开链接地址&#xff1a;https://www.cnblogs.com/lijuntao/p/6694483.html转载于:https://www.cnblogs.com/ccw869476711/p/9401468.html

mysql 分区_搞懂MySQL分区

一.InnoDB逻辑存储结构首先要先介绍一下InnoDB逻辑存储结构和区的概念&#xff0c;它的所有数据都被逻辑地存放在表空间&#xff0c;表空间又由段&#xff0c;区&#xff0c;页组成。段段就是上图的segment区域&#xff0c;常见的段有数据段、索引段、回滚段等&#xff0c;在In…

apt Could not get lock /var/lib/dpkg/lock 解决方案

apt Could not get lock /var/lib/dpkg/lock 解决方案 删除锁定文件 sudo rm /var/lib/dpkg/lock

oracle创建DBLink连接

1.创建dblink的第一种方式&#xff0c;是在本地数据库tnsnames.ora文件中配置了要远程访问的数据库。tnsnames.ora文件在你安装oracle客户端安装文件里 如&#xff1a;(E:\oracle\product\10.2.0\db_1\NETWORK\ADMIN) 创建远程连接&#xff1a; INT (DESCRIPTION (ADDRES…

理解oracle中连接和会话

理解oracle中连接和会话1. 概念不同&#xff1a;概念不同&#xff1a; 连接是指物理的网络连接。 在已建立的连接上&#xff0c;建立客户端与oracle的会话&#xff0c;以后客户端与oracle的交互都在一个会话环境中进行。 2. 关系是多对多&#xff1a; 一个连接上可以建立0个…

ActiveMQ消息存储持久化

转https://www.cnblogs.com/xinhuaxuan/p/6128380.html https://blog.csdn.net/lr131425/article/details/68064914 为了避免意外宕机以后丢失信息&#xff0c;需要做到重启后可以恢复消息队列&#xff0c;消息系统一般都会采用持久化机制。 就是在发送者将消息发送出去后&…

python 非_Python函数的非固定参数

一、概述在原来的文章中我已经写了&#xff0c;位置参数和关键字参数&#xff0c;下面我们来谈谈默认参数和参数组二、默认参数默认参数指的是&#xff0c;我们在传参之前&#xff0c;先给参数制定一个默认的值。当我们调用函数时&#xff0c;默认参数是非必须传递的。默认参数…

C#关于面对象多态例子

//主的喂狗 class Program { static void Main(string[] args) { //我们来模拟一个主人养狗动物的例子 首先创建一个主人对象,同时主人买了条狗 //买来条狗&#xff0c;主人一喂&#xff0c;狗会吃东西 Person person ne…

ubuntu package XXX needs to be reinstalled,but I can't find an archive 问题修复

ubuntu package XXX needs to be reinstalled, but I can’t find an archive 修复 原文连接: https://blog.csdn.net/tbitwqb/article/details/78241101 内容&#xff1a; 不知道什么原因&#xff0c;可能是升级过程过关机或者其他什么情况导致当前问题的发生。 无论是apt…

CentOS6.2解决passwd: Authentication token manipulation error报错

passwd: Authentication token manipulation error这种错误可能有多种原因&#xff0c;就我了解的可能有/etc/passwd等文件i权限 今天在给学员上课的时候发现提示passwd: Authentication token manipulation error错误&#xff0c;我来简单描述今天的问题 [roothost4 Scripts]#…

Java核心技术第五章——2.Object类

Object类&#xff1a;所有类的超类 Object类是Java中所有类的始祖&#xff0c;在Java中每个类都是由它扩展而来的。但是并不需要这样写&#xff1a; public class Emloyee extends Object 如果没有明确的指出超类&#xff0c;Object就被认为是这个类的超类。在Java中&#xff0…

21day学通python_铁乐学python_day21_面向对象编程3

抽象类和接口类以下内容大部分摘自博客http://www.cnblogs.com/Eva-J/继承有两种用途&#xff1a;一&#xff1a;继承基类的方法&#xff0c;并且做出自己的改变或者扩展(代码重用)二&#xff1a;声明某个子类兼容于某基类&#xff0c;定义一个接口类Interface&#xff0c;接口…

系统crash无法启动 tpm error / could not read size 0x8000000e

系统crash无法启动 tpm error / couldn’t read size 0x8000000e 原文连接: https://unix.stackexchange.com/questions/305719/a-tpm-error-7-occurred-attempting-to-read-a-pcr-value-in-centos 内容&#xff1a; 问题&#xff1a; I’m getting this error while booting…