注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Larbin[6]html源代码分析  

2010-04-19 19:58:50|  分类: Larbin |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

       到现在还没有提到如何把从一个页面中把url得到,加入到要爬取的url集合中去,现在从页面解析开始:

/* parse an html page */

void html::parseHtml() {

    while ((posParse = strchr(posParse, '<')) != NULL) {

       if (posParse[1] == '!') {

           if (posParse[2] == '-' && posParse[3] == '-') {

              posParse += 4;

               parseComment();

           } else {

              // nothing...

              posParse += 2;

           }

       } else {

           posParse++;

           parseTag();

       }

    }

}

       这里是找’<’字符,当然这是HTML里标签中的重要字符,如果以”<!”开头,有可能是注释(<!--XXXXXXXX-->),否则,则有可能是一个标签。先看parseComment

void html::parseComment() {

    while ((posParse = strchr(posParse, '-')) != NULL) {

       if (posParse[1] == '-' && posParse[2] == '>') {

           posParse += 3;

           return;

       } else {

           posParse++;

       }

    }

    posParse = buffer + pos;

}

       这里判断后面半截”-->”的代码,如果是注释,就跳过注释中的内容,不是注释,就从开始的位置开始。接下来看parseTag的前面一部分:

void html::parseTag() {

    skipSpace();

    char *param = NULL; // what parameter are we looking for

    int action = -1;

    // read the name of the tag

    if (thisCharIs(0, 'a')) { // a href

       param = "href";

       action = LINK;

       posParse++;

    } else if (thisCharIs(0, 'l')) {

        isTag(thisCharIs(1, 'i') && thisCharIs(2, 'n')

&& thisCharIs(3, 'k'), "href", LINK, 4);

    } else if (thisCharIs(0, 'b')) { // base href

       isTag(thisCharIs(1, 'a') && thisCharIs(2, 's')

&& thisCharIs(3, 'e'),"href", BASE, 4);

    } else if (thisCharIs(0, 'f')) { // frame src

       isTag(thisCharIs(1, 'r') && thisCharIs(2, 'a')

              && thisCharIs(3, 'm') && thisCharIs(4, 'e'),

              "src", LINK, 5);

#ifdef IMAGES

    } else if (thisCharIs(0, 'i')) { // img src

       isTag(thisCharIs(1, 'm') && thisCharIs(2, 'g'), "src", LINK, 3);

#endif // IMAGES

    } else {

       return;

    }

       skipSpace是除去空格,回车,换行,tab的宏:

#define skipSpace() \

  while (*posParse == ' ' || *posParse == '\n' \

         || *posParse == '\r' || *posParse == '\t') { \

    posParse++; \

  }

       接下来判断的标签依次是”a””link””base””frame””img”isTag这个宏就很简单了:

#define isTag(t, p, a, i) if (t) { \

      param = p; \

      action = a; \

      posParse += i; \

    } else { \

      posParse++; \

      return; \

    }

       link为例,t=thisCharIs(1, 'i') && thisCharIs(2, 'n') && thisCharIs(3, 'k'),也就是看l后面是不是ink这三个字符,如果不是,就返回,如果是param”href”action=LINKi=4

       下面是parseTag的后面一部分:

// now find the parameter

    assert(param != NULL);

    skipSpace();

    for (;;) {

       int i = 0;

       while (param[i] != 0 && thisCharIs(i, param[i]))

           i++;

       posParse += i;

       if (posParse[i] == '>' || posParse[i] == 0)

           return;

       if (param[i] == 0) {

           parseContent(action);

           return;

       } else {

           // not the good parameter

           nextWord();

       }

    }

}

       下面是判断接下来的字符是不是与param一样,也就是我们只关心与param这种参数。如果不是一个标签,则返回,如果是一个我们不关心的标签,就跳过这个标签的内容。如果是我们关心的标签,则用parseContent函数的前半部分:

