linux網頁抓取-2

五、解析網頁源代碼,得到所需要信息

解析html並不複雜,只是有點麻煩而已。因爲頁面不可能全部讀入內存在解析,只有分開讀。分開讀就必須要考慮需要查找的標籤有可能只讀到一部分這種情況。如讀1024字節數據,我需要在裏面找<div class="article_title">,碰巧的是,1024字節數據最後幾位是<div class.在這種情況下,我不能簡單的說1024字節裏沒有我所需要的,那就丟掉這1024字節。這樣導致的後果解析出來的文章有遺漏。
需要解析的標籤如下:
  1. #define ARTICLE_TITLE ("<div class=\"article_title\">")  
  2. #define ARTICLE_MANAGE ("<div class=\"article_manage\">")  
  3. #define BLOG_TITLE ("<div class=\"blog_title\">")  
  4. #define URL_LINK ("<a href=")  
  5. #define LINK_TITLE ("<span class=\"link_title\"><a href=")  
  6. #define LINK_TITLE_END ("</a></span>")  
  7. #define LINK_VIEW ("<span class=\"link_view\"")  
  8. #define LINK_COMMENTS ("<span class=\"link_comments\"")  
  9. #define LINK_POSTDATE ("<span class=\"link_postdate\">")  
  10. #define BLOG_RANK ("<ul id=\"blog_rank\">")  
  11. #define BLOG_STATISTICES (" <ul id=\"blog_statistics\">")  
  12. #define URL_END ("</a>")  
  13. #define DIV_END ("</div>")  
  14. #define SPAN ("<span>")  
  15. #define SPAN_END ("</span>")  
  16. #define UL_END  ("</ul>")  
我的解析流程圖如下所示,有待優化。



1、從保存的首頁中讀1024字節到數組。
2、strcat到2048個字節的數組,多定義一個2048字節的數組,就是爲了解決查找標籤有可能只讀到一部分的情況。
3、判斷狀態,自定義5個狀態

 

  1. #define TAG_RESOLV_ARTICLE 0  //解析文章標題、URL  
  2. #define TAG_RESOLV_ARTICLE_STATIS 1//解析文章訪問信息  
  3. #define TAG_RESOLV_RANK 2//解析博主博客的訪問信息  
  4. #define TAG_RESOLV_STATIS 3//解析博主文章統計  
  5. #define TAG_RESOLV_END 4//解析結束  

4、根據狀態查找相應的標籤位置。

   如果狀態爲TAG_RESOLV_RANK,則查找<ulid="blog_rank">和</ul>是否在數組中。只有兩個標籤同時在數組中,才解析標籤所包含的有用信息。當<ulid="blog_rank">存在,而</ul>不存在時,則丟掉<ulid="blog_rank">之前的數據,在讀1024字節數據後在解析。引用我自己寫的一段代碼來分析一下。

  1. /* 
  2. *功能:解析博客排名,訪問量等。 
  3. */  
  4. int resolvBlogRank(char *buf, int len, struct BloggerInfo *blogger, int *tag) {  
  5.     char *blog_rank_start, *blog_rank_end, *span_start, *span_end;  
  6.     char tmpbuf[BUFFERLEN * 2];  
  7.     int roll_back_loc,buf_len;  
  8.     bzero(tmpbuf, sizeof (tmpbuf));  
  9.     blog_rank_start = strstr(buf, BLOG_RANK);//找到BLOG_RANK第一次出現的位置(呵呵,只會出現一次)  
  10.     if (blog_rank_start == 0) {//如果buf數組裏面沒有出現BLOG_RANK,則只保留buf數組最後200個字節。爲什麼是200?主要是因爲BLOG_RANK所包括的字符長度目前不會超過200哈。  
  11.         buf_len=strlen(buf);  
  12.         roll_back_loc=buf_len-200>0?buf_len-200:0;  
  13.         strcat(tmpbuf, buf + roll_back_loc);  
  14.         bzero(buf, len);  
  15.         strcat(buf, tmpbuf);  
  16.     } else {//BLOG_RANK出現在buf裏面  
  17.         blog_rank_end = strstr(blog_rank_start + strlen(BLOG_RANK), UL_END);//找與<span style="white-space: pre-wrap; ">BLOG_RANK對應的結尾標籤,這裏是</ul></span>  
  18.         if (blog_rank_end == 0) {//UL標籤沒有找到,則保留BLOG_RANK之後的數據  
  19.             strcat(tmpbuf, blog_rank_start);  
  20.             bzero(buf, len);  
  21.             strcat(buf, tmpbuf);  
  22.         } else {//UL標籤找到  
  23.             span_start = strstr(blog_rank_start + strlen(BLOG_RANK), SPAN);  
  24.             span_end = strstr(span_start + strlen(SPAN), SPAN_END);  
  25.             blogger->visits = myatoi(span_start + strlen(SPAN), span_end);//myatoi函數是我自己寫的,用於將字符串轉換爲整數。如“第10000名”=》10000  
  26.             span_start = strstr(span_end + strlen(SPAN_END), SPAN);  
  27.             span_end = strstr(span_start + strlen(SPAN), SPAN_END);  
  28.             blogger->integral = myatoi(span_start + strlen(SPAN), span_end);  
  29.             span_start = strstr(span_end + strlen(SPAN_END), SPAN);  
  30.             span_end = strstr(span_start + strlen(SPAN), SPAN_END);  
  31.             blogger->ranking = myatoi(span_start + strlen(SPAN), span_end);  
  32.             *tag = TAG_RESOLV_STATIS;  
  33.             strcat(tmpbuf, blog_rank_end + strlen(UL_END));  
  34.             bzero(buf, len);  
  35.             strcat(buf, tmpbuf);  
  36.         }  
  37.     }  
  38.     return 0;  
  39. }  

5、循環,直到所解析的內容解析完畢

、根據解析出來的文章URL,發送HTTP請求,保存返回的網頁源代碼

我是以文章名作爲文件的名字,這裏需要注意一個問題,當文件名出現/時,必須把文件名中的/替換爲別的符號,我是替換爲_符號。因爲/在linux中屬於路徑的一部分。

至此,linux網頁抓取工具就宣告完畢。


接下來的工作:

1.網頁抓取是單線程的,接下來會採用多線程模式。
2.網頁抓取沒有抓取圖片。js,css,所以在有網絡的情況下才能呈現該有的樣子。
3.代碼很多地方需要優化,有的地方有點亂。
4.準備做個windows版本。不考慮做界面。
5.揉和window版本和linux版本,做個通用版。其實通用版還不是不同操作系統調用不同的函數而已。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章