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

 
1、背景
      母親喜歡聽評書,跟着廣播天天一集總以爲不過癮,因而2010年給她買了一個帶內存,能播放MP3的音箱,今後給她找評書便成了個人責任和義務。

      一開始開始還好,單先生說的書多,找起來不困難, 但隨着聽的越多,加上聽慣了單先生的,其餘人的母親都不喜歡,即使單先生的,相似白眉大俠、童林傳等武俠類的她也不愛聽(本人也不是很喜歡,規律都差很少,本身被欺負了,找兄弟,再不行找師傅,還不行,找師祖,總之一句話你等着,我叫人去),後來實在找不到了,也慢慢的試着聽孫一,張少佐等其餘人的了。

      電驢被封后,而能打包下載mp3的網站愈來愈少,想找點評書着實讓人撓頭。
        
      一次偶然的機會,發現聽中國裏面的評書比較全,可是無法批量下載,因而就有了本文,寫一款打包下載MP3的軟件,軟件下載地址

     隨着智能機的普及,母親已經使用手機聽評書了,因此本文僅供學習交流,請勿用於商業及非法用途。

2、所需技能及工具
     想要實現批量下載須要三樣利器。
    一、Visual Studio,傳說中的編程界的九陽神功,我如今通常是2010和2015交替使用。
    二、正則表達式,童子功,打好基礎開發速度事半功倍。
    三、IE10以上、Edge 、Chrome等瀏覽器,至關於慕容世家的絕學 斗轉星移。

3、要實現的功能

    一、搜索評書或其餘有聲讀物。
    二、下載評書。

4、實戰開始

    軟件實現搜索功能很簡單,大致上三步便可

    1)、模擬瀏覽器向網站提交查詢 ,獲取返回的結果 。
    2)、分析結果,寫出對應的正則表達式,生成結果的記錄集 。
    3)、將記錄集呈如今窗體上。

    一、首先讓咱們看看tingChina的查詢頁面什麼樣?
   
    二、選中評書,選擇在演播中搜索,輸入單田芳,點擊搜索資源,結果頁面以下

       我們分析一下連接地址,mainlei從名稱看,應該是指有聲小說、評書、相聲、戲曲、兒歌、人文、笑話,查詢界面第一行的搜索分類。 我選的是評書,而mainlei=1,那有以此類推一下,有聲讀物對應的是0,相聲對應的是2,具體的試一下就能簡單的驗證。

       而lei應該就是查詢界面中的那個下拉框,一共有標題、演播、做者三個選項,而我選的是演播,而lei=1,一樣以此類推,標題應該就是0,做者則是2。

   三、分析完連接地址,接下來我們分析頁面的代碼,筆者習慣使用IE瀏覽器,因此直接在查詢結果頁面按F12,而後按圖中的提示操做便可。

       按照圖中的提示,能提取一段html代碼,固然,若是你對html很是熟悉,直接查看源代碼找到這段代碼也行。
       這時,你們要注意三個問題。
         一、有的 li元素包含 style="background-color:#F3F3F3;"這段代碼,有的不包含。
         二、有的 a標籤包含 style="color:blue;"這段代碼,有的則不含。
         三、根據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>

    四、軟件搜索的最終界面以下:
 

   五、主要代碼以下:
 
 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<
string string > list =  new  Dictionary< string string >();
        
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< string string > listAsc = list.OrderBy(o => o.Value).ToDictionary(o => o.Key, p => p.Value);

            
//循環動態生成查詢結果.
             foreach  (KeyValuePair< string string > 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( 5 0 5 10 );
                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)
{
    
//點擊一個有聲讀物,進入其詳細窗口
     //待補充
}

本想一篇文章介紹完,發現內容還真很多(也多是我寫的囉嗦,見諒),因而改爲三篇吧,會盡快推出下一篇。
未完待續...
 
做者: 相信的勇氣
本文爲博主原創文章,歡迎轉載分享但請註明出處及連接,不然將其追究法律責!
勤奮的男人和愛笑的女人,運氣通常都不會太差。
相關文章
相關標籤/搜索