Java爬虫框架WebMagic的使用总结

2023-11-17

最近,项目做一个公司新闻网站,分为PC&移动端(h5),数据来源是从HSZX与huanqiu2个网站爬取,主要使用Java编写的WebMagic作为爬虫框架,数据分为批量抓取、增量抓取,批量抓当前所有历史数据,增量需要每10分钟定时抓取一次,由于从2个网站抓取,并且频道很多,数据量大,更新频繁;开发过程中遇到很多的坑,今天腾出时间,感觉有必要做以总结。

工具说明:

           1、WebMagic是一个简单灵活的爬虫框架。基于WebMagic,你可以快速开发出一个高效、易维护的爬虫。

                  官网地址:http://webmagic.io/

                  文档说明:http://webmagic.io/docs/zh/

            2、jsoup是Java的一个html解析工作,解析性能很不错。

                    文档地址:http://www.open-open.com/jsoup/

            3、Jdiy一款超轻量的java极速开发框架,javaEE/javaSE环境均适用,便捷的数据库CRUD操作API。支持各大主流数据库。

                    官网地址:http://www.jdiy.org/jdiy.jd

 

 

 

一、使用到的技术,如下:
       WebMagic作为爬虫框架、httpclient作为获取网页工具、Jsoup作为分析页面定位抓取内容、ExecutorService线程池作为定时增量抓取、Jdiy作为持久层框架
       
二、历史抓取代码,如下:

  1. package com.spider.huanqiu.history;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5. import org.apache.commons.lang3.StringUtils;  
  6. import org.jdiy.core.Rs;  
  7. import org.jsoup.Jsoup;  
  8. import org.jsoup.nodes.Document;  
  9. import org.jsoup.nodes.Element;  
  10. import org.jsoup.select.Elements;  
  11. import us.codecraft.webmagic.Page;  
  12. import us.codecraft.webmagic.Site;  
  13. import us.codecraft.webmagic.Spider;  
  14. import us.codecraft.webmagic.processor.PageProcessor;  
  15. import com.spider.huasheng.history.Pindao;  
  16. import com.spider.utils.Config;  
  17. import com.spider.utils.ConfigBase;  
  18. import com.spider.utils.DateUtil;  
  19. import com.spider.utils.HttpClientUtil;  
  20. import com.spider.utils.service.CommService;  
  21.   
  22. /** 
  23.  * 描        述:抓取xxx-国际频道历史数据 
  24.  * 创建时间:2016-11-9 
  25.  * @author Jibaole 
  26.  */  
  27. public class HQNewsDao extends ConfigBase  implements PageProcessor{  
  28.        public static final String index_list = "(.*).huanqiu.com/(.*)pindao=(.*)";//校验地址正则  
  29.        public static String pic_dir = fun.getProValue(PINDAO_PIC_FILE_PATH);//获取图片保存路径  
  30.          
  31.       
  32.     // 部分一:抓取网站的相关配置,包括编码、重试次数、抓取间隔、超时时间、请求消息头、UA信息等  
  33.         private Site site = Site.me().setRetryTimes(3).setSleepTime(1000).setTimeOut(6000)  
  34.                            .addHeader("Accept-Encoding", "/").setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36");  
  35.     @Override  
  36.     public Site getSite() {    
  37.         return site;  
  38.     }  
  39.       
  40.       
  41.      @Override  
  42.         public void process(Page page) {  
  43.         try {  
  44.             //列表页  
  45.             if (page.getUrl().regex(index_list).match()) {  
  46.                 List<String> Urllist =new ArrayList<String>();  
  47.                 String url =page.getUrl().toString();  
  48.                 String pageUrl = url.substring(0,url.lastIndexOf("?"));  
  49.                 String pindaoId =url.substring(url.lastIndexOf("=")+1);  
  50.                 Urllist = saveNewsListData(pageUrl,pindaoId);  
  51.                 page.addTargetRequests(Urllist);//添加地址,根据url对该地址处理  
  52.             }  
  53.             //可增加else if 处理不同URL地址  
  54.         } catch (Exception e) {  
  55.             e.printStackTrace();  
  56.         }  
  57.      }  
  58.   
  59.   
  60.     private List<String> saveNewsListData(String pageUrl,String pindaoId) {  
  61.     List<String> urlList = new ArrayList<String>();  
  62.     Document docList = null;  
  63.    String newsIdFirst="";  
  64.    String pageListStr=HttpClientUtil.getPage(pageUrl);//HttpClientUtil方式获取网页内容  
  65.     if(StringUtils.isNotEmpty(pageListStr)){  
  66.      try {  
  67.         docList = Jsoup.parse(pageListStr);  
  68.         Elements fallsFlow=docList.getElementsByClass("fallsFlow");  
  69.         if(!fallsFlow.isEmpty()){  
  70.             Elements liTag=fallsFlow.get(0).getElementsByTag("li");  
  71.             if(!liTag.isEmpty()){  
  72.                 for(int i=0;i<liTag.size();i++){  
  73.                      String  title="",contentUrl="",newsId="",pic="",absContent="",pushTime="",timeFalg="";  
  74.                     Element obj=liTag.get(i);  
  75.                     try{  
  76.                           contentUrl=obj.getElementsByTag("h3").select("a").attr("href");  
  77.                          if(StringUtils.isNotEmpty(contentUrl)){  
  78.                               title=obj.getElementsByTag("h3").select("a").attr("title");//标题  
  79.                               Rs isTitle = CommService.checkNewsName(title); //校验新闻标题  
  80.                                 if(!isTitle.isNull()){  
  81.                                     continue;  
  82.                                 }  
  83.                                   
  84.                                   
  85.                               System.err.println("<<<<<<--DAO------当前抓取文章为(xxx历史):"+title+"------------");  
  86.                               newsId =  contentUrl.substring(contentUrl.lastIndexOf("/") + 1,contentUrl.lastIndexOf(".html"));  
  87.                               if(!pageUrl.contains(".htm") && i == 0){  
  88.                                   newsIdFirst = newsId;  
  89.                               }  
  90.                              //图片  
  91.                              if(!obj.getElementsByTag("img").attr("src").isEmpty()){  
  92.                                     pic=obj.getElementsByTag("img").first().attr("src");  
  93.                                     if(StringUtils.isNotEmpty(pic) ){  
  94.                                         pic = fun.downloadPic(pic,pic_dir+"list/"+newsId+"/");//获取列表图片,保存本地  
  95.                                     }  
  96.                                 }  
  97.                              if(!obj.getElementsByTag("h5").isEmpty()){  
  98.                                  //简介  
  99.                                  absContent = obj.getElementsByTag("h5").first().text();  
  100.                                  if(StringUtils.isNotEmpty(absContent) && absContent.indexOf("[")>0){  
  101.                                       absContent = absContent.substring(0, absContent.indexOf("["));  
  102.                                   }  
  103.                              }  
  104.                                
  105.                               if(!obj.getElementsByTag("h6").isEmpty()){  
  106.                                   pushTime = obj.getElementsByTag("h6").text();   
  107.                                   timeFalg=pushTime.substring(0, 4);  
  108.                               }  
  109.                               String hrmlStr=HttpClientUtil.getPage(contentUrl);  
  110.                               if(StringUtils.isNotEmpty(hrmlStr)){  
  111.                                   Document docPage = Jsoup.parse(hrmlStr);  
  112.                               Elements pageContent = docPage.getElementsByClass("conText");  
  113.                                 if(!pageContent.isEmpty()){  
  114.                                     String comefrom = pageContent.get(0).getElementsByClass("fromSummary").text();//来源  
  115.                                     if(StringUtils.isNotEmpty(comefrom) && comefrom.contains("环球")){  
  116.                                         String author=pageContent.get(0).getElementsByClass("author").text();//作者  
  117.                                         Element contentDom = pageContent.get(0).getElementById("text");  
  118.                                         if(!contentDom.getElementsByTag("a").isEmpty()){  
  119.                                             contentDom.getElementsByTag("a").removeAttr("href");//移除外跳连接  
  120.                                         }  
  121.                                         if(!contentDom.getElementsByClass("reTopics").isEmpty()){  
  122.                                              contentDom.getElementsByClass("reTopics").remove();//推荐位  
  123.                                         }  
  124.                                        if(!contentDom.getElementsByClass("spTopic").isEmpty()){  
  125.                                            contentDom.getElementsByClass("spTopic").remove(); //去除排行榜列表  
  126.                                        }  
  127.                                        if(!contentDom.getElementsByClass("editorSign").isEmpty()){  
  128.                                            contentDom.getElementsByClass("editorSign").remove();//移除编辑标签  
  129.                                        }  
  130.                                          
  131.                                         String content = contentDom.toString();  
  132.                                         if(!StringUtils.isEmpty(content)){  
  133.                                             content = content.replaceAll("\r\n|\r|\n|\t|\b|~|\f", "");//去掉回车换行符  
  134.                                             content = replaceForNews(content,pic_dir+"article/"+newsId+"/");//替换内容中的图片  
  135.                                             while (true) {  
  136.                                                  if(content.indexOf("<!--") ==-1 && content.indexOf("<script") == -1){  
  137.                                                      break;  
  138.                                                  }else{  
  139.                                                    if(content.indexOf("<!--") >0 && content.lastIndexOf("-->")>0){  
  140.                                                           String moveContent= content.substring(content.indexOf("<!--"), content.indexOf("-->")+3);//去除注释  
  141.                                                           content = content.replace(moveContent, "");  
  142.                                                             }  
  143.                                                          if(content.indexOf("<script") >0 && content.lastIndexOf("</script>")>0){  
  144.                                                           String moveContent= content.substring(content.indexOf("<script"), content.indexOf("</script>")+9);//去除JS  
  145.                                                           content = content.replace(moveContent, "");  
  146.                                                           }  
  147.                                                }  
  148.                                             }  
  149.                                         }  
  150.                                     if(StringUtils.isEmpty(timeFalg) || "2016".equals(timeFalg) ||   
  151.                                         "28".equals(pindaoId) || "29".equals(pindaoId) || "30".equals(pindaoId)){  
  152.                                             Rs news= new Rs("News");  
  153.                                             news.set("title", title);  
  154.                                             news.set("shortTitle",title);  
  155.                                             news.set("beizhu",absContent);  
  156.                                             news.set("savetime", pushTime);  
  157.                                             if(StringUtils.isNotEmpty(pic)){  
  158.                                                 news.set("path", pic);  
  159.                                                 news.set("mini_image", pic);  
  160.                                             }  
  161.                                             news.set("pindaoId", pindaoId);  
  162.                                             news.set("status", 0);//不显示  
  163.                                             news.set("canComment", 1);//是否被评论  
  164.                                             news.set("syn", 1);//是否异步  
  165.                                             news.set("type", 1);//是否异步  
  166.                                             news.set("comefrom",comefrom);  
  167.                                             news.set("author", author);  
  168.                                             news.set("content", content);  
  169.                                             news.set("content2", content);  
  170.                                             CommService.save(news);  
  171.   
  172.                                               System.err.println("------新增(xxx历史):"+title+"------>>>>>>>");  
  173.                                     }else{  
  174.                                         break;  
  175.                                     }  
  176.                                       }  
  177.                                   }  
  178.                               }  
  179.                               }  
  180.                     }catch (Exception e) {  
  181.                         e.printStackTrace();    
  182.                     }  
  183.                 }  
  184.             }  
  185.             if(!pageUrl.contains(".htm")){  
  186.                 //得到分页内容  
  187.                 Element pages = docList.getElementById("pages");  
  188.                 int num = pages.getElementsByTag("a").size();  
  189.                 String pageMaxStr = pages.getElementsByTag("a").get(num-2).text();  
  190.                 int pageMax=0;  
  191.                 if(StringUtils.isNotEmpty(pageMaxStr)){  
  192.                     pageMax= Integer.parseInt(pageMaxStr);  
  193.                 }  
  194.                 if(pageMax>historyMaxPage){//控制历史抓取页数  
  195.                     pageMax = historyMaxPage;  
  196.                 }  
  197.                 for(int i=1 ;i<pageMax;i++){//翻页请求  
  198.                     String link = "";  
  199.                     link = pageUrl+(i+1)+".html?pindao="+pindaoId;  
  200.                     urlList.add(link);//循环处理url,翻页内容  
  201.                 }  
  202.                 //获取增量标识  
  203.                  Rs flag = CommService.checkPd(pindaoId,pageUrl,Config.SITE_HQ);  
  204.                     //初始化  
  205.                     if(flag.isNull()){  
  206.                         Rs task= new Rs("TaskInfo");  
  207.                         task.set("pindao_id", pindaoId);  
  208.                         task.set("news_id", newsIdFirst);  
  209.                         task.set("page_url", pageUrl);  
  210.                         task.set("site", Config.SITE_HQ);  
  211.                         task.set("create_time", DateUtil.fullDate());  
  212.                         CommService.save(task);   
  213.                     }  
  214.              }  
  215.         }  
  216.       } catch (Exception e) {  
  217.         e.printStackTrace();  
  218.       }  
  219.     }  
  220.     return urlList;  
  221.     }  
  222.   
  223.     public static void main(String[] args) {  
  224.         List<String> strList=new ArrayList<String>();  
  225.             strList.add("http://www.xxx/exclusive/?pindao="+Pindao.getKey("国际"));  
  226.             //滚动新闻  
  227.             strList.add("http://www.xxx/article/?pindao="+Pindao.getKey("国际"));  
  228.           
  229.         for(String str:strList){  
  230.             Spider.create(new HQNewsDao()).addUrl(str).thread(1).run();   
  231.         }  
  232.  }  
  233.       
  234.     //所有频道Action  
  235.     public static void runNewsList(List<String> strList){  
  236.         for(String str:strList){  
  237.             Spider.create(new HQNewsDao()).addUrl(str).thread(1).run(); //添加爬取地址、设置线程数    
  238.         }  
  239.     }  
  240. }  


