抓取分析網頁批量下載評書(上)之搜索有聲小說

来源:http://www.cnblogs.com/claspcn/archive/2016/03/14/5275198.html
-Advertisement-
Play Games

一、背景       母親喜歡聽評書,跟著廣播每天一集總覺得不過癮,於是2010年給她買了一個帶記憶體,能播放MP3的音箱,從此給她找評書便成了我的責任和義務。       一開始開始還好,單先生說的書多,找起來不困難, 但隨著聽的越多,加上聽慣了單先生的,其他人的母親都不喜歡,即便單先生的,類似白眉


一、背景       母親喜歡聽評書,跟著廣播每天一集總覺得不過癮,於是2010年給她買了一個帶記憶體,能播放MP3的音箱,從此給她找評書便成了我的責任和義務。
      一開始開始還好,單先生說的書多,找起來不困難, 但隨著聽的越多,加上聽慣了單先生的,其他人的母親都不喜歡,即便單先生的,類似白眉大俠、童林傳等武俠類的她也不愛聽(本人也不是很喜歡,規律都差不多,自己被欺負了,找兄弟,再不行找師傅,還不行,找師祖,總之一句話你等著,我叫人去),後來實在找不到了,也慢慢的試著聽孫一,張少佐等其他人的了。
      電驢被封後,而能打包下載mp3的網站越來越少,想找點評書著實讓人撓頭。                一次偶然的機會,發現聽中國裡面的評書比較全,但是沒法批量下載,於是就有了本文,寫一款打包下載MP3的軟體,軟體下載地址
     隨著智能機的普及,母親已經使用手機聽評書了,所以本文僅供學習交流,請勿用於商業及非法用途。
二、所需技能及工具      想要實現批量下載需要三樣利器。     1、Visual Studio,傳說中的編程界的九陽神功,我現在一般是2010和2015交替使用。
    2、正則表達式,童子功,打好基礎開發速度事半功倍。     3、IE10以上、Edge 、Chrome等瀏覽器,相當於慕容世家的絕學鬥轉星移。
三、要實現的功能
    1、搜索評書或其他有聲讀物。     2、下載評書。
四、實戰開始
    軟體實現搜索功能很簡單,大體上三步即可
    1)、模擬瀏覽器向網站提交查詢 ,獲取返回的結果 。     2)、分析結果,寫出對應的正則表達式,生成結果的記錄集 。     3)、將記錄集呈現在窗體上。
    1、首先讓我們看看tingChina的查詢頁面什麼樣?    
    2、選中評書,選擇在演播中搜索,輸入單田芳,點擊搜索資源,結果頁面如下
       咱們分析一下鏈接地址,mainlei從名稱看,應該是指有聲小說、評書、相聲、戲曲、兒歌、人文、笑話,查詢界面第一行的搜索分類。我選的是評書,而mainlei=1,那有以此類推一下,有聲讀物對應的是0,相聲對應的是2,具體的試一下就能簡單的驗證。
       而lei應該就是查詢界面中的那個下拉框,一共有標題、演播、作者三個選項,而我選的是演播,而lei=1,同樣以此類推,標題應該就是0,作者則是2。
   3、分析完鏈接地址,接下來咱們分析頁面的代碼,筆者習慣使用IE瀏覽器,所以直接在查詢結果頁面按F12,然後按圖中的提示操作即可。
       按照圖中的提示,能提取一段html代碼,當然,如果你對html非常熟悉,直接查看源代碼找到這段代碼也行。        這時,大家要註意三個問題。          1、有的li元素包含style="background-color:#F3F3F3;"這段代碼,有的不包含。          2、有的a標簽包含style="color:blue;"這段代碼,有的則不含。          3、根據mainlei的不同,結果中鏈接地址也有些區別,比如評書就是<a href="pingshu/disp_1209.htm">,而有聲讀物則是<a href="yousheng/disp_27623.htm">,註意粗體的部分。
       這種情況正則表達式怎麼寫呢,對於前兩種情況,這裡我用了一種簡單粗暴的方法,就是把這兩段內容統一替換掉,這樣就能簡化正則表達式了。        最終的正則表達式:<li><a href=""(?<mainlei>[\w]*)/disp_(?<Number>[\d]*).htm""\s*>(?<Title>[\s\S]{1,20}?)</a>\([\d]*\)</li>
    4、軟體搜索的最終界面如下:  
   5、主要代碼如下:    C# Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  private void frmSearch_Load(object sender, EventArgs e)
{
    List<DictionaryEntry> list = 
new List<DictionaryEntry>();
    list.Add(
new DictionaryEntry("0","標題"));
    list.Add(
new DictionaryEntry("1","演播"));
    list.Add(
new DictionaryEntry("2","作者"));

    
this.cmb_lei.DisplayMember = "Value";
    
this.cmb_lei.ValueMember = "Key";
    
this.cmb_lei.DataSource = list;

    
//this.cmb_lei.SelectedValue = "1";
}

