使用HttpGet協議與正則表達實現桌面版的糗事百科

来源:http://www.cnblogs.com/mingjiatang/archive/2016/04/28/5441263.html
-Advertisement-
Play Games

寫在前面 最近在重溫asp.net,找了一本相關的書籍。本書在第一章就講了,在不使用瀏覽器的情況下生成一個web請求,獲取伺服器返回的內容。於是在網上搜索關於Http請求相關的資料,發現了很多資料都是講述基於HttpGet和HttpPost請求伺服器的資源,然根據Get和Post的單詞意思就大概知道 ...


寫在前面
最近在重溫asp.net,找了一本相關的書籍。本書在第一章就講了,在不使用瀏覽器的情況下生成一個web請求,獲取伺服器返回的內容。於是在網上搜索關於Http請求相關的資料,發現了很多資料都是講述基於HttpGet和HttpPost請求伺服器的資源,然根據Get和Post的單詞意思就大概知道Get(得到)意為從服務中獲取資源,而Post(發送)意為先發送數據包返還給伺服器再獲取伺服器資源。當然他們之間還有一些其他的區別,但是本文主要講的不是這個。當知道如何使用Get和Post的請求去訪問伺服器的數據,我就迫不及待找一些網頁來做測試,於是就有了糗事百科的Winform版啦。 下麵給大家看看效果。   下麵我將這個過程分為以下幾個部分來進行講解,併在文章的最後提供下載鏈接。 1、分析糗事百科的網頁,構造web請求。 2、分析網頁html源代碼,提取需要的信息。 3、數據綁定。     1、分析糗事百科的網頁,構造web請求

打開糗事百科笑話的主頁,在這裡我只取糗事笑話中文字這一板塊,點擊文字這一菜單欄。如下圖。

  1.1 獲取糗事百科內容的url 從上圖可以看出,文字版本的url鏈接為:http://www.qiushibaike.com/textnew/page/2/?s=4869039。根據鏈接的內容可以看出http://www.qiushibaike.com為該網頁的主機部分是不變的,/textnew/page代表是文字笑話這一主題的頁面也是不變的,而後面的數字2?s=4869039是url中變換不同頁面內容的關鍵,通過分析得知數字2代表不同的文字笑話的頁數,而?s=4869039沒有弄得很清楚,估計是標識符啥的,但是並不影響,我們就把它固定下來,不做改變。綜上所述在http://www.qiushibaike.com/textnew/page/2/?s=4869039中我們只需要變動數字2就可以獲取不同頁面的文字笑話內容。     1.2 構造HttpGet請求的頭信息 上一步我們獲取了文字內容頁面的url,下麵我需要模擬瀏覽器針對這個url構造一個Get請求,從而獲取糗百的頁面數據。打開瀏覽器的開發者工具,從中可以看到瀏覽器構造的詳細的http請求的報頭信息如下圖。然後我們在代碼中仿照這樣的請求報頭信息去請求伺服器資源。    註意:其中紅線標示的部分在實例化一個Http請求類時都需要被設置,否則會得到錯誤的返回結果。    1.3 c#實現糗百網頁的抓取 根據上面的分析,我使用c#語言並利用System.Net程式集中的HttpWebRequest和HttpWebResponse這兩個類去實現網頁內容的抓取。 源代碼如下:  
const string qsbkMainUrl = "http://www.qiushibaike.com";

//獲取糗百文字笑話頁的url


 private static string GetWBJokeUrl(int pageIndex)

  {

            StringBuilder url = new StringBuilder();

            url.Append(qsbkMainUrl);

            url.Append ("/textnew/page/");

            url.Append(pageIndex.ToString ());

            url.Append("/?s=4869039");

            return url.ToString();

    }

//根據網頁的url獲取網頁的html源碼


 private static string  GetUrlContent(string url)
 {
            try

            {

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

                request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.8.1000 Chrome/30.0.1599.101 Safari/537.36";

                request.Method = "GET";

                request.ContentType = "text/html;charset=UTF-8";

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                Stream myResponseStream = response.GetResponseStream();

                StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));//因為知道糗百網頁的編碼方式為utf-8

                string retString = myStreamReader.ReadToEnd();

                myStreamReader.Close();

                myResponseStream.Close();

                return retString;

            }

            catch { return null; }

  }

  