三、增量抓取代码,如下(在历史上改动):

 说明:增量每10分钟执行一次,每次只抓取最新一页数据,根据增量标识(上一次第一条新闻news_id),存在相同news_id或一页爬完就终止抓取。

  1. package com.spider.huanqiu.task;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5. import org.apache.commons.lang3.StringUtils;  
  6. import org.jdiy.core.Rs;  
  7. import org.jsoup.Jsoup;  
  8. import org.jsoup.nodes.Document;  
  9. import org.jsoup.nodes.Element;  
  10. import org.jsoup.select.Elements;  
  11. import us.codecraft.webmagic.Page;  
  12. import us.codecraft.webmagic.Site;  
  13. import us.codecraft.webmagic.Spider;  
  14. import us.codecraft.webmagic.processor.PageProcessor;  
  15. import com.spider.huasheng.history.Pindao;  
  16. import com.spider.utils.Config;  
  17. import com.spider.utils.ConfigBase;  
  18. import com.spider.utils.DateUtil;  
  19. import com.spider.utils.HttpClientUtil;  
  20. import com.spider.utils.service.CommService;  
  21.   
  22. public class HQNewsTaskDao extends ConfigBase  implements PageProcessor{  
  23.        public static final String index_list = "(.*).huanqiu.com/(.*)pindao=(.*)";  
  24.        public static String pic_dir = fun.getProValue(PINDAO_PIC_FILE_PATH);  
  25.        public static String new_id="";       
  26.       
  27.     // 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等  
  28.     private Site site = Site.me().setRetryTimes(3).setSleepTime(1000).setTimeOut(6000)  
  29.                        .addHeader("Accept-Encoding", "/").setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36");  
  30.     @Override  
  31.     public Site getSite() {    
  32.         return site;  
  33.     }  
  34.       
  35.      @Override  
  36.         public void process(Page page) {  
  37.         try {  
  38.             //列表页  
  39.             if (page.getUrl().regex(index_list).match()) {  
  40.                 List<String> Urllist =new ArrayList<String>();  
  41.                 String url =page.getUrl().toString();  
  42.                 String pageUrl = url.substring(0,url.lastIndexOf("?"));  
  43.                 String pindaoId =url.substring(url.lastIndexOf("=")+1);  
  44.                 Rs isFlag = CommService.checkPd(pindaoId,pageUrl,Config.SITE_HQ);  
  45.                 if(!isFlag.isNull()){  
  46.                      new_id=isFlag.getString("news_id");  
  47.                 }  
  48.                 Urllist = saveNewsListData(pageUrl,pindaoId);  
  49.                 page.addTargetRequests(Urllist);  
  50.             }  
  51.         } catch (Exception e) {  
  52.             e.printStackTrace();  
  53.         }  
  54.      }  
  55.   
  56.     private List<String> saveNewsListData(String pageUrl,String pindaoId) {  
  57.     List<String> urlList = new ArrayList<String>();  
  58.     Document docList = null;  
  59.     String pageListStr=HttpClientUtil.getPage(pageUrl);  
  60.     if(StringUtils.isNotEmpty(pageListStr)){  
  61.      try {  
  62.         docList = Jsoup.parse(pageListStr);  
  63.         Elements fallsFlow=docList.getElementsByClass("fallsFlow");  
  64.         if(!fallsFlow.isEmpty()){  
  65.             String newsIdFirst="";  
  66.             Boolean isIng = true;  
  67.             Elements liTag=fallsFlow.get(0).getElementsByTag("li");  
  68.             if(!liTag.isEmpty()){  
  69.                 for(int i=0;i<liTag.size() && isIng;i++){  
  70.                     String  title="",contentUrl="",newsId="",pic="",absContent="",pushTime="";  
  71.                     Element obj=liTag.get(i);  
  72.                     try{  
  73.                           contentUrl=obj.getElementsByTag("h3").select("a").attr("href");  
  74.                          if(StringUtils.isNotEmpty(contentUrl)){  
  75.                               title=obj.getElementsByTag("h3").select("a").attr("title");//标题  
  76.                               Rs isTitle = CommService.checkNewsName(title); //校验新闻标题  
  77.                                 if(!isTitle.isNull()){  
  78.                                     continue;  
  79.                                 }  
  80.                               System.err.println("---------当前抓取文章为(增量):"+title+"------------");  
  81.                               newsId =  contentUrl.substring(contentUrl.lastIndexOf("/") + 1,contentUrl.lastIndexOf(".html"));  
  82.                             if(!newsId.equals(new_id)){  
  83.                               if(!pageUrl.contains(".htm") && i == 0){  
  84.                                   newsIdFirst = newsId;  
  85.                               }  
  86.                              //图片  
  87.                              if(!obj.getElementsByTag("img").attr("src").isEmpty()){  
  88.                                     pic=obj.getElementsByTag("img").first().attr("src");  
  89.                                     if(StringUtils.isNotEmpty(pic) ){  
  90.                                         pic = fun.downloadPic(pic,pic_dir+"list/"+newsId+"/");  
  91.                                     }  
  92.                                 }  
  93.                              if(!obj.getElementsByTag("h5").isEmpty()){  
  94.                                  //简介  
  95.                                  absContent = obj.getElementsByTag("h5").first().text();  
  96.                                  if(StringUtils.isNotEmpty(absContent) && absContent.indexOf("[")>0){  
  97.                                       absContent = absContent.substring(0, absContent.indexOf("["));  
  98.                                   }   
  99.                              }  
  100.                             if(!obj.getElementsByTag("h6").isEmpty()){  
  101.                                 pushTime = obj.getElementsByTag("h6").text();  
  102.                             }  
  103.                             String hrmlStr=HttpClientUtil.getPage(contentUrl);  
  104.                             if(StringUtils.isNotEmpty(hrmlStr)){  
  105.                               Document docPage = Jsoup.parse(hrmlStr);  
  106.                               Elements pageContent = docPage.getElementsByClass("conText");  
  107.                                 if(!pageContent.isEmpty()){  
  108.                                     String comefrom = pageContent.get(0).getElementsByClass("fromSummary").text();//来源  
  109.                                     if(StringUtils.isNotEmpty(comefrom) && comefrom.contains("环球")){  
  110.                                         String author=pageContent.get(0).getElementsByClass("author").text();//作者  
  111.                                         Element contentDom = pageContent.get(0).getElementById("text");  
  112.                                         if(!contentDom.getElementsByTag("a").isEmpty()){  
  113.                                             contentDom.getElementsByTag("a").removeAttr("href");//移除外跳连接  
  114.                                         }  
  115.                                         if(!contentDom.getElementsByClass("reTopics").isEmpty()){  
  116.                                              contentDom.getElementsByClass("reTopics").remove();//推荐位  
  117.                                         }  
  118.                                         if(!contentDom.getElementsByClass("spTopic").isEmpty()){  
  119.                                            contentDom.getElementsByClass("spTopic").remove();   
  120.                                        }  
  121.                                         if(!contentDom.getElementsByClass("editorSign").isEmpty()){  
  122.                                            contentDom.getElementsByClass("editorSign").remove();//移除编辑   
  123.                                        }  
  124.                                         String content = contentDom.toString();  
  125.                                         if(!StringUtils.isEmpty(content)){  
  126.                                             content = content.replaceAll("\r\n|\r|\n|\t|\b|~|\f", "");//去掉回车换行符  
  127.                                             content = replaceForNews(content,pic_dir+"article/"+newsId+"/");//替换内容中的图片  
  128.                                             while (true) {  
  129.                                                  if(content.indexOf("<!--") ==-1 && content.indexOf("<script") == -1){  
  130.                                                      break;  
  131.                                                  }else{  
  132.                                                    if(content.indexOf("<!--") >0 && content.lastIndexOf("-->")>0){  
  133.                                                           String moveContent= content.substring(content.indexOf("<!--"), content.indexOf("-->")+3);//去除注释  
  134.                                                           content = content.replace(moveContent, "");  
  135.                                                             }  
  136.                                                          if(content.indexOf("<script") >0 && content.lastIndexOf("</script>")>0){  
  137.                                                           String moveContent= content.substring(content.indexOf("<script"), content.indexOf("</script>")+9);//去除JS  
  138.                                                           content = content.replace(moveContent, "");  
  139.                                                           }  
  140.                                                }  
  141.                                             }  
  142.                                         }  
  143.                                         if(StringUtils.isNotEmpty(content) && StringUtils.isNotEmpty(title)){  
  144.                                             Rs news= new Rs("News");  
  145.                                             news.set("title", title);  
  146.                                             news.set("shortTitle",title);  
  147.                                             news.set("beizhu",absContent);  
  148.                                             news.set("savetime", pushTime);  
  149.                                             if(StringUtils.isNotEmpty(pic)){  
  150.                                                 news.set("path", pic);  
  151.                                                 news.set("mini_image", pic);  
  152.                                             }  
  153.                                             news.set("pindaoId", pindaoId);  
  154.                                             news.set("status", 1);//不显示  
  155.                                             news.set("canComment", 1);//是否被评论  
  156.                                             news.set("syn", 1);//是否异步  
  157.                                             news.set("type", 1);//是否异步  
  158.                                             news.set("comefrom",comefrom);  
  159.                                             news.set("author", author);  
  160.                                             news.set("content", content);  
  161.                                             news.set("content2", content);  
  162.                                             CommService.save(news);  
  163.                                         }  
  164.                                       }  
  165.                                   }  
  166.                             }  
  167.                             }else{  
  168.                                 isIng=false;  
  169.                                 break;  
  170.                             }  
  171.                               }  
  172.                     }catch (Exception e) {  
  173.                         e.printStackTrace();    
  174.                     }  
  175.                 }  
  176.             }  
  177.             if(!pageUrl.contains(".htm")){  
  178.                 //增量标识  
  179.                  Rs flag = CommService.checkPd(pindaoId,pageUrl,Config.SITE_HQ);  
  180.                     //初始化  
  181.                     if(flag.isNull()){  
  182.                         Rs task= new Rs("TaskInfo");  
  183.                         task.set("pindao_id", pindaoId);  
  184.                         task.set("news_id", newsIdFirst);  
  185.                         task.set("page_url", pageUrl);  
  186.                         task.set("site", Config.SITE_HQ);  
  187.                         task.set("create_time", DateUtil.fullDate());  
  188.                         CommService.save(task);   
  189.                     }else if(StringUtils.isNotEmpty(newsIdFirst)){  
  190.                         flag.set("news_id", newsIdFirst);  
  191.                         flag.set("update_time", DateUtil.fullDate());  
  192.                         CommService.save(flag);  
  193.                     }  
  194.              }  
  195.         }  
  196.       } catch (Exception e) {  
  197.         e.printStackTrace();  
  198.       }  
  199.     }  
  200.     return urlList;  
  201.     }  
  202.   
  203.     public static void main(String[] args) {  
  204.         List<String> strList=new ArrayList<String>();  
  205.             strList.add("http://www.xxx/exclusive/?pindao="+Pindao.getKey("国际"));  
  206.             //滚动新闻  
  207.             strList.add("http://www.xxx/article/?pindao="+Pindao.getKey("国际"));  
  208.           
  209.         for(String str:strList){  
  210.             Spider.create(new HQNewsTaskDao()).addUrl(str).thread(1).run();   
  211.         }  
  212.  }  
  213.       
  214.     //所有频道Action  
  215.     public static void runNewsList(List<String> strList){  
  216.         for(String str:strList){  
  217.             Spider.create(new HQNewsTaskDao()).addUrl(str).thread(1).run();       
  218.         }  
  219.     }  
  220. }  

 


