使用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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...