抓取分析网页批量下载评书(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)
{
    
//点击一个有声读物,进入其详细窗口
     //待补充
}

本想一篇文章介绍完,发现内容还真很多(也多是我写的啰嗦,见谅),因而改为三篇吧,会尽快推出下一篇。
未完待续...
 
做者: 相信的勇气
本文为博主原创文章,欢迎转载分享但请注明出处及连接,不然将其追究法律责!
勤奋的男人和爱笑的女人,运气通常都不会太差。
相关文章
相关标签/搜索