Java爬取CSDN博客

水深无声 2022-08-21 05:51 338阅读 0赞

最近由于要做一个关于技术博客搜索的搜索工具,我开始接触到了爬虫,因为Java学的比较精通(主要是有很多封装的工具包),写了一个小小的Demo,进入主题吧
参开博客链接

  1. 请求的规则,我用的是Jsoup请求网页,它可以在请求时,按照你设置的规则来进行请求,所有要有一个请求规则类,PS:但是后面好像并没有什么用到

规则的父类,一般请求都需要的

  1. package com.lg.po;
  2. import java.io.Serializable;
  3. /** * 规则的父类,一般请求都需要的 * @author LG * */
  4. public class SuperRule implements Serializable{
  5. /** * 网页路径 */
  6. private String url;
  7. /** * GET/POST请求 */
  8. private int requestType = GET;
  9. /** * GET请求方式 */
  10. public final static int GET = 0;
  11. /** * POST请求方式 */
  12. public final static int POST = 1;
  13. /** * 参数集合 */
  14. private String[] params;
  15. /** * 参数对应的值 */
  16. private String[] values;
  17. /** * 对返回的HTML,第一次过滤所使用的标签, */
  18. private String resultTagName;
  19. /** * CLASS / ID / SELECTION * 设置resultTagName的类型,默认为ID */
  20. private int type = ID;
  21. public final static int ID = 0;
  22. public final static int CLASS = 1;
  23. public final static int SELECTION = 2;
  24. public SuperRule(){}
  25. public SuperRule(String url){
  26. this.url = url;}
  27. public SuperRule(String url, int requestType, String[] params, String[] values,
  28. String resultTagName,int type) {
  29. super();
  30. this.url = url;
  31. this.requestType = requestType;
  32. this.params = params;
  33. this.values = values;
  34. this.resultTagName = resultTagName;
  35. this.type = type;
  36. }
  37. //剩下的set,get方法自己脑补
  38. }

