1. 定义URL类型
搜索引擎程序首先必须要做的一件事情是根据一个给定的URL,组成消息体,发送给该URL 指向的服务器。为此,定义 Url 类。关于 URL 的详细介绍可以参看RFC2396 Uniform Resource Identifiers (URI): Generic Syntax[RFCs,2004]。
下面是URL类的定义,对应文件Url.h。
enum url_scheme{
SCHEME_HTTP,
SCHEME_FTP,
SCHEME_INVALID
};
class CUrl
{
public:
string m_sUrl; // URL字串
enum url_scheme m_eScheme; // 协议名
string m_sHost; // 主机名
int m_nPort; // 端口号
string m_sPath; // 请求资源
public:
CUrl();
~CUrl();
bool ParseUrl( string strUrl );
private:
void ParseScheme ( const char *url );
};
URL可以是HTTP, FTP等协议开始的字符串, TSE主要是针对HTTP协议,为了不失一般性,在 url_scheme 中定义了 SCHEME_HTTP,SCHEME_FTP,SCHEME_INVALID,分别对应HTTP协议,FTP协议和其他协议。一个URL由6个部分组成:
<scheme>://<net_loc>/<path>;<params>?<query>#<fragment>
除了scheme部分,其他部分可以不在URL中同时出现。 Scheme 表示协议名称,对应于URL类中的m_eScheme. Net_loc 表示网络位置,包括主机名和端口号,对应于URL类中的m_sHost和m_nPort.
下面四个部分对应于URL类中的m_sPath.
Path 表示URL 路径.
Params 表示对象参数.
Query 表示查询信息,也经常记为request.
Fragment 表示片断标识.
为了程序的简化,URL 类的实现主要是解析出 net_loc 部分,用于组成消息体,发送给服务器。
其中 void CUrl::ParseUrlEx(const char *url, char *protocol, int lprotocol, char *host, int lhost, char *request, int lrequest, int *port) 执行具体的字符串匹配找出协议名,主机名,请求信息和端口号,找到后赋给 Url 类的成员变量保存。在URL类中还有些是TSE抓取过程中的细节函数, 如char* CUrl::GetIpByHost(const char *host),CUrl::IsValidHost(const char *host),bool CUrl::IsVisitedUrl(const char *url)等,此处就不一一介绍了。读者可以通过阅读TSE的代码获得这部分的具体实现。
2. 定义Page类
有了 URL,搜集系统就可以按照 URL 标识抓取其所对应的网页,网页信息保存在Page类中。 下面是Page类的定义,对应文件Page.h。
class CPage
{
public:
string m_sUrl;
// 网页头信息
string m_sHeader;
int m_nLenHeader;
int m_nStatusCode;
int m_nContentLength;
string m_sLocation;
bool m_bConnectionState; // 如果连接关闭, 是false, 否则为true
string m_sContentEncoding;
string m_sContentType;
string m_sCharset;
string m_sTransferEncoding;
// 网页体信息
string m_sContent;
int m_nLenContent;
string m_sContentNoTags;
// link, in a lash-up state
string m_sContentLinkInfo;
// 为搜索引擎准备的链接,in a lash-up state
string m_sLinkInfo4SE;
int m_nLenLinkInfo4SE;
// 为历史存档准备的链接, in a lash-up state
string m_sLinkInfo4History;
int m_nLenLinkInfo4History;
//为搜索准备的链接,in a good state
RefLink4SE m_RefLink4SE[MAX_URL_REFERENCES];
int m_nRefLink4SENum;
//为历史存档准备的链接, in a good state
RefLink4History m_RefLink4History[MAX_URL_REFERENCES/2];
int m_nRefLink4HistoryNum;
map<string,string> m_mapLink4SE;
vector<string > m_vecLink4History;
enum page_type m_eType; // 网页类型
public:
CPage();
CPage::CPage(string strUrl, string strLocation, char* header, char* body,
int nLenBody);
~CPage();
void ParseHeaderInfo(string header); // 解析网页头信息
bool ParseHyperLinks(); // 从网页体中解析链接信息
bool NormalizeUrl(string& strUrl);
bool IsFilterLink(string plink);
private:
// 解析网页头信息
void GetStatusCode(string header);
void GetContentLength(string header);
void GetConnectionState(string header);
void GetLocation(string header);
void GetCharset(string header);
void GetContentEncoding(string header);
void GetContentType(string header);
void GetTransferEncoding(string header);
// 从网页体中解析链接信息
bool GetContentLinkInfo();
bool GetLinkInfo4SE();
bool GetLinkInfo4History();
bool FindRefLink4SE();
bool FindRefLink4History();
};
Page 类的具体实现请参看 Page.cpp 文件。一个网页是以 URL 作为标识的,所以 Page 类的第一个成员变量是 m_sUrl。Page 类主要完成两个任务:解析网页头信息和提取链接信息。 解析网页头信息包括获得状态码 m_nStatusCode ,网页体长度m_nContentLength(内容字节数),转向信息 m_sLocation,连接状态(如果没有关闭,下次请求同一个网站可以重新利用已经建立好的socket,节约资源) ,网页
体编码m_sContentEncoding(如果是gzip编码,要解压缩,然后提取链接信息。现在门户网站的首页有增大趋势,为了加快传输速度,通常采用gzip编码压缩后传输) ,网页类型 m_sContentType,网页体字符集 m_sCharset,和传输编码方式m_sTransferEncoding。
提取链接信息,是从获得的网页体中,根据HTML的规定,提取出链接信息和相应的链接描述信息,形成网页结构库,扩充 URL 库。在 TSE 中对于网页内容的链接提取区分了为搜索引擎提取和为历史网页存档提取两种。因为对于通常意义下的搜索引擎而言,图片链接,网页格式链接是没有用处的,如果不区分开,会增加程序运行的负担,增加存储空间。而且区分开后,可以单独保存下来,便于以后单独搜集这些信息。
(推荐阅读:dedecms优化url的技巧分享)
(推荐阅读:有没有必要进行URL静态化?)
(推荐阅读:Url中含有中文关键词是否好些?)
(推荐阅读:在IIS上配置404页面的图文教程)
(推荐阅读:从使用页面相似检测工具所想到的)