2、分析網頁html源代碼,提取需要的信息
在1中我們已經根據page頁索引的不同而獲取不同的頁面內容,而這一步的任務就是如何從返回的html源代碼中獲取我們想要的笑話內容。 我們提取網頁文字的笑話內容包括三個部分:發佈笑話者的頭像,發佈笑話者的昵稱,發佈內容。   2.1 分析網頁構造正則表達式 首先我們對html源碼進行分析並找出我們想要的內容所在的標簽位置,以及它們的html的結構。     這上面是我分析的我們所需要的內容所在html源碼中的標簽位置,由於一個頁面中每條笑話的html顯示標簽都是一樣的,所以只要能偶提取一條笑話的內容,那麼該頁的其它笑話也可以同樣提取。由於這種結構基本是固定的,每個笑話的各部分內容都是用相同的html標簽表示,並且位置也是相同的,因此在寫正則表達的時候,可以用很多常量字元去固定,這樣能夠加快正則的匹配效率。下麵給出匹配笑話內容的正則表達,(通過分組實現捕獲一個笑話的不同內容)。當然這個正則表達式可能存在一些不能完全精確匹配的情況。  
正則<img src="([^"]*")\s*alt="([^"]*)"/>\s</a>\s<a href="([^"]*)"[^>]*>\s<h2>[^>]*>\s</a>\s</div>\s*<div class="content">\s*((.*|<br/>)*)
  其中,第一個括弧裡面的內容代表“頭像地址”,第二個括弧裡面的內容代表“昵稱”,第三個括弧裡面的內容代表“笑話內容”   2.2 編碼獲取頁面的所有笑話  a、首先建一個笑話的實體類 
public class JokeItem

    {

        private string nickName;

        /// <summary>

        /// 昵稱

        /// </summary>

        public string NickName

        {

            get { return nickName; }

            set { nickName = value; }

        }

 

        private Image headImage;

        /// <summary>

        /// 頭像

        /// </summary>

        public Image HeadImage

        {

            get { return headImage; }

            set { headImage = value; }

        }

        private string jokeContent;

        /// <summary>

        /// 笑話內容

        /// </summary>

        public string JokeContent

        {

            get { return jokeContent; }

            set { jokeContent = value; }

        }

 

        private string jokeUrl;

        /// <summary>

        /// 笑話地址

        /// </summary>

        public string JokeUrl

        {

            get { return jokeUrl; }

            set { jokeUrl = value; }

        }

}

b、利用正則獲取笑話內容

/// <summary>

        /// 獲取笑話列表

        /// </summary>

        /// <param name="htmlContent"></param>

        public static  List<JokeItem> GetJokeList(int pageIndex)

        {

            string htmlContent=GetUrlContent(GetWBJokeUrl(pageIndex));

            List<JokeItem> jokeList = new List<JokeItem>();

            Regex rg = new Regex(@"<img src=""([^""]*"")\s*alt=""([^""]*)""/>\s</a>\s<a href=""([^""]*)""[^>]*>\s<h2>[^>]*>\s</a>\s</div>\s*<div class=""content"">\s*((.*|<br/>)*)", RegexOptions.IgnoreCase);

            JokeItem joke;

            MatchCollection matchResults = rg.Matches(htmlContent);

 

            foreach (Match result in matchResults)

            {

                joke = new JokeItem();

                joke.HeadImage = GetWebImage(result.Groups[1].Value);

                joke.HeadImage = joke.HeadImage != null ? new Bitmap(GetWebImage(result.Groups[1].Value), 50, 50) : null;

                joke.NickName = result.Groups[2].Value;

                joke.JokeUrl = qsbkMainUrl + "/" + result.Groups[3].Value; ;

                joke.JokeContent = result.Groups[4].Value.Replace("<br/>", "\r\n").Replace("<br>", "\r\n");

                joke.JokeContent = Regex.Replace(joke.JokeContent, @"(\r\n)+", "\r\n");//去掉多餘的空行

                jokeList.Add(joke);

            }

            return jokeList;

        }

 

