zoukankan      html  css  js  c++  java
  • 抓数据小程序

     为了拓展公司业务,客服部需要大量相关行业的客户资料。由于公司规模不大,从成本上考虑够买数据不太现实,所以我们就开发了一套方案,从行业相关的商业网站上去抓取客户资料。

       鉴于不同的网站在数据排版、字符编码、获取数据方式(get或post)不同。如要抓到自己想要的数据,针对每个网站都需要进行网页的分析,有效数据的提取。在这里主要分享关键代码,顺便把最近写的一个程序源代码贴出来供园友们下载研究,里面有抓取三个网站数据的例子(深市A股、三星手机、当当网微软技术丛书,抓取不同的网站需要修改运行入口)。掌握其中一个的技巧,便可以在所有类似网站上获取你想要的数据,比方你在炒股,你可以抓取股票网站数据到本地,做个报表分析,操作的好,能让你赚的盆满钵满;假若你自己有个淘宝网店,需要商品图片,copy别人店铺的图片多慢啊,抓取便是;如果你有博客或新闻网站,没有更新的数据怎么办,看中哪个网站抓取便是。说了这么多,回正题……

    下面我以抓取其中一个网站为例来介绍这个小程序,首先抓取任务如下:

    http://detail.zol.com.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事件。

    • DoWork代码如下(代码中标红的方法是几个关键的方法
      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.com.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类提供了各种场景需要的方法,有兴趣的可以深入研究。

    源码下载

    正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!

     
     
     
    标签: 分享
  • 相关阅读:
    liunx定时任务执行
    spark-stream简单使用案例
    spark的UDF操作,RDD与DataFrame转换,RDD DataFrame DataSet的分析
    uni-app:text文本组件是行内元素,如何让标题居中显示?
    报错:java.math.BigDecimal cannot be cast to java.lang.String(oracle数据库中的number类型数据,java查询出来的对象属性数据类型其实为BigDecimal)
    uni-app封装请求方法
    in和exists比较
    人写的SQL与机读SQL的顺序
    spring cloud组件之Feign:Feign内置的Ribbon把Rest的请求进行隐藏并基于某种负载均衡算法自动发起请求,而Feign伪装成类似Controller一样来拼接url
    spring cloud组件之Hystrixi:通过服务降级即返回一个结果来隔离访问远程服务,防止出现级联失败
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2852863.html
Copyright © 2011-2022 走看看