51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 2716|回复: 5
打印 上一主题 下一主题

[讨论] Java爬虫,信息抓取的实现

[复制链接]
  • TA的每日心情
    擦汗
    2022-8-30 09:02
  • 签到天数: 2 天

    连续签到: 2 天

    [LV.1]测试小兵

    跳转到指定楼层
    1#
    发表于 2018-3-15 16:53:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    今天公司有个需求,需要做一些指定网站查询后的数据的抓取,于是花了点时间写了个demo供演示使用。

    思想很简单:就是通过Java访问的链接,然后拿到html字符串,然后就是解析链接等需要的数据。

    技术上使用Jsoup方便页面的解析,当然Jsoup很方便,也很简单,一行代码就能知道怎么用了:
    1. Document doc = Jsoup.connect("http://www.oschina.net/")   
    2. .data("query", "Java")   // 请求参数  
    3. .userAgent("I ’ m jsoup") // 设置 User-Agent   
    4. .cookie("auth", "token") // 设置 cookie   
    5. .timeout(3000)           // 设置连接超时时间  
    6. .post();  
    复制代码
    下面介绍整个实现过程:
    1、分析需要解析的页面:

    网址:http://www1.sxcredit.gov.cn/publ ... od=publicIndexQuery



    先在这个页面上做一次查询:观察下请求的url,参数,method等。

    这里我们使用chrome内置的开发者工具(快捷键F12),下面是查询的结果:

    我们可以看到url,method,以及参数。知道了如何或者查询的URL,下面就开始代码了,为了重用与
    扩展,我定义了几个类:

    1、Rule.java用于指定查询url,method,params等
    1. package com.zhy.spider.rule;  
    2.   
    3. /**
    4. * 规则类
    5. *  
    6. * [url=home.php?mod=space&uid=267564]@Author[/url] zhy
    7. *  
    8. */  
    9. public class Rule  
    10. {  
    11.     /**
    12.      * 链接
    13.      */  
    14.     private String url;  
    15.   
    16.     /**
    17.      * 参数集合
    18.      */  
    19.     private String[] params;  
    20.     /**
    21.      * 参数对应的值
    22.      */  
    23.     private String[] values;  
    24.   
    25.     /**
    26.      * 对返回的HTML,第一次过滤所用的标签,请先设置type
    27.      */  
    28.     private String resultTagName;  
    29.   
    30.     /**
    31.      * CLASS / ID / SELECTION
    32.      * 设置resultTagName的类型,默认为ID  
    33.      */  
    34.     private int type = ID ;  
    35.       
    36.     /**
    37.      *GET / POST
    38.      * 请求的类型,默认GET
    39.      */  
    40.     private int requestMoethod = GET ;   
    41.       
    42.     public final static int GET = 0 ;  
    43.     public final static int POST = 1 ;  
    44.       
    45.   
    46.     public final static int CLASS = 0;  
    47.     public final static int ID = 1;  
    48.     public final static int SELECTION = 2;  
    49.   
    50.     public Rule()  
    51.     {  
    52.     }  
    53.   
    54.       
    55.     public Rule(String url, String[] params, String[] values,  
    56.             String resultTagName, int type, int requestMoethod)  
    57.     {  
    58.         super();  
    59.         this.url = url;  
    60.         this.params = params;  
    61.         this.values = values;  
    62.         this.resultTagName = resultTagName;  
    63.         this.type = type;  
    64.         this.requestMoethod = requestMoethod;  
    65.     }  
    66.   
    67.     public String getUrl()  
    68.     {  
    69.         return url;  
    70.     }  
    71.   
    72.     public void setUrl(String url)  
    73.     {  
    74.         this.url = url;  
    75.     }  
    76.   
    77.     public String[] getParams()  
    78.     {  
    79.         return params;  
    80.     }  
    81.   
    82.     public void setParams(String[] params)  
    83.     {  
    84.         this.params = params;  
    85.     }  
    86.   
    87.     public String[] getValues()  
    88.     {  
    89.         return values;  
    90.     }  
    91.   
    92.     public void setValues(String[] values)  
    93.     {  
    94.         this.values = values;  
    95.     }  
    96.   
    97.     public String getResultTagName()  
    98.     {  
    99.         return resultTagName;  
    100.     }  
    101.   
    102.     public void setResultTagName(String resultTagName)  
    103.     {  
    104.         this.resultTagName = resultTagName;  
    105.     }  
    106.   
    107.     public int getType()  
    108.     {  
    109.         return type;  
    110.     }  
    111.   
    112.     public void setType(int type)  
    113.     {  
    114.         this.type = type;  
    115.     }  
    116.   
    117.     public int getRequestMoethod()  
    118.     {  
    119.         return requestMoethod;  
    120.     }  
    121.   
    122.     public void setRequestMoethod(int requestMoethod)  
    123.     {  
    124.         this.requestMoethod = requestMoethod;  
    125.     }  
    126.   
    127. }  
    复制代码
    简单说一下:这个规则类定义了我们查询过程中需要的所有信息,方便我们的扩展,以及代码的重用,
    我们不可能针对每个需要抓取的网站写一套代码。


    2、需要的数据对象,目前只需要链接,LinkTypeData.java
    1. package com.zhy.spider.bean;  
    2.   
    3. public class LinkTypeData  
    4. {  
    5.     private int id;  
    6.     /**
    7.      * 链接的地址
    8.      */  
    9.     private String linkHref;  
    10.     /**
    11.      * 链接的标题
    12.      */  
    13.     private String linkText;  
    14.     /**
    15.      * 摘要
    16.      */  
    17.     private String summary;  
    18.     /**
    19.      * 内容
    20.      */  
    21.     private String content;  
    22.     public int getId()  
    23.     {  
    24.         return id;  
    25.     }  
    26.     public void setId(int id)  
    27.     {  
    28.         this.id = id;  
    29.     }  
    30.     public String getLinkHref()  
    31.     {  
    32.         return linkHref;  
    33.     }  
    34.     public void setLinkHref(String linkHref)  
    35.     {  
    36.         this.linkHref = linkHref;  
    37.     }  
    38.     public String getLinkText()  
    39.     {  
    40.         return linkText;  
    41.     }  
    42.     public void setLinkText(String linkText)  
    43.     {  
    44.         this.linkText = linkText;  
    45.     }  
    46.     public String getSummary()  
    47.     {  
    48.         return summary;  
    49.     }  
    50.     public void setSummary(String summary)  
    51.     {  
    52.         this.summary = summary;  
    53.     }  
    54.     public String getContent()  
    55.     {  
    56.         return content;  
    57.     }  
    58.     public void setContent(String content)  
    59.     {  
    60.         this.content = content;  
    61.     }  
    62. }  

    63. 3、核心的查询类:ExtractService.java
    64. [java] view plain copy
    65. package com.zhy.spider.core;  
    66.   
    67. import java.io.IOException;  
    68. import java.util.ArrayList;  
    69. import java.util.List;  
    70. import java.util.Map;  
    71.   
    72. import javax.swing.plaf.TextUI;  
    73.   
    74. import org.jsoup.Connection;  
    75. import org.jsoup.Jsoup;  
    76. import org.jsoup.nodes.Document;  
    77. import org.jsoup.nodes.Element;  
    78. import org.jsoup.select.Elements;  
    79.   
    80. import com.zhy.spider.bean.LinkTypeData;  
    81. import com.zhy.spider.rule.Rule;  
    82. import com.zhy.spider.rule.RuleException;  
    83. import com.zhy.spider.util.TextUtil;  
    84.   
    85. /**
    86. *  
    87. * @author zhy
    88. *  
    89. */  
    90. public class ExtractService  
    91. {  
    92.     /**
    93.      * @param rule
    94.      * [url=home.php?mod=space&uid=26358]@return[/url]
    95.      */  
    96.     public static List<LinkTypeData> extract(Rule rule)  
    97.     {  
    98.   
    99.         // 进行对rule的必要校验  
    100.         validateRule(rule);  
    101.   
    102.         List<LinkTypeData> datas = new ArrayList<LinkTypeData>();  
    103.         LinkTypeData data = null;  
    104.         try  
    105.         {  
    106.             /**
    107.              * 解析rule
    108.              */  
    109.             String url = rule.getUrl();  
    110.             String[] params = rule.getParams();  
    111.             String[] values = rule.getValues();  
    112.             String resultTagName = rule.getResultTagName();  
    113.             int type = rule.getType();  
    114.             int requestType = rule.getRequestMoethod();  
    115.   
    116.             Connection conn = Jsoup.connect(url);  
    117.             // 设置查询参数  
    118.   
    119.             if (params != null)  
    120.             {  
    121.                 for (int i = 0; i < params.length; i++)  
    122.                 {  
    123.                     conn.data(params[i], values[i]);  
    124.                 }  
    125.             }  
    126.   
    127.             // 设置请求类型  
    128.             Document doc = null;  
    129.             switch (requestType)  
    130.             {  
    131.             case Rule.GET:  
    132.                 doc = conn.timeout(100000).get();  
    133.                 break;  
    134.             case Rule.POST:  
    135.                 doc = conn.timeout(100000).post();  
    136.                 break;  
    137.             }  
    138.   
    139.             //处理返回数据  
    140.             Elements results = new Elements();  
    141.             switch (type)  
    142.             {  
    143.             case Rule.CLASS:  
    144.                 results = doc.getElementsByClass(resultTagName);  
    145.                 break;  
    146.             case Rule.ID:  
    147.                 Element result = doc.getElementById(resultTagName);  
    148.                 results.add(result);  
    149.                 break;  
    150.             case Rule.SELECTION:  
    151.                 results = doc.select(resultTagName);  
    152.                 break;  
    153.             default:  
    154.                 //当resultTagName为空时默认去body标签  
    155.                 if (TextUtil.isEmpty(resultTagName))  
    156.                 {  
    157.                     results = doc.getElementsByTag("body");  
    158.                 }  
    159.             }  
    160.   
    161.             for (Element result : results)  
    162.             {  
    163.                 Elements links = result.getElementsByTag("a");  
    164.   
    165.                 for (Element link : links)  
    166.                 {  
    167.                     //必要的筛选  
    168.                     String linkHref = link.attr("href");  
    169.                     String linkText = link.text();  
    170.   
    171.                     data = new LinkTypeData();  
    172.                     data.setLinkHref(linkHref);  
    173.                     data.setLinkText(linkText);  
    174.   
    175.                     datas.add(data);  
    176.                 }  
    177.             }  
    178.   
    179.         } catch (IOException e)  
    180.         {  
    181.             e.printStackTrace();  
    182.         }  
    183.   
    184.         return datas;  
    185.     }  
    186.   
    187.     /**
    188.      * 对传入的参数进行必要的校验
    189.      */  
    190.     private static void validateRule(Rule rule)  
    191.     {  
    192.         String url = rule.getUrl();  
    193.         if (TextUtil.isEmpty(url))  
    194.         {  
    195.             throw new RuleException("url不能为空!");  
    196.         }  
    197.         if (!url.startsWith("http://"))  
    198.         {  
    199.             throw new RuleException("url的格式不正确!");  
    200.         }  
    201.   
    202.         if (rule.getParams() != null && rule.getValues() != null)  
    203.         {  
    204.             if (rule.getParams().length != rule.getValues().length)  
    205.             {  
    206.                 throw new RuleException("参数的键值对个数不匹配!");  
    207.             }  
    208.         }  
    209.   
    210.     }  
    211.   
    212.   
    213. }  

    复制代码

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2022-8-30 09:02
  • 签到天数: 2 天

    连续签到: 2 天

    [LV.1]测试小兵

    2#
     楼主| 发表于 2018-3-15 16:54:26 | 只看该作者
    1. 4、里面用了一个异常类:RuleException.java
    2. [java] view plain copy
    3. package com.zhy.spider.rule;

    4. public class RuleException extends RuntimeException
    5. {

    6. public RuleException()
    7. {
    8. super();
    9. // TODO Auto-generated constructor stub
    10. }

    11. public RuleException(String message, Throwable cause)
    12. {
    13. super(message, cause);
    14. // TODO Auto-generated constructor stub
    15. }

    16. public RuleException(String message)
    17. {
    18. super(message);
    19. // TODO Auto-generated constructor stub
    20. }

    21. public RuleException(Throwable cause)
    22. {
    23. super(cause);
    24. // TODO Auto-generated constructor stub
    25. }

    26. }

    27. 5、最后是测试了:这里使用了两个网站进行测试,采用了不同的规则,具体看代码吧
    28. [java] view plain copy
    29. package com.zhy.spider.test;

    30. import java.util.List;

    31. import com.zhy.spider.bean.LinkTypeData;
    32. import com.zhy.spider.core.ExtractService;
    33. import com.zhy.spider.rule.Rule;

    34. public class Test
    35. {
    36. @org.junit.Test
    37. public void getDatasByClass()
    38. {
    39. Rule rule = new Rule(
    40. "http://www1.sxcredit.gov.cn/public/infocomquery.do?method=publicIndexQuery",
    41. new String[] { "query.enterprisename","query.registationnumber" }, new String[] { "兴网","" },
    42. "cont_right", Rule.CLASS, Rule.POST);
    43. List<LinkTypeData> extracts = ExtractService.extract(rule);
    44. printf(extracts);
    45. }

    46. @org.junit.Test
    47. public void getDatasByCssQuery()
    48. {
    49. Rule rule = new Rule("http://www.11315.com/search",
    50. new String[] { "name" }, new String[] { "兴网" },
    51. "div.g-mn div.con-model", Rule.SELECTION, Rule.GET);
    52. List<LinkTypeData> extracts = ExtractService.extract(rule);
    53. printf(extracts);
    54. }

    55. public void printf(List<LinkTypeData> datas)
    56. {
    57. for (LinkTypeData data : datas)
    58. {
    59. System.out.println(data.getLinkText());
    60. System.out.println(data.getLinkHref());
    61. System.out.println("***********************************");
    62. }

    63. }
    64. }
    复制代码
    [java] view plain copy
    深圳市网兴科技有限公司  
    http://14603257.11315.com  
    ***********************************  
    荆州市兴网公路物资有限公司  
    http://05155980.11315.com  
    ***********************************  
    西安市全兴网吧  
    #  
    ***********************************  
    子长县新兴网城  
    #  
    ***********************************  
    陕西同兴网络信息有限责任公司第三分公司  
    #  
    ***********************************  
    西安高兴网络科技有限公司  
    #  
    ***********************************  
    陕西同兴网络信息有限责任公司西安分公司  
    #  
    ***********************************  

    最后使用一个Baidu新闻来测试我们的代码:说明我们的代码是通用的。
    [java] view plain copy
            /**
    * 使用百度新闻,只设置url和关键字与返回类型
    */  
    @org.junit.Test  
    public void getDatasByCssQueryUserBaidu()  
    {  
        Rule rule = new Rule("http://news.baidu.com/ns",  
                new String[] { "word" }, new String[] { "支付宝" },  
                null, -1, Rule.GET);  
        List<LinkTypeData> extracts = ExtractService.extract(rule);  
        printf(extracts);  
    }  
    我们只设置了链接、关键字、和请求类型,不设置具体的筛选条件。
    结果:有一定的垃圾数据是肯定的,但是需要的数据肯定也抓取出来了。我们可以设置Rule.SECTION,以及筛选条件进一步的限制。

    [html] view plain copy
    按时间排序  
    /ns?word=支付宝&ie=utf-8&bs=支付宝&sr=0&cl=2&rn=20&tn=news&ct=0&clk=sortbytime  
    ***********************************  
    x  
    javascript:void(0)  
    ***********************************  
    支付宝将联合多方共建安全基金 首批投入4000万  
    http://finance.ifeng.com/a/20140409/12081871_0.shtml  
    ***********************************  
    7条相同新闻  


    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-9-20 15:38 , Processed in 0.073556 second(s), 24 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表