//http非同步請求的回調函數
public void ResponseCallBack(IAsyncResult result)
{

    
string Html = "";
    HttpWebRequest req = (HttpWebRequest)result.AsyncState;
    
try
    {
        
using (HttpWebResponse response = (HttpWebResponse)req.EndGetResponse(result))
        {
            Stream resStream = response.GetResponseStream();
            StreamReader sr = 
new StreamReader(resStream, Encoding.GetEncoding("GB2312"));
            Html = sr.ReadToEnd();
        }
    }
    
catch(Exception ex) {
        
if (IsDisposed || !this.IsHandleCreated) return;
        
this.Invoke(new Action(() =>
        {
            MessageBox.Show(
"查詢時出現異常,原因:" + ex.Message);
        }));
        
return;
    }

    
//替換掉干擾代碼
    Html = Html.Replace(@" style=""background-color:#F3F3F3;""""").Replace(@" style=""color:blue;""""");

    
//動態生成Label的字體
    Font font = new Font("微軟雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));

    
//正則表達式分析網頁,查找查詢結果
    MatchCollection ms = Regex.Matches(Html, @"<li><a href=""(?<mainlei>[\w]*)/disp_(?<Number>[\d]*).htm""\s*>(?<Title>[\s\S]{1,20}?)</a>\([\d]*\)</li>", RegexOptions.IgnoreCase | RegexOptions.Multiline);
    
if (ms.Count > 0)
    {
        
//最大寬度
        int MaxWidth = 0;
        Dictionary<
stringstring> list = new Dictionary<stringstring>();
        
foreach (Match m in ms)
        {
            list.Add(
string.Format("http://www.tingchina.com/{0}/disp_{1}.htm", m.Groups["mainlei"].Value, m.Groups["Number"].Value), m.Groups["Title"].Value);

            
//獲取字體的大小,找到最寬的那個條記錄
            Size size = TextRenderer.MeasureText(m.Groups["Title"].Value, font);
            
if (size.Width > MaxWidth)
            {
                MaxWidth = size.Width;
            }
        }

        
if (IsDisposed || !this.IsHandleCreated) return;
        
this.Invoke(new Action(() =>
        {
            
//對結果進行排序
            Dictionary<stringstring> listAsc = list.OrderBy(o => o.Value).ToDictionary(o => o.Key, p => p.Value);

            
//迴圈動態生成查詢結果.
            foreach (KeyValuePair<stringstring> kvp in listAsc)
            {
                Label lbl = 
new Label();
                lbl.Text = kvp.Value;
                lbl.Tag = kvp.Key;
                lbl.Cursor = System.Windows.Forms.Cursors.Hand;
                lbl.Margin = 
new System.Windows.Forms.Padding(50510);
                lbl.ForeColor = System.Drawing.Color.FromArgb(((
int)(((byte)(0)))), ((int)(((byte)(192)))), ((int)(((byte)(0)))));
                lbl.Font = font;
                lbl.Width = MaxWidth;
                lbl.Click += 
new EventHandler(lbl_Click);
                
this.fpnl_Content.Controls.Add(lbl);
            }
        }));
    }
    
else
    {
        
if (IsDisposed || !this.IsHandleCreated) return;
        
this.Invoke(new Action(() =>
        {
            MessageBox.Show(
"沒有查找到數據,請更換關鍵詞。");
        }));
    }
}

private void btn_Search_Click(object sender, EventArgs e)
{
    
if (this.txt_key.Text.Trim() == "")
    {
        MessageBox.Show(
"請輸入查詢關鍵字.");
        
return;
    }

    
//迴圈獲得分類編號
    string mainlei = "0";
    
foreach (Control c in this.pnl_Search.Controls)
    {
        
if (c.GetType().Equals(typeof(RadioButton)) && ((RadioButton)c).Checked)
        {
            mainlei = c.Name.Replace(
"rdo_mainlei""");
            
break;
        }
    }

    
//發送非同步請求,根據關鍵字查詢
    string Url = string.Format("http://www.tingchina.com/search1.asp?mainlei={0}&lei={1}&keyword={2}"
        mainlei, 
        
this.cmb_lei.SelectedValue, 
        HttpUtility.UrlEncode(
this.txt_key.Text.Trim(),Encoding.GetEncoding("GB2312")));

    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(Url);
    request.Method = 
"GET";
    request.BeginGetResponse(
new AsyncCallback(ResponseCallBack), request);
    
this.fpnl_Content.Controls.Clear();
}

private void lbl_Click(object sender, EventArgs e)
{
    
//點擊一個有聲讀物,進入其詳細視窗
    //待補充
}

本想一篇文章介紹完,發現內容還真不少(也可能是我寫的啰嗦,見諒),於是改成上下篇吧,會儘快推出下一篇。
未完待續...
 
作者:相信的勇氣 出處:http://www.newrain.cn/article/detail/15 本文為博主原創文章,歡迎轉載分享但請註明出處及鏈接,否則將其追究法律責! 勤奮的男人和愛笑的女人,運氣一般都不會太差。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Nginx最大特點: 靜態小文件(1M),支持高併發,同時占用系統資源很少。3W併發,10個進程,記憶體150M。 Nginx特點: 1、配置簡單,靈活,輕量。 2、高併發(靜態小文件),靜態幾萬的併發。 3、占用資源少。2W併發 開10個線程服務,記憶體消耗幾百M。 4、功能種類較多(Web,cach
  • 一、作用 文件/etc/apt/sources.list是一個普通可編輯的文本文件,保存了ubuntu軟體更新的源伺服器的地址。和sources.list功能一樣的是/etc/apt/sources.list.d/*.list(*代表一個文件名,只能由字母、數字、下劃線、英文句號組成)。source
  • Application Request Route(文中簡稱為ARR)是一個寄宿於 IIS7(及以後的IIS 版本)的一個基於代理的模塊,它可以通過判斷 Http Headers,Server Variables 以及負載均衡演算法將 HTTP 的請求轉發到不同的處理伺服器之上。ARR依賴URL Re...
  • 1、C#常量數據類型只能是原始數據類型:int、bool、char、double、string等。 2、C#中用訪問修飾符來說明變數的可訪問性,其值可以是:private、protected、internal、protected internal和public。 public:訪問不受限制,在任意地
  •    眾所周知,如果一個類可以被枚舉,那麼這個類必須要實現IEnumerable介面,而恰恰我們所有的linq都是一個繼承自IEnumerable介面的匿名類, 那麼問題就來了,IEnumerable使了何等神通讓這些集合類型可以被自由的枚舉???   一: 探索IEnumerable 首先我們看看
  • 我們可以通過代碼和配置文件的方式完成所有的服務寄宿工作。在Hosting項目中的Program.cs文件中的Main方法中,通過代碼實現對 BookService的WCF服務應用的寄宿實現。
  • 葡萄城近日與微軟公司達成合作,將Wijmo 產品線的HTML5和JaveScript 控制項融合到微軟Dynamics CRMOnline 2016版中
  • 以前知道一種解析json串的方法,覺得有點麻煩。就從別的地方搜到了另一種 string json = vlt.getlist(); JObject jo = JObject.Parse(json); var data = jo.getValue("data").ToObject<T>(); T就是對
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...