四、定时抓取,配置如下:
           1、web.xml重配置监听       

 

  1. <!-- 添加:增量数据抓取监听 -->  
  2.    <listener>   
  3.        <listener-class>com.spider.utils.AutoRun</listener-class>   
  4.    </listener>  

        2、定时代码

       

  1. package com.spider.utils;  
  2.   
  3. import java.util.concurrent.Executors;  
  4. import java.util.concurrent.ScheduledExecutorService;  
  5. import java.util.concurrent.TimeUnit;  
  6. import javax.servlet.ServletContextEvent;  
  7. import javax.servlet.ServletContextListener;  
  8. import com.spider.huanqiu.timer.HQJob1;  
  9. import com.spider.huanqiu.timer.HQJob2;  
  10. import com.spider.huanqiu.timer.HQJob3;  
  11. import com.spider.huanqiu.timer.HQJob4;  
  12. import com.spider.huasheng.timer.HSJob1;  
  13. import com.spider.huasheng.timer.HSJob2;  
  14. /** 
  15.  * 描        述:监听增量抓取Job 
  16.  * 创建时间:2016-11-4 
  17.  * @author Jibaole 
  18.  */  
  19. public class AutoRun implements ServletContextListener {   
  20.     
  21.   public void contextInitialized(ServletContextEvent event) {   
  22.       ScheduledExecutorService scheduExec =  Executors.newScheduledThreadPool(6);  
  23.     /*  
  24.      * 这里开始循环执行 HSJob()方法了  
  25.      * schedule(param1, param2,param3)这个函数的三个参数的意思分别是:  
  26.      *    param1:你要执行的方法;param2:延迟执行的时间,单位毫秒;param3:循环间隔时间,单位毫秒  
  27.      */   
  28.     scheduExec.scheduleAtFixedRate(new HSJob1(), 1*1000*60,1000*60*10,TimeUnit.MILLISECONDS);  //延迟1分钟,设置没10分钟执行一次  
  29.     scheduExec.scheduleAtFixedRate(new HSJob2(), 3*1000*60,1000*60*10,TimeUnit.MILLISECONDS);  //延迟3分钟,设置没10分钟执行一次  
  30.       
  31.     scheduExec.scheduleAtFixedRate(new HQJob1(), 5*1000*60,1000*60*10,TimeUnit.MILLISECONDS);  //延迟5分钟,设置没10分钟执行一次  
  32.     scheduExec.scheduleAtFixedRate(new HQJob2(), 7*1000*60,1000*60*10,TimeUnit.MILLISECONDS);  //延迟7分钟,设置没10分钟执行一次  
  33.     scheduExec.scheduleAtFixedRate(new HQJob3(), 9*1000*60,1000*60*14,TimeUnit.MILLISECONDS);  //延迟9分钟,设置没10分钟执行一次  
  34.     scheduExec.scheduleAtFixedRate(new HQJob4(), 11*1000*60,1000*60*10,TimeUnit.MILLISECONDS);  //延迟11分钟,设置没10分钟执行一次  
  35.   }   
  36.   public void contextDestroyed(ServletContextEvent event) {   
  37.       System.out.println("=======timer销毁==========");  
  38.     //timer.cancel();   
  39.   }   
  40. }   


       3、具体执行业务(举一个例子)

         

  1. package com.spider.huasheng.timer;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5. import java.util.TimerTask;  
  6. import com.spider.huasheng.task.HSTaskDao;  
  7. import com.spider.huasheng.task.HSTaskDao1;  
  8. import com.spider.huasheng.task.HSTaskDao2;  
  9.   
  10. /** 
  11.  * 描        述:国际、社会、国内、评论等频道定时任务 
  12.  * 创建时间:2016-11-9 
  13.  * @author Jibaole 
  14.  */  
  15. public class HSJob1 implements Runnable{   
  16.     @Override   
  17.     public void run() {   
  18.         System.out.println("======>>>开始:xxx-任务1====");  
  19.   try {   
  20.       runNews();  
  21.         runNews1();  
  22.         runNews2();  
  23.      } catch (Throwable t) {    
  24.          System.out.println("Error");    
  25.      }   
  26.        System.out.println("======xxx-任务1>>>结束!!!====");  
  27.     }   
  28.     /** 
  29.      * 抓取-新闻 频道列表 
  30.      */  
  31.     public void runNews(){  
  32.         List<String> strList=new ArrayList<String>();  
  33.         /**##############>>>16、国际<<<##################*/  
  34.         //国际视野  
  35.         strList.add("http://xxx/class/2199.html?pindao=国际");  
  36.           
  37.         /**##############>>>17、社会<<<##################*/  
  38.         //社会  
  39.         strList.add("http://xxx/class/2200.html?pindao=社会");  
  40.           
  41.         /**##############>>>18、国内<<<##################*/  
  42.         //国内动态  
  43.         strList.add("http://xxx/class/1922.html?pindao=国内");  
  44.         HQNewsTaskDao.runNewsList(strList);  
  45.     }  
  46.       
  47.     /** 
  48.      * 抓取-新闻 频道列表 
  49.      */  
  50.     public void runNews1(){  
  51.         List<String> strList=new ArrayList<String>();  
  52.         /**##############>>>19、评论<<<##################*/  
  53.         //华声视点  
  54.         strList.add("http://xxx/class/709.html?pindao=评论");  
  55.         //财经观察  
  56.         strList.add("http://xxx/class/2557.html?pindao=评论");  
  57.         /**##############>>>20、军事<<<##################*/  
  58.         //军事  
  59.         strList.add("http://xxx/class/2201.html?pindao=军事");  
  60.         HQNewsTaskDao.runNewsList(strList);  
  61.     }  
  62.     /** 
  63.      * 抓取-新闻 频道列表 
  64.      */  
  65.     public void runNews2(){  
  66.         List<String> strList=new ArrayList<String>();  
  67.         /**##############>>>24、财经<<<##################*/  
  68.         //财讯  
  69.         strList.add("http://xxx/class/2353.html?pindao=财经");  
  70.         //经济观察  
  71.         strList.add("http://xxx/class/2348.html?pindao=财经");  
  72.         /**##############>>>30、人文<<<##################*/  
  73.         //历史上的今天  
  74.         strList.add("http://xxx/class/1313.html?pindao=人文");  
  75.         //正史风云  
  76.         strList.add("http://xxx/class/1362.html?pindao=人文");  
  77.         HSTaskDao2.runNewsList(strList);  
  78.     }  
  79. }  

 

 

 

 五、使用到的工具类

 

 

 

       1、HttpClientUtil工具类

  1. package com.spider.utils;  
  2.   
  3.   
  4. import java.io.BufferedReader;  
  5. import java.io.File;  
  6. import java.io.IOException;  
  7. import java.io.InputStreamReader;  
  8. import java.net.URL;  
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11. import java.util.Map;  
  12. import org.apache.commons.httpclient.HttpClient;  
  13. import org.apache.commons.httpclient.HttpStatus;  
  14. import org.apache.commons.httpclient.methods.GetMethod;  
  15. import org.apache.http.HttpEntity;  
  16. import org.apache.http.NameValuePair;  
  17. import org.apache.http.client.config.RequestConfig;  
  18. import org.apache.http.client.entity.UrlEncodedFormEntity;  
  19. import org.apache.http.client.methods.CloseableHttpResponse;  
  20. import org.apache.http.client.methods.HttpGet;  
  21. import org.apache.http.client.methods.HttpPost;  
  22. import org.apache.http.conn.ssl.DefaultHostnameVerifier;  
  23. import org.apache.http.conn.util.PublicSuffixMatcher;  
  24. import org.apache.http.conn.util.PublicSuffixMatcherLoader;  
  25. import org.apache.http.entity.ContentType;  
  26. import org.apache.http.entity.StringEntity;  
  27. import org.apache.http.entity.mime.MultipartEntityBuilder;  
  28. import org.apache.http.entity.mime.content.FileBody;  
  29. import org.apache.http.entity.mime.content.StringBody;  
  30. import org.apache.http.impl.client.CloseableHttpClient;  
  31. import org.apache.http.impl.client.HttpClients;  
  32. import org.apache.http.message.BasicNameValuePair;  
  33. import org.apache.http.util.EntityUtils;  
  34.   
  35.   
  36. public class HttpClientUtil {  
  37.     private final static String charset = "UTF-8";  
  38.     private RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(15000)  
  39.             .setConnectTimeout(15000)  
  40.             .setConnectionRequestTimeout(15000)  
  41.             .build();  
  42.       
  43.     private static HttpClientUtil instance = null;  
  44.     private HttpClientUtil(){}  
  45.     public static HttpClientUtil getInstance(){  
  46.         if (instance == null) {  
  47.             instance = new HttpClientUtil();  
  48.         }  
  49.         return instance;  
  50.     }  
  51.       
  52.     /** 
  53.      * 发送 post请求 
  54.      * @param httpUrl 地址 
  55.      */  
  56.     public String sendHttpPost(String httpUrl) {  
  57.         HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost    
  58.         return sendHttpPost(httpPost);  
  59.     }  
  60.       
  61.     /** 
  62.      * 发送 post请求 
  63.      * @param httpUrl 地址 
  64.      * @param params 参数(格式:key1=value1&key2=value2) 
  65.      */  
  66.     public String sendHttpPost(String httpUrl, String params) {  
  67.         HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost    
  68.         try {  
  69.             //设置参数  
  70.             StringEntity stringEntity = new StringEntity(params, "UTF-8");  
  71.             stringEntity.setContentType("application/x-www-form-urlencoded");   
  72.             httpPost.setEntity(stringEntity);  
  73.         } catch (Exception e) {  
  74.             e.printStackTrace();  
  75.         }  
  76.         return sendHttpPost(httpPost);  
  77.     }  
  78.        
  79.     /** 
  80.      * 发送 post请求 
  81.      * @param httpUrl 地址 
  82.      * @param maps 参数 
  83.      */  
  84.     public String sendHttpPost(String httpUrl, Map<String, String> maps) {  
  85.         HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost    
  86.         httpPost.setHeader("Content-Type","application/x-www-form-urlencoded;charset="+charset);  
  87.         httpPost.setHeader("User-Agent","Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.");  
  88.         // 创建参数队列    
  89.         List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();  
  90.         for (String key : maps.keySet()) {  
  91.             nameValuePairs.add(new BasicNameValuePair(key, maps.get(key)));  
  92.         }  
  93.         try {  
  94.             httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));  
  95.         } catch (Exception e) {  
  96.             e.printStackTrace();  
  97.         }  
  98.         return sendHttpPost(httpPost);  
  99.     }  
  100.       
  101.       
  102.     /** 
  103.      * 发送 post请求(带文件) 
  104.      * @param httpUrl 地址 
  105.      * @param maps 参数 
  106.      * @param fileLists 附件 
  107.      */  
  108.     public String sendHttpPost(String httpUrl, Map<String, String> maps, List<File> fileLists) {  
  109.         HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost  
  110.         MultipartEntityBuilder meBuilder = MultipartEntityBuilder.create();  
  111.         for (String key : maps.keySet()) {  
  112.             meBuilder.addPart(key, new StringBody(maps.get(key), ContentType.TEXT_PLAIN));  
  113.         }  
  114.         for(File file : fileLists) {  
  115.             FileBody fileBody = new FileBody(file);  
  116.             meBuilder.addPart("files", fileBody);  
  117.         }  
  118.         HttpEntity reqEntity = meBuilder.build();  
  119.         httpPost.setEntity(reqEntity);  
  120.         return sendHttpPost(httpPost);  
  121.     }  
  122.       
  123.     /** 
  124.      * 发送Post请求 
  125.      * @param httpPost 
  126.      * @return 
  127.      */  
  128.     private String sendHttpPost(HttpPost httpPost) {  
  129.         CloseableHttpClient httpClient = null;  
  130.         CloseableHttpResponse response = null;  
  131.         HttpEntity entity = null;  
  132.         String responseContent = null;  
  133.         try {  
  134.             // 创建默认的httpClient实例.  
  135.             httpClient = HttpClients.createDefault();  
  136.             httpPost.setConfig(requestConfig);  
  137.             // 执行请求  
  138.             response = httpClient.execute(httpPost);  
  139.             entity = response.getEntity();  
  140.             responseContent = EntityUtils.toString(entity, "UTF-8");  
  141.         } catch (Exception e) {  
  142.             e.printStackTrace();  
  143.         } finally {  
  144.             try {  
  145.                 // 关闭连接,释放资源  
  146.                 if (response != null) {  
  147.                     response.close();  
  148.                 }  
  149.                 if (httpClient != null) {  
  150.                     httpClient.close();  
  151.                 }  
  152.             } catch (IOException e) {  
  153.                 e.printStackTrace();  
  154.             }  
  155.         }  
  156.         return responseContent;  
  157.     }  
  158.   
  159.     /** 
  160.      * 发送 get请求 
  161.      * @param httpUrl 
  162.      */  
  163.     public String sendHttpGet(String httpUrl) {  
  164.         HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求  
  165.         return sendHttpGet(httpGet);  
  166.     }  
  167.   
  168.     /** 
  169.      * 发送 get请求Https 
  170.      * @param httpUrl 
  171.      */  
  172.     public String sendHttpsGet(String httpUrl) {  
  173.         HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求  
  174.         return sendHttpsGet(httpGet);  
  175.     }  
  176.       
  177.     /** 
  178.      * 发送Get请求 
  179.      * @param httpPost 
  180.      * @return 
  181.      */  
  182.     private String sendHttpGet(HttpGet httpGet) {  
  183.         CloseableHttpClient httpClient = null;  
  184.         CloseableHttpResponse response = null;  
  185.         HttpEntity entity = null;  
  186.         String responseContent = null;  
  187.         try {  
  188.             // 创建默认的httpClient实例.  
  189.             httpClient = HttpClients.createDefault();  
  190.             httpGet.setConfig(requestConfig);  
  191.             // 执行请求  
  192.             response = httpClient.execute(httpGet);  
  193.             entity = response.getEntity();  
  194.             responseContent = EntityUtils.toString(entity, "UTF-8");  
  195.         } catch (Exception e) {  
  196.             e.printStackTrace();  
  197.         } finally {  
  198.             try {  
  199.                 // 关闭连接,释放资源  
  200.                 if (response != null) {  
  201.                     response.close();  
  202.                 }  
  203.                 if (httpClient != null) {  
  204.                     httpClient.close();  
  205.                 }  
  206.             } catch (IOException e) {  
  207.                 e.printStackTrace();  
  208.             }  
  209.         }  
  210.         return responseContent;  
  211.     }  
  212.       
  213.     /** 
  214.      * 发送Get请求Https 
  215.      * @param httpPost 
  216.      * @return 
  217.      */  
  218.     private String sendHttpsGet(HttpGet httpGet) {  
  219.         CloseableHttpClient httpClient = null;  
  220.         CloseableHttpResponse response = null;  
  221.         HttpEntity entity = null;  
  222.         String responseContent = null;  
  223.         try {  
  224.             // 创建默认的httpClient实例.  
  225.             PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.load(new URL(httpGet.getURI().toString()));  
  226.             DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);  
  227.             httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build();  
  228.             httpGet.setConfig(requestConfig);  
  229.             // 执行请求  
  230.             response = httpClient.execute(httpGet);  
  231.             entity = response.getEntity();  
  232.             responseContent = EntityUtils.toString(entity, "UTF-8");  
  233.         } catch (Exception e) {  
  234.             e.printStackTrace();  
  235.         } finally {  
  236.             try {  
  237.                 // 关闭连接,释放资源  
  238.                 if (response != null) {  
  239.                     response.close();  
  240.                 }  
  241.                 if (httpClient != null) {  
  242.                     httpClient.close();  
  243.                 }  
  244.             } catch (IOException e) {  
  245.                 e.printStackTrace();  
  246.             }  
  247.         }  
  248.         return responseContent;  
  249.     }  
  250.       
  251.     /** 
  252.      * 利用httpClient获取页面 
  253.      * @param url 
  254.      * @return 
  255.      */  
  256.      public static String getPage(String url){  
  257.          String result="";  
  258.         HttpClient httpClient = new HttpClient();  
  259.         GetMethod getMethod = new GetMethod(url+"?date=" + new Date().getTime());//加时间戳,防止页面缓存  
  260.         try {  
  261.             int statusCode = httpClient.executeMethod(getMethod);  
  262.             httpClient.setTimeout(5000);  
  263.             httpClient.setConnectionTimeout(5000);  
  264.             if (statusCode != HttpStatus.SC_OK) {  
  265.                 System.err.println("Method failed: "+ getMethod.getStatusLine());  
  266.             }  
  267.               
  268.             // 读取内容  
  269.             //byte[] responseBody = getMethod.getResponseBody();  
  270.             BufferedReader reader = new BufferedReader(new InputStreamReader(getMethod.getResponseBodyAsStream()));    
  271.             StringBuffer stringBuffer = new StringBuffer();    
  272.             String str = "";    
  273.             while((str = reader.readLine())!=null){    
  274.                 stringBuffer.append(str);    
  275.             }    
  276.             // 处理内容  
  277.             result = stringBuffer.toString();  
  278.         } catch (Exception e) {  
  279.             System.err.println("页面无法访问");  
  280.         }  
  281.         getMethod.releaseConnection();  
  282.         return result;  
  283.   }  
  284. }  

