抓数据小程序
为了拓展公司业务,客服部需要大量相关行业的客户资料。由于公司规模不大,从成本上考虑够买数据不太现实,所以我们就开发了一套方案,从行业相关的商业网站上去抓取客户资料。
鉴于不同的网站在数据排版、字符编码、获取数据方式(get或post)不同。如要抓到自己想要的数据,针对每个网站都需要进行网页的分析,有效数据的提取。在这里主要分享关键代码,顺便把最近写的一个程序源代码贴出来供园友们下载研究,里面有抓取三个网站数据的例子( 深市A股、三星手机、当当网微软技术丛书,抓取不同的网站需要修改运行入口 )。 掌握其中一个的技巧,便可以在所有类似网站上获取你想要的数据,比方你在炒股,你可以抓取股票网站数据到本地,做个报表分析,操作的好,能让你赚的盆满钵满;假若你自己有个淘宝网店,需要商品图片,copy别人店铺的图片多慢啊,抓取便是;如果你有博客或新闻网站,没有更新的数据怎么办,看中哪个网站抓取便是。 说了这么多,回正题……
下面我以抓取其中一个网站为例来介绍这个小程序,首先抓取任务如下:
http://detail.zol测试数据.cn/cell_phone_index/subcate57_98_list_1.html
只要图片,手机名称,价格,网络模式,网络类型,其它信息不要
手机图片要下载下来
1.程序界面设计如下,只为达到抓取数据目的,界面比较鄙陋筒靴们将就看:-)。
2.用时信息通过Timer控件的tick事件来显示抓取用的时间,代码如下:
1 #region // 时间处理
2 int duration = 0 ;
3 private void timer1_Tick( object sender, EventArgs e)
4 {
5 duration++ ;
6 lbTime.Text = " 用时: " + GetTimeBySecount( int .Parse(duration.ToString().Trim()));
7 }
8 /// <summary>
9 /// 通过秒返回时:分:秒格式的时间
10 /// </summary>
11 /// <returns></returns>
12 private string GetTimeBySecount( int s)
13 {
14 s = s + 1 ;
15 TimeSpan timeSpan = new TimeSpan( 0 , 0 , s);
16 string hour = timeSpan.Hours < 10 ? timeSpan.Hours.ToString().Trim().PadLeft( 2 , ' 0 ' ) : timeSpan.Hours.ToString().Trim();
17 string minute = timeSpan.Minutes < 10 ? timeSpan.Minutes.ToString().Trim().PadLeft( 2 , ' 0 ' ) : timeSpan.Minutes.ToString().Trim();
18 string second = timeSpan.Seconds < 10 ? timeSpan.Seconds.ToString().Trim().PadLeft( 2 , ' 0 ' ) : timeSpan.Seconds.ToString().Trim();
19 return string .Format( " {0}:{1}:{2} " , hour, minute, second);
20 }
21 #endregion
3.进度信息用的是委托显示抓取详情,代码如下:
1 #region // 委托显示用户提示信息
2 /// <summary>
3 /// 为了进程之间通信,定义一个委托
4 /// </summary>
5 /// <param name="displayString"> 实时处理的信息 </param>
6 /// <param name="lbl"> 接收实时处理信息的 Label 对象 </param>
7 /// <param name="ui"> 承载 Label 控件的窗体对象 </param>
8 delegate void SetText( string displayString, Label lbl, Form ui);
9 /// <summary>
10 /// 利用委托操作窗体线程上的 Lable 控件
11 /// </summary>
12 /// <param name="str"> 实时处理的信息 </param>
13 /// <param name="lb"> 接收实时处理信息的 Label 对象 </param>
14 /// <param name="fui"> 承载 Label 控件的窗体对象 </param>
15 public static void SetLableText( string str, Label lb, Form fui)
16 {
17 if (lb.InvokeRequired)
18 {
19 SetText st = new SetText(SetLableText);
20 fui.Invoke(st, str, lb, fui);
21 }
22 else
23 {
24 lb.Text = str;
25 }
26 }
27 #endregion
4.拖放一个backgroundWorker控件,启动DoWork事件和RunWorkerCompleted事件。
Common.Get_HttpAll:根据网页地址,和字符编码获取网页源代码返回string
Common.ResolverAndOutput:从网页内容中获取关键信息,通常用于获取列表数据,table里面的tr数据。
参数1传入要分析的网页内容;
参数2传入要分析的网页内容的起始点,为空则表示从网页内容起始位置开始;
参数3传入要分析的网页内容的终结点,为空则表示截止到网页内容的最后位置;
参数4传入过滤规则,例如:<tr>(?<content>.+?)</tr>,表示获取参数2和参数3之间的字符串中所有<tr>开始,</tr>结束的所有字符串,这些字符串用$~拼接;
参数5默认传入1;
参数6默认传入false;
Common.JieQuString:截取字符串中A和B之间的数据。参数1传入带分析的字符串;参数2传入A(A在字符串中唯一);参数3传入B(B在字符串中唯一)):
1 private void backgroundWorker1_DoWork( object sender, DoWorkEventArgs e)
2 {
3 try
4 {
5 DataSet ds = new DataSet();
6 DataTable dtContact = new DataTable( " tbl " );
7 dtContact.Columns.Add( " name " );
8 dtContact.Columns.Add( " price " );
9 dtContact.Columns.Add( " fileName " );
10 dtContact.Columns.Add( " model " );
11 dtContact.Columns.Add( " type " );
12 DataRow dr;
13 int i = 1 ;
14 bool flag = true ;
15 do
16 {
17 string path = " http://detail.zol测试数据.cn/cell_phone_index/subcate57_98_list_ " + i.ToString() + " .html " ;
18 string getHtml = Common.Get_HttpAll (path, " GB2312 " );
19 if (!getHtml.Contains( " wrong " ))
20 {
21 string useHtml = Common.ResolverAndOutput (getHtml, "" , "" , " <div class=\"list-item clearfix\">(?<content>.+?)target=\"_blank\">查询底价</a> " , 1 , false );
22 string [] trItem = useHtml.Replace( " ~ " , "" ).Split( ' $ ' );
23 flag = trItem.Length > 2 ;
24 for ( int j = 0 ; j < trItem.Length - 1 ; j++ )
25 {
26 SetLableText( " 进度:当前正在分析第 " + i + " 页,第 " +(j+ 1 )+ " 条数据 " , lbJD, this );
27 dr = dtContact.NewRow();
28 string imgUrl = Common.JieQuString (trItem[j], " <div class=\"pic-box SP\" data-rel=\" " , " \"> " );
29 int splitIndex=imgUrl.LastIndexOf( ' / ' );
30 if (splitIndex < 0 ) {
31 break ;
32 }
33 string fileName= imgUrl.Substring(splitIndex, imgUrl.Length - splitIndex).Replace( " / " , "" );
34 // 下载当前产品图片
35 string filepath = " E:\\抓数据\\中关村三星手机图片\\ " + fileName;
36 WebClient mywebclient = new WebClient();
37 mywebclient.DownloadFile(imgUrl, filepath);
38 // 填充行值
39 dr[ " name " ] = Common.JieQuString(Common.JieQuString(trItem[j], " <h3> " , " </h3> " ), " > " , " </a> " );
40 dr[ " price " ] = Common.JieQuString(trItem[j], " <span class=\"price\">¥<b class=''> " , " </b></span> " );
41 dr[ " fileName " ] = fileName;
42 dr[ " model " ] = Common.JieQuString(trItem[j], " <span>网络模式:</span> " , " </li> " );
43 dr[ " type " ] = Common.JieQuString(trItem[j], " <span>网络类型:</span> " , " </li> " );
44 dtContact.Rows.Add(dr);
45 }
46 ds.Tables.Add(dtContact.Copy());
47 string savePath = " E:\\抓数据\\中关村三星手机.xml " ;
48 ds.WriteXml(savePath);
49 ds.Tables.Clear();
50 }
51 else
52 {
53 continue ;
54 }
55 i++ ;
56 } while (flag);
57 }
58 catch (Exception ex)
59 {
60 MessageBox.Show( " 代码异常: " + ex);
61 }
62 }
RunWorkerCompleted代码如下:
1 private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e)
2 {
3 timer1.Stop();
4 timer1.Enabled = false ;
5 MessageBox.Show( " ok,见 E:\\抓数据\\中关村三星手机.xml " );
6 }
5.点击窗体抓取数据启动Click事件,代码如下:
1 private void btnGetData_Click( object sender, EventArgs e)
2 {
3 timer1.Enabled = true ;
4 timer1.Start();
5 backgroundWorker1.RunWorkerAsync();
6 }
6.大功告成。启动程序效果如下:
7.运行完成后查看抓取的数据信息和手机图片如下(把Xml文件拖到Excel中显示):
总结:此例只是针对Get请求数据的情况,而且当前抓取的网站都是不需要登录的。而在实际生产中肯定有Post请求数据的,也有需要登录的,源码里面的Common类提供了各种场景需要的方法,有兴趣的可以深入研究。
源码下载
正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!
标签: 分享
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息