现在的位置: 首页 > 综合 > 正文

新浪微博搜索结果数据抓取

2014年09月05日 ⁄ 综合 ⁄ 共 8971字 ⁄ 字号 评论关闭

这篇文章抓取使用的是jsoup,要求简单的情况下比起httpclient确实方便的多。有启示性但对我的需求来说不太适用,比如没有登陆。

项目需要在抓取新浪微博搜索结果数据,顺手做了个工具,以实现在新浪微博搜索中自动抓取配置的关键字的搜索结果。在此分享一下。

先看一下新浪微博搜索结果页面的源码:

可以看到,得到的并不是普通html,都是通过js调用的。其中汉字全部是经过编码的。文本元素全部都是上图红框中的格式,要得到搜索结果就需要对红框中的文本进行解析。其中用到了jsoup 和 fastjson jar包,需要自行下载。

jsoup: http://jsoup.org/download

fastjson:http://sourceforge.net/projects/fastjson

搜索结果抓取核心类:

  1. import java.io.IOException; 
  2. import java.text.ParseException; 
  3. import java.util.ArrayList; 
  4. import java.util.Date; 
  5. import java.util.List; 
  6. import java.util.regex.Matcher; 
  7. import java.util.regex.Pattern; 
  8.  
  9. import org.apache.solr.common.SolrInputDocument; 
  10. import org.jsoup.Jsoup; 
  11. import org.jsoup.nodes.Document; 
  12. import org.jsoup.nodes.Element; 
  13. import org.jsoup.safety.Whitelist; 
  14. import org.jsoup.select.Elements; 
  15.  
  16. import com.alibaba.fastjson.JSON; 
  17.  
  18. public class WeiboFetcher extends AbstractFetcher { 
  19.      
  20.     // 文本块正文匹配正则 
  21.     private final String blockRegex = "<script>STK\\s&&\\sSTK\\.pageletM\\s&&\\sSTK\\.pageletM\\.view\\(.*\\)"
  22.     private Pattern pattern = Pattern.compile(blockRegex); 
  23.     private static Whitelist whitelist = new Whitelist(); 
  24.      
  25.     static
  26.         // 只保留em标签的文本 
  27.         whitelist.addTags("em"); 
  28.     } 
  29.      
  30.     @Override() 
  31.     public List<SolrInputDocument> fetch() { 
  32.  
  33.         List<SolrInputDocument> newsResults = new ArrayList<SolrInputDocument>(); 
  34.          
  35.         newsResults = WeiboResult(); 
  36.  
  37.         System.out.println("WeiboFetcher Over: " + newsResults.size()); 
  38.  
  39.         return newsResults; 
  40.          
  41.     } 
  42.  
  43.  
  44.     /** 
  45.      * 获取关键字搜索结果 
  46.      * @return 
  47.      */ 
  48.     private List<SolrInputDocument> WeiboResult() { 
  49.  
  50.         String keyWord = null
  51.         List<SolrInputDocument> newsResultList = new ArrayList<SolrInputDocument>(); 
  52.          
  53.         // 获取配置的关键字 
  54.         List<String> keyWordList = KeywordReader.getInstance().getKeywords(); 
  55.              
  56.         for (String keyWordLine : keyWordList) { 
  57.              
  58.             // 转换为新浪微博搜索接受的格式 
  59.             keyWord = policy.getKeyWord(keyWordLine,null); 
  60.  
  61.             newsResultList.addAll(getWeiboContent(keyWord)); 
  62.         } 
  63.              
  64.         return newsResultList; 
  65.     } 
  66.      
  67.     /** 
  68.      * 获取搜索结果 
  69.      * @param keyWord 
  70.      * @return 
  71.      */ 
  72.     private List<SolrInputDocument> getWeiboContent(String keyWord){ 
  73.          
  74.         System.out.println("fetch keyword: " + keyWord); 
  75.          
  76.         List<SolrInputDocument> resultList = new ArrayList<SolrInputDocument>(); 
  77.          
  78.         for(int i = 0; i < depth; i++){ 
  79.              
  80.             String page = ""
  81.              
  82.             if(i > 0){ 
  83.                 page = "&page=" + (i+1); 
  84.             } 
  85.              
  86.             //抓取返回50个内容  
  87.             try { 
  88.                  
  89.                 System.out.println("fetch url page depth " + (i + 1)); 
  90.                  
  91.                 // 注意&nodup=1 
  92.                 Document doc = Jsoup.connect( 
  93.                         "http://s.weibo.com/weibo/" + keyWord+"&nodup=1" + page).get(); 
  94.                  
  95.                 String source = doc.html(); 
  96.                  
  97.                 // 匹配文本块 
  98.                 Matcher m = pattern.matcher(source); 
  99.                  
  100.                 while(m.find()){ 
  101.                      
  102.                     String jsonStr = m.group(); 
  103.                      
  104.                     jsonStr = jsonStr.substring(jsonStr.indexOf("{"), jsonStr.lastIndexOf(")")); 
  105.                      
  106.                     // 解析json,转换为实体类 
  107.                     WeiboBlock block = JSON.parseObject(jsonStr, WeiboBlock.class); 
  108.                      
  109.                     if(block.getHtml().trim().startsWith("<div class=\"search_feed\">")){ 
  110.                          
  111.                         doc = Jsoup.parse(block.getHtml()); 
  112.                     } 
  113.                 } 
  114.                  
  115.                  
  116.                  
  117.                 List<Element> elements = getAllElement(doc); 
  118.                  
  119.                 if(elements == null || elements.size() == 0){ 
  120.                      
  121.                     System.out.println("No more urls to fetch with current keyword." ); 
  122.                     return resultList; 
  123.                      
  124.                 } 
  125.                  
  126.                 for (Element elem : elements) { 
  127.  
  128.                     String url = elem.select(".date").last().attr("href"); 
  129.                     String dateS = elem.select(".date").last().attr("date"); 
  130.                     String content = null
  131.                     Date date = null
  132.                     String content_text = null
  133.                     String title = null
  134.                      
  135.                     if (!isCrawledUrl(url)){ 
  136.                          
  137.                         if (url != null) { 
  138.                              
  139.                             if (dateS != null && !"".equals(dateS)) { 
  140.                                 try { 
  141.                                     date = sdf.parse(changeString2Date(dateS)); 
  142.                                 } catch (ParseException e) { 
  143.                                     e.printStackTrace(); 
  144.                                 } 
  145.                             } 
  146.                              
  147.                             if (date != null) { 
  148.                                  
  149.                                 elem.getElementsByClass("info W_linkb W_textb").remove(); 
  150.                                 content = Jsoup.clean(Jsoup.clean(elem.select(".content").html(), whitelist), Whitelist.none()); 
  151.                                 title = this.parseTitle(content); 
  152.                          
  153.                                 url = elem.select(".date").last().attr("href"); 
  154.  
  155.                                 SolrInputDocument sid = buildSolrInputDocumentList(url, content, title, date); 
  156.                                 if (sid != null && sid.size() > 0) { 
  157.                                     resultList.add(sid); 
  158.                                 } 
  159.                             } 
  160.                         }else { 
  161.                             System.out.println("current Url: ---------null------------" ); 
  162.                         } 
  163.                     } 
  164.                 } 
  165.                  
  166.             } catch (IOException e) { 
  167.                 e.printStackTrace(); 
  168.             } 
  169.              
  170.         } 
  171.          
  172.         return resultList; 
  173.     } 
  174.      
  175.     /** 
  176.      * 获取所有的结果正文节点 
  177.      * @param doc 
  178.      * @return 
  179.      */ 
  180.     private List<Element> getAllElement(Document doc) { 
  181.  
  182.         List<Element> resultList = new ArrayList<Element>(); 
  183.          
  184.         Elements elems = doc.select(".search_feed .feed_list"); 
  185.          
  186.         for (Element element : elems) { 
  187.             resultList.add(element); 
  188.         } 
  189.          
  190.         return resultList; 
  191.     } 
  192.      
  193.      
  194.      
  195.     @Override 
  196.     protected boolean isCrawledUrl(String url) { 
  197.         return isAvaliableUrl(url); 
  198.     } 
  199.  
  200.  
  201.     /** 
  202.      * 生成标题 
  203.      * @param htmlContent 
  204.      * @return 
  205.      */ 
  206.     private String parseTitle(String htmlContent) { 
  207.         if (htmlContent == null || htmlContent.trim().equals("")) 
  208.             return null
  209.         String title = htmlContent; 
  210.         title = title.trim(); 
  211.         for (int i = 0; i < title.length(); i++) { 
  212.             if (String.valueOf((title.charAt(i))).matches("[,.\\?\\!\\.,]")) { 
  213.                 title = title.substring(0, i); 
  214.                 break
  215.             } 
  216.         } 
  217.         return title; 
  218.     } 
  219.  