c、根據頭像url地址獲取頭像

 private static Image GetWebImage(string webUrl)

        {

            try

            {

                Encoding encode = Encoding.GetEncoding("utf-8");//網頁編碼==Encoding.UTF8  

                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(new Uri(webUrl));

                HttpWebResponse ress = (HttpWebResponse)req.GetResponse();

                Stream sstreamRes = ress.GetResponseStream();

                return System.Drawing.Image.FromStream(sstreamRes); 

            }

            catch { return null; }

        }

 

3、數據綁定


數據都獲取了,數據綁定是最容易的一步,由於數據獲取這一步牽涉到web請求,會發生幾秒的網路延遲,因此需要使用一個後臺的工作線程去請求數據。在此處採用backgroundWorker控制項來實現非同步請求數據。其中UI部分借用了兩個第三方控制項,一個是載入的等待條,另一個是數據綁定控制項。數據綁定代碼就不貼出來了。可以在下麵下載我的源碼。   4、總結
在這個過程中,我對http的請求方式有了進一步的理解,也終於把平常學習的正則表達式發揮了用處。 把平常學習到的技術綜合起來再結合一個好的想法就會做出讓自己意想不到的小程式,希望自己以後能多把自己學習的技術與實踐結合起來。   開發環境:vs2013,.net2.0 源碼地址:http://download.csdn.net/detail/mingge38/9504931  
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 【一】從第3000行開始,顯示1000行。即顯示3000~3999行 cat filename | tail -n +3000 | head -n 1000 【二】顯示1000行到3000行 cat filename| head -n 3000 | tail -n +1000 *註意兩種方法的順序 ...
  • 最近在公司搭建AD域控制器,發現無法在電腦真正添加域用戶,也就是添加的用戶雖然可以在本地登錄,但是無法遠程登錄,嘗試多種方法都無法解決,而最終原因居然是虛擬機導致的伺服器的SID衝突。本文記錄下該問題的發生原因和解決過程。 添加域賬戶 在域用戶裡面添加一個用戶,如下圖: (圖1) 將用戶添加到“開 ...
  • 安裝: 1. UnixBench from version 5.1 on has both system and graphics tests. If you want to use the graphic tests, edit the Makefile and make sure that th ...
  • 安裝samba完後會生成samba目錄 > /etc/samba http://blog.csdn.net/xt_xiaotian/article/details/4216408 允許的IP地址段,將自己的IP地址段加入即可(註意IP的最後一段沒有,但後邊有個點) 重啟機器時,smb服務並不會自動啟 ...
  • LNMT在網站架構中的實現過程: Client --> http --> Nginx --> reverse_proxy (http) --> tomcat (http connector) --> mysql 但是當nginx有大量的併發請求時,nginx會反代大量的併發請求至tomcat,這時為 ...
  • 介紹 本篇主要介紹Linux定時任務命令crontab的用法,crontab是定時任務的命令,而crond則是定時任務的啟動服務。crontab的定時任務分為系統任務和用戶任務,其實二者沒有太大的區別。 啟動 在Centos中crond服務預設是自動啟動的,如果沒有啟動可以手動啟動,具體方法如下。 ...
  • 情形: 1.主機(host):ubuntu 2.虛擬機里安裝的操作系統版本(guest):windows 7專業版 3.simplify3d破解版版本:3.0.2(破解需要的工具均在下文的百度雲地址里) 所需文件下載地址:http://pan.baidu.com/s/1slUoEZz,密碼:57cs ...
  • 在測試前,理應瞭解本機所具備的特點,比如CPU頻率、記憶體頻率、記憶體大小,等等信息。 查看CPU用如下命令(多少個核,頻率,特性等): cat /proc/cpuinfo 查看記憶體用如下命令:(只有當前記憶體大小,已用空間等等,不能看到記憶體頻率) cat /proc/meminfo 要查看記憶體型號和頻率 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...