posParse++;

    while (*posParse == ' ' || *posParse == '=')

       posParse++;

    if (*posParse == '\"' || *posParse == '\'')

       posParse++;

    area = posParse;

    char *endItem = area + maxUrlSize;

    if (endItem > buffer + pos)

       endItem = buffer + pos;

    while (posParse < endItem && *posParse != '\"' && *posParse != '\''

           && *posParse != '\n' && *posParse != ' ' && *posParse != '>'

           && *posParse != '\r' && *posParse != '\t'

&& notCgiChar(*posParse)) {

       if (*posParse == '\\')

           *posParse = '/'; // Bye Bye DOS !

       posParse++;

    }

       这里略过空格和=号,因为参数后面要写一个等号的,再有就有双引号与单引号,也就是我们想得到的参数值前的引号,这里限制了url的长度(maxUrlSize),下面的while是去掉其它可能影响的字符。

if (posParse == buffer + pos) {

       // end of file => content may be truncated => forget it

       return;

    } else if (posParse < endItem && notCgiChar(*posParse)) {

       // compute this url (not too long and not cgi)

       char oldchar = *posParse;

       *posParse = 0;

       switch (action) {

       case LINK:

           // try to understand this new link

           manageUrl(new url(area, here->getDepth() - 1, base), false);

           break;

       case BASE:

           // This page has a BASE HREF tag

       {

           uint end = posParse - area - 1;

           while (end > 7 && area[end] != '/')

              end--; // 7 because http://

           if (end > 7) { // this base looks good

              end++;

              char tmp = area[end];

              area[end] = 0;

              url *tmpbase = new url(area, 0, (url *) NULL);

              area[end] = tmp;

              delete base;

              if (tmpbase->isValid()) {

                  base = tmpbase;

              } else {

                  delete tmpbase;

                  base = NULL;

              }

           }

       }

           break;

       default:

           assert(false);

       }

       *posParse = oldchar;

    }

    posParse++;

       前一个if是判断是不是超过了文件的长度,case BASE中是得到base,即基地址,这个比较简单,如果是case LINK,则调用manageUrl

void html::manageUrl(url *nouv, bool isRedir) {

    if (nouv->isValid() && filter1(nouv->getHost(), nouv->getFile())

           && (global::externalLinks

|| isRedir || !strcmp(nouv->getHost(),

                  this->here->getHost()))) {

       // The extension is not stupid (gz, pdf...)

#ifdef LINKS_INFO

       links.addElement(nouv->giveUrl());

#endif // LINKS_INFO

       if (nouv->initOK(here)) {

           check(nouv);

       } else {

           // this url is forbidden for errno reason (set by initOK)

           answers(errno);

           delete nouv;

       }

    } else {

       // The extension is stupid

       delete nouv;

    }

}

       filter1已经在check中看过了,它是对文件格式的过滤,而initOK是对url判断,看它是不是合理的,如果合理,就会调用check,也就是如果是没有见过的,就会根据它的文件后缀将它加入到URLsDisk中或是UrlsPriority中,这也就是何时将url加入集合中去的。

       再看一个函数:

int html::verifType() {

    if (startWithIgnoreCase("content-type: ", area)) {

       // Let's read the type of this doc

       if (!startWithIgnoreCase("text/html", area + 14)) {

#ifdef SPECIFICSEARCH

           if (matchContentType(area+14)) {

              interestingSeen();

              isInteresting = true;

           } else {

              checkType();

           }

#else // SPECIFICSEARCH

           checkType();

#endif // SPECIFICSEARCH

       }

    }

    return 0;

}

       这里会判断这种type是不是我们想要的,matchContentType如果定义了SPECIFICSEARCH,则为:

bool matchContentType (char *ct) {

    int i=0;

    while (contentTypes[i] != NULL) {

       if (startWithIgnoreCase(contentTypes[i], ct))

       return true;

       i++;

    }

    return false;

}

      

 

 

  评论这张
 
阅读(2751)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017