2、下载图片方法

 

  1. /** 
  2.      * 下载图片到本地 
  3.      * @param picUrl 图片Url 
  4.      * @param localPath 本地保存图片地址 
  5.      * @return 
  6.      */  
  7.     public String downloadPic(String picUrl,String localPath){  
  8.         String filePath = null;  
  9.         String url = null;  
  10.         try {    
  11.             URL httpurl = new URL(picUrl);    
  12.             String fileName = getFileNameFromUrl(picUrl);    
  13.             filePath = localPath + fileName;  
  14.             File f = new File(filePath);    
  15.             FileUtils.copyURLToFile(httpurl, f);   
  16.             Function fun = new Function();  
  17.             url = filePath.replace("/www/web/imgs", fun.getProValue("IMG_PATH"));  
  18.         } catch (Exception e) {    
  19.             logger.info(e);    
  20.             return null;    
  21.         }   
  22.         return url;  
  23.     }  


          1、替换咨询内容图片方法

         

  1. /** 
  2.      * 替换内容中图片地址为本地地址 
  3.      * @param content html内容 
  4.      * @param pic_dir 本地地址文件路径 
  5.      * @return html内容 
  6.      */  
  7.     public static String replaceForNews(String content,String pic_dir){  
  8.         String str = content;  
  9.         String cont = content;  
  10.         while (true) {  
  11.             int i = str.indexOf("src=\"");  
  12.             if (i != -1) {  
  13.                 str = str.substring(i+5, str.length());  
  14.                 int j = str.indexOf("\"");  
  15.                 String pic_url = str.substring(0, j);  
  16.                 //下载图片到本地并返回图片地址  
  17.                 String pic_path = fun.downloadPicForNews(pic_url,pic_dir);  
  18.                 if(StringUtils.isNotEmpty(pic_url) && StringUtils.isNotEmpty(pic_path)){  
  19.                 cont = cont.replace(pic_url, pic_path);  
  20.                 str = str.substring(j,str.length());  
  21.                 }  
  22.             } else{  
  23.                 break;  
  24.             }  
  25.         }  
  26.         return cont;  
  27.     }  


         

  1. /** 
  2.      * 下载图片到本地 
  3.      * @param picUrl 图片Url 
  4.      * @param localPath 本地保存图片地址 
  5.      * @return 
  6.      */  
  7.     public String downloadPicForNews(String picUrl,String localPath){  
  8.         String filePath = "";  
  9.         String url = "";  
  10.         try {    
  11.             URL httpurl = new URL(picUrl);  
  12.            HttpURLConnection urlcon = (HttpURLConnection) httpurl.openConnection();  
  13.            urlcon.setReadTimeout(3000);  
  14.            urlcon.setConnectTimeout(3000);  
  15.            int state = urlcon.getResponseCode(); //图片状态  
  16.            if(state == 200){  
  17.                String fileName = getFileNameFromUrl(picUrl);    
  18.                filePath = localPath + fileName;  
  19.                File f = new File(filePath);    
  20.                FileUtils.copyURLToFile(httpurl, f);   
  21.                Function fun = new Function();  
  22.                url = filePath.replace("/www/web/imgs", fun.getProValue("IMG_PATH"));  
  23.            }  
  24.         } catch (Exception e) {    
  25.             logger.info(e);    
  26.             return null;    
  27.         }   
  28.         return url;  
  29.     }  


     获取文件名称,根绝时间戳自定义

  1. /** 
  2.      * 根据url获取文件名 
  3.      * @param url  
  4.      * @return 文件名 
  5.      */  
  6.     public static String getFileNameFromUrl(String url){    
  7.         //获取后缀  
  8.         String sux = url.substring(url.lastIndexOf("."));  
  9.         if(sux.length() > 4){  
  10.             sux = ".jpg";  
  11.         }  
  12.         int i = (int)(Math.random()*1000);  
  13.         //随机时间戳文件名称  
  14.         String name = new Long(System.currentTimeMillis()).toString()+ i + sux;   
  15.         return name;    
  16.     }  

 

 

  