结果实体类:

  1.  
  2. public class WeiboBlock{ 
  3.      
  4.     private String pid; 
  5.     private String js; 
  6.     private String css; 
  7.     private String html; 
  8.      
  9.     public WeiboBlock(){} 
  10.      
  11.     public String getPid() { 
  12.         return pid; 
  13.     } 
  14.     public void setPid(String pid) { 
  15.         this.pid = pid; 
  16.     } 
  17.     public String getJs() { 
  18.         return js; 
  19.     } 
  20.     public void setJs(String js) { 
  21.         this.js = js; 
  22.     } 
  23.     public String getCss() { 
  24.         return css; 
  25.     } 
  26.     public void setCss(String css) { 
  27.         this.css = css; 
  28.     } 
  29.     public String getHtml() { 
  30.         return html; 
  31.     } 
  32.     public void setHtml(String html) { 
  33.         this.html = html; 
  34.     } 
  35.      

关键字生成策略类:

  1. public class SinaKeyWordsPolicy implements KeyWordsPolicy { 
  2.  
  3.     @Override 
  4.     public String getKeyWord(String keyWordLine, String siteLine) { 
  5.          
  6.         String keyWord = null
  7.  
  8.         keyWordLine = keyWordLine.replaceAll("\""""); 
  9.         keyWordLine = keyWordLine.replaceAll("AND"" "); 
  10.         keyWordLine = keyWordLine.replaceAll("OR""|"); 
  11.          
  12.         if (keyWordLine.contains("|")) { 
  13.              
  14.             String[] tempStrings = keyWordLine.split("|"); 
  15.             if (tempStrings.length > 3) { 
  16.                 for (int i=0; i<3 ;i++) { 
  17.                     keyWord += tempStrings[i]; 
  18.                     keyWord += "|"
  19.                 } 
  20.             }else { 
  21.                 keyWord = keyWordLine; 
  22.             } 
  23.         }else { 
  24.             keyWord = keyWordLine; 
  25.         } 
  26.         return java.net.URLEncoder.encode(java.net.URLEncoder.encode(keyWord)); 
  27.     } 
  28.  

关键字配置文件使用文本文件即可,每行一组关键字,格式类似如下:

"key1"

"key1"AND"key2"

"key1"AND("key2"OR"key3")

 附:项目源码已经整理并上传GitHub, 访问地址:https://github.com/Siriuser/WeiboCrawler

需要源码的话请自行下载。

本文出自 “果壳中的宇宙” 博客,请务必保留此出处http://williamx.blog.51cto.com/3629295/1047832

抱歉!评论已关闭.