解析CSDN博客的规则类

  1. package com.lg.po;
  2. /** * 博客规则类 * @author LG * */
  3. public class BlogRule extends SuperRule{
  4. /** * 用于判断是否从博客空间到某一篇具体的博客,默认false */
  5. private boolean isDirect = false;
  6. /** * 该博客链接的类型,默认BLOG */
  7. private int blogType = BLOG;
  8. /** * HOME我的 SPACE博客空间 BLOG博客 */
  9. public final static int HOME = 0;
  10. public final static int SPACE = 1;
  11. public final static int BLOG = 2;
  12. public BlogRule(){}
  13. public BlogRule(boolean isDirect, int blogType) {
  14. super();
  15. this.isDirect = isDirect;
  16. this.blogType = blogType;
  17. }

2.获取网页的类容,因为向服务器请求的过程中,如果请求的频率和次数都比较高的话,可能遭到别人反爬虫,网上有很多解决反爬的方法,如,降低请求次数,分时段爬取,我这里用的是换代理,一个IP不行了另一个赶紧顶上,免费IP代理地址

  1. package com.lg.utils;
  2. import java.io.IOException;
  3. import java.util.Map;
  4. import java.util.Queue;
  5. import java.util.concurrent.CountDownLatch;
  6. import org.apache.http.HttpEntity;
  7. import org.apache.http.HttpHost;
  8. import org.apache.http.HttpResponse;
  9. import org.apache.http.client.methods.HttpGet;
  10. import org.apache.http.impl.client.CloseableHttpClient;
  11. import org.apache.http.impl.client.HttpClients;
  12. import org.apache.http.util.EntityUtils;
  13. import org.jsoup.Connection;
  14. import org.jsoup.Jsoup;
  15. import org.jsoup.nodes.Document;
  16. import com.lg.filter.DatasBackUp;
  17. import com.lg.po.BlogRule;
  18. import com.lg.po.SuperRule;
  19. /** * 解析网页的工具类 * @author LG * */
  20. public class ParseCommenUtil {
  21. /** * 标识换IP是只能一个线程换 */
  22. private static boolean ischange = true;
  23. /** * 代理IP */
  24. private static String proxyHost = "218.106.96.196";
  25. /** * 代理端口 */
  26. private static int proxyPort = 80;
  27. /** * 下载某个路径的网页 */
  28. public static Document download(SuperRule rule,Queue<String> ipQueue){
  29. Document doc = downloadHttp(rule,ipQueue);
  30. try {
  31. doc.setBaseUri("http://blog.csdn.net");//设置网页的基本路径,因为网页中有的用的是相对路径
  32. } catch (Exception e) {
  33. System.out.println("设置基础URL出错");
  34. }
  35. return doc;
  36. }
  37. /** * 通过HttpClient方式下载网页 * @param rule * @param ipQueue * @return */
  38. public static Document downloadHttp(SuperRule rule,Queue<String> ipQueue){
  39. //通过HttpClient方式在网页
  40. CloseableHttpClient httpClient = HttpClients.createDefault();
  41. HttpGet httpGet = new HttpGet(rule.getUrl());
  42. //这里要设置模拟浏览器登录,要不然直接拒绝你
  43. httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.2)");
  44. httpGet.setHeader("Accept-Language", "zh-cn,zh;q=0.5");
  45. httpGet.setHeader("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
  46. HttpResponse response = null;
  47. while(true){
  48. try {
  49. response = httpClient.execute(new HttpHost(proxyHost, proxyPort),httpGet);
  50. HttpEntity entity = response.getEntity();
  51. return Jsoup.parse(EntityUtils.toString(entity));
  52. } catch (Exception e) { //发生异常换IP
  53. ischange = true;//打开门
  54. chageIP(rule, ipQueue);
  55. }
  56. }
  57. }
  58. /** * 换IP的方法,这里要注意静态变量的线程安全,所有用到了Java中异步的方式 * @param r * @param ipQueue */
  59. public static synchronized void chageIP(SuperRule r,Queue<String> ipQueue){
  60. if(ischange){
  61. //当可以换IP是,一个线程进来,其它线程等待
  62. if (ipQueue.size()>0) {
  63. try {
  64. String ip_port = ipQueue.poll();
  65. String[] ips = ip_port.split(":");
  66. proxyHost = ips[0];
  67. proxyPort = Integer.parseInt(ips[1]);
  68. System.out.println("成功换IP---------------------"+proxyHost);
  69. } catch (Exception e2) {
  70. System.out.println("换IP发生错误");
  71. }
  72. }
  73. ischange = false;//当一个线程换完IP后,其它的线程就不能换了,除非这个IP不能用,关上门
  74. }
  75. }
  76. /** * 输出队列中元素 * @param q */
  77. public static void sop(Queue<BlogRule> q){
  78. BlogRule rule = null;
  79. while((rule=q.poll())!=null){
  80. System.out.println(rule.getUrl());
  81. }
  82. }
  83. /** * 爬取是一个树状的方式,所以会有重复的,这里是通过一个Map来记录已经解析过得URL,用Map是因为HashMap * 是根据哈希表来进行存储数据的,查询的效率高 */
  84. public static boolean isDownloaded(Map<String, Boolean> map,String url){
  85. if(map.get(url)==null){
  86. //如果不在Map中
  87. return false;
  88. }
  89. else {
  90. return true;
  91. }
  92. }
  93. /** * 有时爬取的时候会出现一些错误,或者准备的IP用完了,不得不停止程序,但是存入数据库的解析过的网页数据又不能用,因为会重复, * 所以这里就写了一个把没有处理完的URL和已经处理过的URL写到本地去得方法 * @param queuespace */
  94. public static void writeToLocal(Queue<BlogRule> queue,Queue<BlogRule> queuespace,Map<String, Boolean> map){
  95. CountDownLatch countDownLatch = new CountDownLatch(3);//计数器,只有等这全部写完后,才能运行下面的程序
  96. String basepath = "C:\\Users\\LG\\Desktop\\proxy\\";//存储路径自己定义
  97. new Thread(new DatasBackUp(queue,basepath+"blogurl.txt",countDownLatch)).start();//存取博文的文件
  98. new Thread(new DatasBackUp(queuespace,basepath+"blogspace.txt",countDownLatch)).start();//存取博客空间(这里可以查看博主所有博文)的路径,
  99. new Thread(new DatasBackUp(map,basepath+"blogtemp.txt",countDownLatch)).start();//存取解析过的URL路径
  100. try {
  101. countDownLatch.await();
  102. System.out.println("备份完成");
  103. } catch (Exception e1) {
  104. System.out.println("备份等待时错误");
  105. }
  106. }
  107. }

3.解析博客的主要实现类,包含一个抽象类

  1. package com.lg.parse;
  2. import java.util.Collections;
  3. import java.util.HashMap;
  4. import java.util.LinkedList;
  5. import java.util.Map;
  6. import java.util.Queue;
  7. import java.util.Set;
  8. import java.util.concurrent.ConcurrentLinkedQueue;
  9. import java.util.concurrent.CountDownLatch;
  10. import org.jsoup.nodes.Element;
  11. import org.jsoup.select.Elements;
  12. import com.lg.po.BlogDatas;
  13. import com.lg.po.BlogRule;
  14. import com.lg.utils.ParseCommenUtil;
  15. /** * 解析博客的抽象类 * @author LG * */
  16. public abstract class AbstractBlogParse implements BlogParseable<BlogDatas>{
  17. /** * 检测是否重复的存储单位 */
  18. public static Map<String, Boolean> map = Collections.synchronizedMap(new HashMap<String, Boolean>());
  19. /** * 开启线程 的数量 */
  20. protected int count = 0;
  21. public void setCount(int count) {
  22. this.count = count;
  23. }
  24. /** * 存放代理IP的队列 */
  25. public static Queue<String> ipQueue = new LinkedList<String>();
  26. /** * 待解析的博文链接队列,线程安全 */
  27. public static Queue<BlogRule> queue = new ConcurrentLinkedQueue<BlogRule>();
  28. /** * 带解析的博客空间队列,线程安全 */
  29. public static Queue<BlogRule> queuespace = new ConcurrentLinkedQueue<BlogRule>();
  30. /** * 解析的主要方法,该方法继承自BlogParseable接口,该接口中只有一个parseMain()方法 */
  31. public Set<BlogDatas> parseMain() {
  32. CountDownLatch countDownLatch = new CountDownLatch(count);
  33. for (int i = 0; i < count; i++) { //开启多线程爬取,--------这里是正式开始爬了
  34. new Thread(new MyRunnable(countDownLatch)).start();
  35. }
  36. try {
  37. countDownLatch.await();
  38. } catch (Exception e1) {
  39. System.out.println("countDownLatch发成了异常---计数器");
  40. }
  41. return null;
  42. }
  43. public abstract void parseSpace(BlogRule rule);
  44. public abstract void parseBlog(BlogRule rule);
  45. /** * 遍历博客空间 链接 得到如:http://blog.csdn.net/lmj623565791,存入队列 */
  46. protected void getSpacesUrl(Elements links) {
  47. if (links.size()>0) {
  48. for(Element link:links){
  49. BlogRule br = new BlogRule(link.absUrl("href"),BlogRule.SPACE);
  50. if (!ParseCommenUtil.isDownloaded(map, br.getUrl())) {
  51. queuespace.offer(br);
  52. }
  53. }
  54. }
  55. }
  56. /** * 遍历所有博客,得到如:http://blog.csdn.net/lmj623565791/article/details/50709663,存入队列 */
  57. protected void getBlogsUrl(Elements links) {
  58. if (links.size()>0) {
  59. for(Element link:links){
  60. BlogRule br = new BlogRule();
  61. String url = link.absUrl("href");
  62. if (!ParseCommenUtil.isDownloaded(map, url)) {
  63. br.setUrl(url);
  64. br.setBlogType(BlogRule.BLOG);
  65. br.setIsDirect(true);
  66. queue.offer(br);
  67. }
  68. }
  69. }
  70. }
  71. /** * 解析网页的多线程类 * @author LG * */
  72. class MyRunnable implements Runnable{
  73. private CountDownLatch countdown = null;
  74. public MyRunnable(CountDownLatch countdown){
  75. this.countdown = countdown;
  76. }
  77. public void run() {
  78. BlogRule rule = null;
  79. while(((rule=queue.poll())!=null)||((rule=queuespace.poll())!=null)){
  80. //当解析队列不为空时
  81. System.out.println(queue.size()+"--"+queuespace.size());
  82. //判断博客的类型
  83. switch (rule.getBlogType()){
  84. case BlogRule.BLOG:
  85. parseBlog(rule);
  86. break;
  87. case BlogRule.SPACE:
  88. parseSpace(rule);
  89. break;
  90. }
  91. }
  92. countdown.countDown();
  93. }
  94. }
  95. }
  96. //继承类
  97. package com.lg.parse;
  98. import java.util.regex.Matcher;
  99. import java.util.regex.Pattern;
  100. import org.jsoup.nodes.Document;
  101. import org.jsoup.nodes.Element;
  102. import org.jsoup.select.Elements;
  103. import com.lg.db.OperateDB;
  104. import com.lg.po.BlogRule;
  105. import com.lg.po.SuperRule;
  106. import com.lg.utils.ParseCommenUtil;
  107. import com.lg.utils.TextUtil;
  108. /** * 解析CSDN博客主要类 */
  109. public class CsdnBlogsParse extends AbstractBlogParse{
  110. /** * 记录解析的网页的数量 */
  111. public static int dataCount = 0;
  112. /** * 多久向本地更新一次没有处理完的URL和已经处理完的URL,这里设置的值当存储到数 * 据库的超过500条时,更新一次 */
  113. public static int backTime = 0;
  114. /** * 暂存已经解析的网页数据,用于数据库的插入,可用于多线程 */
  115. private static StringBuffer dataBuffer = new StringBuffer();
  116. public static StringBuffer getDataBuffer() {
  117. return dataBuffer;
  118. }
  119. public static void setDataBuffer(StringBuffer dataBuffer) {
  120. CsdnBlogsParse.dataBuffer = dataBuffer;
  121. }
  122. /** * 解析的某一篇博客的方法 * @param url */
  123. public void parseBlog(BlogRule rule){
  124. if (!ParseCommenUtil.isDownloaded(map, rule.getUrl())) {
  125. //如果url没被访问过
  126. Document doc = ParseCommenUtil.download(rule,ipQueue);
  127. //缩小寻找的范围
  128. Element ele = doc.getElementById("article_details");
  129. if (ele!=null) {
  130. String blog_title = null;//标题
  131. String blog_url = null;//链接
  132. String labels = null;//标签
  133. String readDate = null,reads=null,comments = null;//发布时间
  134. int readTimes = 0;//阅读量
  135. int commentTimes = 0;//评论量
  136. String userClass = null;//分类
  137. Elements title = ele.select("div.article_title > h1 > span > a");
  138. if (title!=null&&title.size()>0) {
  139. blog_title = title.first().ownText();
  140. blog_title = blog_title.replaceAll("'", "\\\\'");
  141. blog_url = title.first().absUrl("href");
  142. }
  143. Elements cate = ele.select("span.link_categories");
  144. if (cate!=null&&cate.size()>0) {
  145. Elements categorys = cate.first().getElementsByTag("a");
  146. if (categorys!=null&&categorys.size()>0) {
  147. String temp = "";
  148. for(Element category:categorys)
  149. temp+= category.text()+",";
  150. labels = temp;
  151. }
  152. }
  153. Elements reads_before = ele.select("div.article_r");
  154. if (reads_before!=null&&reads_before.size()>0) {
  155. readDate = reads_before.first().child(0).text();
  156. reads = reads_before.first().child(1).text();
  157. readTimes = Integer.parseInt(reads.substring(0, reads.indexOf("人")));
  158. comments = reads_before.first().child(2).text();
  159. }
  160. commentTimes = Integer.parseInt(comments.substring(comments.indexOf("(")+1, comments.indexOf(")")));
  161. Elements c = ele.select("div.category_r > label > span");
  162. if (c!=null&&c.size()>0) {
  163. Element classes = c.first();
  164. userClass = classes.ownText();
  165. }
  166. dataBuffer.append("('" +blog_title+"','" +blog_url+ "','" + labels+ "','" +readDate+ "',"+readTimes +"," +
  167. commentTimes +",'" + userClass + "'" +"),");
  168. OperateDB.insert();//如果解析的网页数据已经达到50,开始向数据库存数据
  169. parseComment(doc);
  170. if(!rule.getIsDirect()){
  171. //将该博客空间加入队列
  172. queuespace.offer(new BlogRule("http://blog.csdn.net/"+TextUtil.getUserName(rule.getUrl()),BlogRule.SPACE));
  173. parseHome(doc);
  174. }
  175. }
  176. map.put(rule.getUrl(), true);
  177. }
  178. }
  179. /** * 获取博客空间中所有博客的URL */
  180. public void parseSpace(BlogRule rule){
  181. if (!ParseCommenUtil.isDownloaded(map, rule.getUrl())) {
  182. Document doc = ParseCommenUtil.download(rule,ipQueue);
  183. if (TextUtil.isOpenBlog(doc)&&doc.select("div.article_title")!=null) {
  184. //如果开通了博客
  185. Elements links = doc.select("div.article_title > h1 > span > a");
  186. if (links!=null&&links.size()>0) {
  187. getBlogsUrl(links);
  188. }
  189. parseNextPage(doc);
  190. //左边相关链接
  191. //parseLeftLink(doc);
  192. //我的博客
  193. parseHome(doc);
  194. map.put(rule.getUrl(), true); //将解析过的URL放入Map中
  195. }
  196. }
  197. }
  198. /** * 解析我的个人信息 */
  199. protected void parseHome(Element ele){
  200. String personHome = ele.getElementById("blog_userface").child(0).absUrl("href");
  201. Document doc = ParseCommenUtil.download(new SuperRule(personHome),ipQueue);
  202. Elements relations = doc.select("div.mod_relations");
  203. if (relations!=null&&relations.size()>0) {
  204. Elements persionlinks = relations.first().getElementsByTag("a");
  205. getSpacesUrl(persionlinks);
  206. }
  207. }
  208. /** * 解析左边栏 相关链接 */
  209. protected void parseLeftLink(Element doc) {
  210. Element links_before = doc.getElementById("side");
  211. if (links_before!=null) {
  212. Elements links = links_before.select("ul.panel_body > ul > li > a");
  213. getSpacesUrl(links);
  214. }
  215. }
  216. /** * 解析博客评论人的路径,有问题,有待改进 */
  217. protected void parseComment(Element doc) {
  218. Element links_before = doc.getElementById("comment_list");
  219. if (links_before!=null) {
  220. Elements links = links_before.select("dd.comment_userface > a");
  221. getSpacesUrl(links);
  222. }
  223. }
  224. /** * 解析博客空间中下一页博客URL */
  225. public void parseNextPage(Element doc){
  226. Element pagelists = doc.getElementById("papelist");
  227. if (pagelists!=null) {
  228. String firstUrl = pagelists.select("a").first().absUrl("href");
  229. String nextUrl = firstUrl.split("article/list")[0] + "article/list/";//获取下一页的路径
  230. String pagedesc = pagelists.select("span").first().text();
  231. Pattern pattern = Pattern.compile("([0-9]+).*?([0-9]+)");
  232. Matcher matcher = pattern.matcher(pagedesc.trim());
  233. int pageCount = 0;
  234. while(matcher.find()){
  235. pageCount = Integer.parseInt(matcher.group(2));
  236. }
  237. for (int i = 2; i <= pageCount; i++) {
  238. Document docpage = ParseCommenUtil.download(new SuperRule(nextUrl + i),ipQueue);
  239. getBlogsUrl(docpage.select("div.article_title > h1 > span > a"));
  240. }
  241. }
  242. }
  243. }

4获取基础数据类,爬取数据都要有一个头,这个类就是头

  1. package com.lg.base;
  2. import java.util.Set;
  3. import java.util.concurrent.CountDownLatch;
  4. import org.jsoup.nodes.Document;
  5. import org.jsoup.nodes.Element;
  6. import org.jsoup.select.Elements;
  7. import com.lg.filter.DatasRecover;
  8. import com.lg.parse.AbstractBlogParse;
  9. import com.lg.parse.CsdnBlogsParse;
  10. import com.lg.po.BlogDatas;
  11. import com.lg.po.BlogRule;
  12. import com.lg.utils.ParseCommenUtil;
  13. /** * 获取基础数据的类,以http://blog.csdn.net/index.html为获取基础数据的接口 * @author LG * */
  14. public class CsdnParseIndex extends AbstractBlogParse{
  15. /** * 解析博客空间和个人博客的对象 */
  16. CsdnBlogsParse blogsParse = null;
  17. Document doc = null;
  18. /** * 用户自定义的开始路径,初始化的规则 */
  19. private BlogRule blogrule = null;
  20. public CsdnParseIndex(BlogRule blogrule){
  21. this.blogrule = blogrule;
  22. }
  23. public CsdnParseIndex(){}
  24. public Set<BlogDatas> parseMain() {
  25. //初始化
  26. init();
  27. if (queue.size()<=0||queuespace.size()>0) {
  28. //如果备份中没有数据
  29. if (blogrule==null) {
  30. //按照默认来进行
  31. blogrule = new BlogRule("http://blog.csdn.net/index.html", 3);
  32. parseBlog(null);
  33. parseSpace(null);
  34. //取出下一页数据
  35. for (int count = 2; count < 23; count++) {
  36. String url = "http://blog.csdn.net/index.html?&page="+count;
  37. blogrule.setUrl(url);
  38. parseBlog(null);
  39. }
  40. }
  41. else {
  42. //用户自定义
  43. queue.offer(blogrule);
  44. }
  45. }
  46. blogsParse = new CsdnBlogsParse();
  47. blogsParse.setCount(count);
  48. blogsParse.parseMain();//开始解析
  49. return null;
  50. }
  51. /** * 取出http://blog.csdn.net/index.html左边链接 */
  52. @Override
  53. public void parseSpace(BlogRule rule) {
  54. Element left = doc.select("div.main_left").first();
  55. Elements alives = left.select("dl.alive_user > dt > a");
  56. //取出左边推荐专家
  57. getSpacesUrl(alives);
  58. Elements experts = left.select("dl.experts > dd > ul > li > a");
  59. //取出左边博客专家
  60. getSpacesUrl(experts);
  61. }
  62. /** * 取出http://blog.csdn.net/index.html中间元素 */
  63. @Override
  64. public void parseBlog(BlogRule rule) {
  65. doc = ParseCommenUtil.download(blogrule,null);
  66. Element center = doc.select("div.main_center").first();
  67. Elements links = center.select("div.blog_list > h1");
  68. if (links.size()>0) {
  69. for(Element link:links){
  70. BlogRule br = new BlogRule();
  71. String url = null;
  72. if(link.select("a").size()>1)
  73. url = link.child(1).absUrl("href");
  74. else {
  75. url = link.child(0).absUrl("href");
  76. }
  77. if (!ParseCommenUtil.isDownloaded(map, url)) {
  78. br.setUrl(url);
  79. br.setBlogType(BlogRule.BLOG);
  80. br.setIsDirect(true);
  81. queue.offer(br);
  82. }
  83. }
  84. }
  85. }
  86. /** * 判断是否有没有处理完的URL,如果有,从这里开始,还有就是读取IP地址 */
  87. public void init(){
  88. CountDownLatch countDownLatch = new CountDownLatch(4);
  89. for (int i = 0; i < 4; i++) {
  90. new Thread(new DatasRecover(i, countDownLatch)).start();
  91. }
  92. try {
  93. countDownLatch.await();
  94. System.out.println("数据恢复完成");
  95. } catch (Exception e1) {
  96. System.out.println("备份恢复时错误");
  97. }
  98. }
  99. }

5爬虫类,可以接受任意的基础数据类

  1. package com.lg.spider;
  2. import com.lg.parse.AbstractBlogParse;
  3. import com.lg.parse.BlogParseable;
  4. /** * 爬虫类 * @author LG * */
  5. public class Spider {
  6. /** * 爬虫的数量 */
  7. public int count;
  8. public Spider(int count){
  9. this.count = count;
  10. }
  11. AbstractBlogParse BlogParse = null;
  12. public AbstractBlogParse getBlogParseable() {
  13. return BlogParse;
  14. }
  15. public void setBlogParseable(AbstractBlogParse BlogParse) {
  16. this.BlogParse = BlogParse;
  17. }
  18. /** * 爬取的入口 * @return * @throws Exception */
  19. public String process() throws Exception {
  20. BlogParse.setCount(count);
  21. BlogParse.parseMain();
  22. return null;
  23. }
  24. }

6测试类,

  1. public static void testParseIndex() throws Exception{
  2. String url = "http://blog.csdn.net/sunny2038/article/details/6926079";
  3. BlogRule rule = new BlogRule();
  4. rule.setUrl(url);
  5. rule.setBlogType(2);
  6. Spider spider = new Spider(10);
  7. CsdnParseIndex ci = new CsdnParseIndex();
  8. spider.setBlogParseable(ci);
  9. spider.process();
  10. }

代码有点多,还有其他的类在这里就不贴出来了,给个下载链接,
第一次写博客,排版不好,希望谅解,代码写的不是很好,各位技术大牛们多多指教。

发表评论

表情:
评论列表 (有 0 条评论,338人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JavaCSDN

    最近由于要做一个关于技术博客搜索的搜索工具,我开始接触到了爬虫,因为Java学的比较精通(主要是有很多封装的工具包),写了一个小小的Demo,进入主题吧 [参开博客链接][