五、遇到的坑
  1、增量抓取经常遇到这2个异常,如下
        抓取超时:Jsoup 获取页面内容,替换为 httpclient获取,Jsoup去解析

 

 

   页面gzip异常(这个问题特别坑,导致历史、增量抓取数据严重缺失,线上一直有问题)

Center

     解决方案:

                      增加:Site..addHeader("Accept-Encoding", "/")

                      这个是WebMagic的框架源码有点小Bug,如果没有设置Header,默认页面Accept-Encoding为:gzip

       Center

 
   
  2、定时抓取
     由ScheduledExecutorService多线程并行执行任务,替换Timer单线程串行

      原方式代码,如下:

  1. package com.spider.utils;  
  2.   
  3. import java.util.Timer;   
  4. import javax.servlet.ServletContextEvent;  
  5. import javax.servlet.ServletContextListener;  
  6. import com.spider.huanqiu.timer.HQJob1;  
  7. import com.spider.huanqiu.timer.HQJob2;  
  8. import com.spider.huanqiu.timer.HQJob3;  
  9. import com.spider.huanqiu.timer.HQJob4;  
  10. import com.spider.huasheng.timer.HSJob1;  
  11. import com.spider.huasheng.timer.HSJob2;  
  12. /** 
  13.  * 描    述:监听增量抓取Job 
  14.  * 创建时间:2016-11-4 
  15.  * @author Jibaole 
  16.  */  
  17. public class AutoRun implements ServletContextListener {   
  18.   //HS-job   
  19.   private Timer hsTimer1 = null;   
  20.   private Timer hsTimer2 = null;   
  21.   //HQZX-job  
  22.   private Timer hqTimer1 = null;   
  23.   private Timer hqTimer2 = null;   
  24.   private Timer hqTimer3 = null;   
  25.   private Timer hqTimer4 = null;   
  26.     
  27.   public void contextInitialized(ServletContextEvent event) {   
  28.     hsTimer1 = new Timer(true);   
  29.     hsTimer2 = new Timer(true);  
  30.       
  31.     hqTimer1 = new Timer(true);  
  32.     hqTimer2 = new Timer(true);  
  33.     hqTimer3 = new Timer(true);  
  34.     hqTimer4 = new Timer(true);  
  35.     /*  
  36.      * 这里开始循环执行 HSJob()方法了  
  37.      * schedule(param1, param2,param3)这个函数的三个参数的意思分别是:  
  38.      *    param1:你要执行的方法;param2:延迟执行的时间,单位毫秒;param3:循环间隔时间,单位毫秒  
  39.      */   
  40.     hsTimer1.scheduleAtFixedRate(new HSJob1(), 1*1000*60,1000*60*10);  //延迟1分钟,设置没10分钟执行一次  
  41.     hsTimer2.scheduleAtFixedRate(new HSJob2(), 3*1000*60,1000*60*10);  //延迟3分钟,设置没10分钟执行一次  
  42.       
  43.     hqTimer1.scheduleAtFixedRate(new HQJob1(), 5*1000*60,1000*60*10);  //延迟5分钟,设置没10分钟执行一次  
  44.     hqTimer2.scheduleAtFixedRate(new HQJob2(), 7*1000*60,1000*60*10);  //延迟7分钟,设置没10分钟执行一次  
  45.     hqTimer3.scheduleAtFixedRate(new HQJob3(), 9*1000*60,1000*60*10);  //延迟9分钟,设置没10分钟执行一次  
  46.     hqTimer4.scheduleAtFixedRate(new HQJob4(), 11*1000*60,1000*60*10);  //延迟11分钟,设置没10分钟执行一次     
  47.   }   
  48.   public void contextDestroyed(ServletContextEvent event) {   
  49.       System.out.println("=======timer销毁==========");  
  50.     //timer.cancel();   
  51.   }   
  52. }   

 

3、定时多个任务时,使用多线程,遇到某个线程抛异常终止任务

     解决方案:在多线程run()方法里面,增加try{}catch{}

4、通过HttpClient定时获取页面内容时,页面缓存,抓不到最新内容

     解决方案:在工具类请求URL地址后面增加:url+"?date=" + new Date().getTime()

   
六、一些方面的处理    
  1、页面抓取规则调整
     先抓列表,在抓内容;改为 抓取列表的同时,需要获取内容详情
  2、保存数据方式作调整
      先抓取标题等概要信息,保存数据库,然后,更新内容信息,根据业务需求再删除一些非来源文章(版权问题);改为:直接控制来源,得到完整数据,再做批量保存;
 3、页面有一个不想要的内容,处理方法
       注释、JS代码、移除无用标签块  

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java爬虫框架WebMagic的使用总结 的相关文章

  • Python 爬虫获取某贴吧所有成员用户名

    最近想用Python爬虫搞搞百度贴吧的操作 所以我得把原来申请的小号找出来用 有一个小号我忘了具体ID 只记得其中几个字母以及某个加入的贴吧 所以今天就用爬虫来获取C语言贴吧的所有成员 计划很简单 爬百度贴吧的会员页面 把结果存到MySQL
  • 9个爬虫基础实战汇总+4个专业爬虫练手站推荐

    个人主页 互联网阿星 格言 选择有时候会大于努力 但你不努力就没得选 作者简介 大家好我是互联网阿星 和我一起合理使用Python 努力做时间的主人 如果觉得博主的文章还不错的话 请点赞 收藏 留言 支持一下博主哦 行业资料 PPT模板 简
  • 【python爬虫】7.爬到的数据存到哪里?

    文章目录 前言 存储数据的方式 存储数据的基础知识 基础知识 Excel写入与读取 基础知识 csv写入与读取 项目 存储周杰伦的歌曲信息 复习 前言 上一关我们以QQ音乐为例 主要学习了如何带参数地请求数据 get请求 和Request
  • 如何使用webmagic发送post请求,并解析传回的JSON

    以浙江法院公开网的送达公告数据为例 http www zjsfgkw cn TrialProcess NoticeSDList 1 分析页面 看到参数有3个 分别是cbfy pageno和pagesize 传回来的数据是以json形式存在
  • 【python爬虫】1.爬虫基础知识

    文章目录 前言 初识爬虫 什么是爬虫 为什么需要爬虫 明晰路径 浏览器的工作原理 爬虫的工作原理 体验爬虫 requests get Response对象的常用属性 爬虫伦理 总结 前言 很高兴能在这里遇见你 我将会带你学习网络爬虫 我们可
  • 用Python进行网络爬虫和数据分析的初次尝试(一)

    某天突然起了兴致 想知道国内每个成员有多少粉 但不知道应该怎么做 各个应援会论坛的用户数 很多粉也去其它成岩的应援论坛 不靠谱 各个贴吧会员数 这只能说明某个成员是否出名 并且也有和应援论坛相同的弊端 最好的方法是在一个中立 无成员倾向的
  • 从在线字典网站获取词汇释义:一个Python爬虫实战案例

    目录 目录 1 准备工作 2 分析网页结构 3 编写爬虫 4 提取单词信息 5 输出结果
  • python实战-JSON形式爬虫-批量爬取图片并下载

    文章目录 一 前言 二 思路 1 网站返回内容 2 url分页结构 3 根据请求快速构造代码 三 具体代码的实现 四 总结 一 前言 上一篇文章已经对html形式的爬虫进行实战 批量爬取电影下载链接 接下来将实战json形式爬虫 批量爬取并
  • 使用多线程或异步技术提高图片抓取效率

    导语 图片抓取是爬虫技术中常见的需求 但是图片抓取的效率受到很多因素的影响 比如网速 网站反爬机制 图片数量和大小等 本文将介绍如何使用多线程或异步技术来提高图片抓取的效率 以及如何使用爬虫代理IP来避免被网站封禁 概述 多线程和异步技术都
  • requests.exceptions.SSLError: HTTPSConnectionPool用python挂代理爬国外网站报错

    我想要爬取国外网站信息 但是由于需要长时间挂梯子进行一些交互 因此用python爬取数据时就会报以下错误 我找了好多解决办法 但大多数都不是由于挂代理而引起的 这里我只针对挂代理进行爬取而出现这种报错提供一个解决方法 在代码里加入协议改一下
  • 第14.6节 使用Python urllib.request模拟浏览器访问网页的实现代码

    Python要访问一个网页并读取网页内容非常简单 在利用 第14 5节 利用浏览器获取的http信息构造Python网页访问的http请求头 的方法构建了请求http报文的请求头情况下 使用urllib包的request模块使得这项工作变得
  • python爬取唯品会商品信息

    目录 1 明确需求和抓包思路 2 发送请求 获取数据 3 解析数据 4 保存数据 5 最终效果 1 明确需求和抓包思路 目标 爬取唯品会中泳衣的商品信息 思路 点击F12打开抓包工具 gt 刷新页面 gt 搜索关键字找到我们想要的数据包 并
  • python编程入门书-最适合Python初学者的6本书籍推荐「必须收藏」

    Python是一种通用的解释型编程 主要用于Web开发 机器学习和复杂数据分析 Python对初学者来说是一种完美的语言 因为它易于学习和理解 随着这种语言的普及 Python程序员的机会也越来越大 如果你想学习Python编程 市场上就有
  • 大数据采集概述

    文章目录 大数据采集概述 1 互联网大数据与采集 1 1互联网大数据来源 1 社交媒体 2 社交网络 3 百科知识库 4 新闻网站 5 评论信息 6 位置型信息 1 2 互联网大数据的特征 1 大数据类型和语义更加丰富 2 数据的规范化程度
  • python爬虫程序之百度翻译,pyexecjs模块的用法(python里的js解析库)

    目录 百度翻译爬虫程序 1 需求分析 2 URL分析 3 难点 请求参数分析 4 如何生成sign值 5 pyexecjs模块 6 程序设计 7 程序改进思路 pyexecjs模块是python爬虫库里关于javaScript的一套程序 它
  • Python爬虫实战之电影爬取过程

    俗话说 兴趣所在 方能大展拳脚 so结合兴趣的学习才能事半功倍 更加努力专心 apparently本次任务是在视频网站爬取一些好看的小电影 地址不放 狗头保命 只记录过程 实现功能 从网站上爬取采用m3u8分段方式的视频文件 对加密的 ts
  • 程序员教你如何用Python爬取付费小说

    小说相信大家都爱看吧一章接一章具有极大的吸引力 看了还想看 当然付费小说价格也不便宜 看到一半突然收费 猝不及防 在我们程序员这里 收费是不存在的 万物皆可爬 什么是网络爬虫 网络爬虫 又被称为网页蜘蛛 网络机器人 在FOAF社区中间 更经
  • 拼多多商品价格监控自动化API接口获取拼多多商品详情数据API接口

    随着电子商务的飞速发展 越来越多的人选择在网上购物 在这个充满竞争的市场中 拼多多以其独特的商业模式和创新的营销手段 迅速崛起成为中国领先的电商平台之一 为了更好地满足消费者的需求 拼多多提供了丰富的API接口 使得开发者可以方便地获取商品
  • 1688买家API接口跨境卖家需要的API接口

    1688作为深耕产业带多年的数字供应链平台 近两年不仅在年轻消费群体中热度飙升 在跨境侧也有不俗表现 11月19日 1688总裁余涌在1688跨境寻源通计划发布会上透露 1688平台拥有100万的源头厂商 每年服务6500万的B类买家 20
  • 【打造优质CSDN热榜评论区】让AI给评论打分!

    大家好啊 我是豆小匠 1 专栏背景 作为CSDN的老用户 自从CSDN强调要打造优质评论区后 热榜的评论区仍旧有进步空间 因此在这个专栏会结合AI 探索一些方法来提高评论区的质量 这个专栏仅为博主的想法 作为技术学习使用 与官方无关联 2

随机推荐

  • C#

    文章目录 简介 方法 备注 简介 unity创建一个相机 想保存相机的图像时 有这样的一段程序 void Awake GetComponent lt gt 物件属性 snapCam GetComponent
  • 代码随想录算法训练营19期第43天

    1049 最后一块石头的重量 II 视频讲解 动态规划之背包问题 这个背包最多能装多少 LeetCode 1049 最后一块石头的重量II 哔哩哔哩 bilibili 代码随想录 初步思路 动态规划 总结 套用01背包 dp j max d
  • python 两个数值互换(一句代码搞定)

    a sire b 23 a b b a print a print b
  • springboot本机启动elasticjob抛出异常HostException(ip is null)

    1 使用的elasticjob版本为3 0 1 2 本机的IPV4在校验isReachable 返回false 可能是使用无线网 导致ip验证问题 3 最后引入Groovy解决 引入包
  • Oracle 视图中出现重复记录(left join)

    Oracle 视图中出现重复记录 问题 解决办法 注意 问题 今天做项目的时候 客户反映页面中出现了重复的数据 经排查后发现前短数据新增的字段 来自于应该新的表 当时是直接使用 left join 左连接的方式对数据进行拼接的 left j
  • (已解决)DeprecationWarning: `np.float` is a deprecated alias for the builtin `float`.

    DeprecationWarning np float is a deprecated alias for the builtin float To silence this warning use float by itself Doin
  • upload-labs-1

    打开第一关 通过查看源码我们可以发现第一关属于前端验证 我们可以将浏览器JS代码禁用掉 禁用JavaScript
  • [图形学] 《Real-Time Rendering》碰撞检测(二)

    reference Real Time Rendering 目录 17 前言 17 1 和射线的碰撞检测 17 2 使用BSP树的动态碰撞检测 17 3 一般层次的碰撞检测 17 3 1 分层的构建 17 3 2 不同层之间的碰撞检测 17
  • 验证码图片实现

    使用验证码进行验证 自动生成验证码 后台实现 package common makeCertPic import java awt Color import java awt Font import java awt Graphics im
  • 第15课:生活中的命令模式——大闸蟹,走起

    用程序来模拟生活 从剧情中思考命令模式 命令模式 命令模式的模型抽象 代码框架 类图 模型说明 实战应用 应用场景 故事剧情 David 听说阿里开了一家实体店 盒马鲜生 特别火爆 明天就周末了 我们一起去吃大闸蟹吧 Tony 吃货 真是味
  • 前端三剑客---HTML&CSS&JavaScript

    HTML CSS JavaScript 1 HTML 1 1 介绍 1 2 快速入门 1 3 基础标签 1 3 1 标题标签 1 3 2 hr标签 1 3 3 字体标签 1 3 4 换行标签 1 3 5 段落标签 1 3 6 加粗 斜体 下
  • diagnose-tools 编译报错

    在 Ubuntu 20 04 4 LTS 环境中 编译diagnose tools 执行make deps时报错 checking whether gcc m32 makes executables we can run no config
  • ValueError: Buffer dtype mismatch, expected ‘unsigned char‘ but got ‘long‘

    在使用pydensecrf进行densecrf时出现ValueError def dense crf img probs n labels 2 h probs shape 0 w probs shape 1 probs np expand
  • NBA GLOSSARY

    NBA 全称 National Basketball Association 美国国家篮球协会 DRAFT draft dr ft n 选秀 R1 Round one 第一轮 St Vincent St Mary HS OH Saint V
  • electron-builder打包过程中报错——网络下载篇(转)

    在electron使用electron builder打包过程中需要用到几个github上的包 但是由于网络原因 会科学上网的同学基本不用看了 下载不下来 导致出错 一 electron v8 2 0 win32 x64 zip 如下图 导
  • MCP4725介绍和STM32模拟IC2驱动

    一 MCP4725 简单总结为下面几个特点 1路DAC输出 12位分辨率 I2C 接口 标准 快速 高速支持 供电电压2 7 5 5 内部EEPROM存储设置 I2C地址可配置 A0 A1 A2内置 默认为 00 二 硬件设计 MCP472
  • torch 测试GPU能否正常使用

    运行程序 import torch print torch cuda is available num gpu 1 Decide which device we want to run on device torch device cuda
  • 介绍D3DPOOL和Lock

    介绍D3DPOOL和Lock 分类 DirectX 2013 02 28 00 21 322人阅读 评论 0 收藏 举报 D3D RUTIME的内存类型 分为3种 VIDEO MEMORY VM AGP MEMORY AM 和SYSTEM
  • 最能感动女人的十大瞬间

    拉着手在街上闲逛 忽然之间 他将她拽停 伸手轻轻地将眼睑下的一根睫毛拨开 她顿感幸福 拨走睫毛不过是弹指之间的小事 却充分说明他对她的注意力100 集中 要不是他喜欢仔细地偷看她 怎能发现刚跌落的一根细小睫毛 没有一个女人 能够抵抗男人如此
  • Java爬虫框架WebMagic的使用总结

    最近 项目做一个公司新闻网站 分为PC 移动端 h5 数据来源是从HSZX与huanqiu2个网站爬取 主要使用Java编写的WebMagic作为爬虫框架 数据分为批量抓取 增量抓取 批量抓当前所有历史数据 增量需要每10分钟定时抓取一次