开门见山,看看这个教程的主要任务,就去csdn博客,挖取技术文章,我以《第一行代码–安卓》的作者为例,将他在csdn发表的额博客信息都挖取出来。因为郭神是我在大学期间比较崇拜的对象之一。他的csdn首页如下:http://blog.csdn.net/guolin_blog,首页如图:

你需要掌握的技术有:java se,正则表达式,js dom编程思想,jsoup,此外还需要http协议的一些知识。其中其他技术点可能你以前就掌握了,只差一个jsoup了,这个哥们是干嘛使的呢?我用一句话来说,就是Java程序获取html之后,向js,jquery一样来解析dom节点的,很多语法与js/jquery十分的相似,比如getElementById,getElemementsByClass等等语法与js相似极了,此外jsoup还有select选择器功能。所以,这里只要稍微掌握jsoup语法就可以像js操作dom一样的用Java来操作请求到的html网页了。jsoup的官方教程地址:http://www.open-open.com/jsoup/

开始之前,你应该有一定的工具的,不如已经有一款熟练的ide来调试和查看变量,有一个web调试工具,如火狐的firebug之类的,总之,就是有一个java web程序员日常开发和调试使用的工具就差不多了。

第一步:新建一个maven项目。这个maven项目可以是一个java se项目,选择jar包就行了。重点是引入jsoup所需要的jar包。pom.xml配置如下:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  2. <modelVersion>4.0.0</modelVersion>
  3. <groupId>com.shizongger.jsoup</groupId>
  4. <artifactId>jsoup-shizongger</artifactId>
  5. <version>0.0.1-SNAPSHOT</version>
  6. <dependencies>
  7. <dependency>
  8. <!-- jsoup HTML parser library @ http://jsoup.org/ -->
  9. <groupId>org.jsoup</groupId>
  10. <artifactId>jsoup</artifactId>
  11. <version>1.9.2</version>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.apache.httpcomponents</groupId>
  15. <artifactId>httpclient</artifactId>
  16. <version>4.5.1</version>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.mockito</groupId>
  20. <artifactId>mockito-all</artifactId>
  21. <version>1.8.4</version>
  22. </dependency>
  23. <dependency>
  24. <groupId>junit</groupId>
  25. <artifactId>junit</artifactId>
  26. <version>4.12</version>
  27. </dependency>
  28. </dependencies>
  29. <build>
  30. <plugins>
  31. <plugin>
  32. <groupId>org.apache.maven.plugins</groupId>
  33. <artifactId>maven-compiler-plugin</artifactId>
  34. <configuration>
  35. <source>1.6</source>
  36. <target>1.6</target>
  37. </configuration>
  38. </plugin>
  39. </plugins>
  40. </build>
  41. </project>

第二步:新建一个带有main方法的类,当然你也可以不带main方法,不过我只是写一个java se小程序而已。(如果是配置了http代理的,按照这一步:配置http代理,这点很重要,不然请求不到html网页的,我们都知道,我们的浏览器都配置了代理了的,不然根本无法请求到html网页,不信你可以把IE浏览器的代理取消,去浏览百度一下看看)。设置http代理的代码如下:

  1. System.setProperty("http.maxRedirects", "50");
  2. System.getProperties().setProperty("proxySet", "true");
  3. // 如果不设置,只要代理IP和代理端口正确,此项不设置也可以
  4. String ip = "代理服务器地址";
  5. System.getProperties().setProperty("http.proxyHost", ip);
  6. System.getProperties().setProperty("http.proxyPort", "代理的端口");

上面ip是代理的ip地址,端口8080是代理的端口,参考的地方就是自己去IE浏览器的配置查看。

第三步:好了,如果是一般的网站,直接可以发送post或者get请求了,但是csdn还需要在http头发送几个信息,反正之前我没有发送这些头部信息,是请求不到的。用firebug分析数据,如图:

  1. private static final String URL = "http://blog.csdn.net/guolin_blog";
  2. Connection conn = Jsoup.connect(URL)
  3. .userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.")
  4. .timeout(30000)
  5. .method(Connection.Method.GET);

第三步:到这里,可以得到一个Connection了,接着就可以获取一个html文档了。

Document doc = conn.get();



如图,html的内容已经加载进来了。

第四步:用jsoup获取所得到的dom节点,有必须时,还需要用到正则表达式,不过本篇博客不会用到正则。其他任务可能会用到,总之,java爬虫应该经常用到正则表达式的。

我用firebug看到所有的文章,都是显示在<div id="article_list" class="list"></div>内,而每篇文章都是在这个div下面的这个div:<div class="list_item article_item">

,



每篇文章占据的div,完整的html元素如下:

  1. <div class="list_item article_item">
  2. <div class="article_title">
  3. <span class="ico ico_type_Original"></span>
  4. <h1>
  5. <span class="link_title"><a href="/guolin_blog/article/details/51336415">
  6. Android提醒微技巧,你真的了解Dialog、Toast和Snackbar吗?
  7. </a></span>
  8. </h1>
  9. </div>
  10. <div class="article_description">
  11. Dialog和Toast所有人肯定都不会陌生的,这个我们平时用的实在是太多了。而Snackbar是Design Support库中提供的新控件,有些朋友可能已经用过了,有些朋友可能还没去了解。但是你真的知道什么时候应该使用Dialog,什么时候应该使用Toast,什么时候应该使用Snackbar吗?本篇文章中我们就来学习一下这三者使用的时机,另外还会介绍一些额外的技巧... </div>
  12. <div class="article_manage">
  13. <span class="link_postdate">2016-07-26 07:55</span>
  14. <span class="link_view" title="阅读次数"><a href="/guolin_blog/article/details/51336415" title="阅读次数">阅读</a>(7458)</span>
  15. <span class="link_comments" title="评论次数"><a href="/guolin_blog/article/details/51336415#comments" title="评论次数" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_pinglun'])">评论</a>(45)</span>
  16. </div>
  17. <div class="clear"></div>
  18. </div>

仔细分析一下,这个div中涵盖了文章的简介,阅读次数,连接地址等等,总之,这个div才是重头戏要获取的数据都在这呢。

  1. public static List<ArticleEntity> getArtitcleByPage(int pageNow) throws IOException{
  2. Connection conn = Jsoup.connect(URL + "/article/list/" + pageNow)
  3. .userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.")
  4. .timeout(30000)
  5. .method(Connection.Method.GET);
  6. Document doc = conn.get();
  7. Element body = doc.body();
  8. List<ArticleEntity> resultList = new ArrayList<ArticleEntity>();
  9. Element articleListDiv = body.getElementById("article_list");
  10. Elements articleList = articleListDiv.getElementsByClass("list_item");
  11. for(Element article : articleList){
  12. ArticleEntity articleEntity = new ArticleEntity();
  13. Element linkNode = (article.select("div h1 a")).get(0);
  14. Element desptionNode = (article.getElementsByClass("article_description")).get(0);
  15. Element articleManageNode = (article.getElementsByClass("article_manage")).get(0);
  16. articleEntity.setAddress(linkNode.attr("href"));
  17. articleEntity.setTitle(linkNode.text());
  18. articleEntity.setDesption(desptionNode.text());
  19. articleEntity.setTime(articleManageNode.select("span:eq(0").text());
  20. resultList.add(articleEntity);
  21. }
  22. return resultList;
  23. }

现在可以将当前页数的文章挖掘出来了,但是郭神的技术文章不止一页啊。就是传说中的,还要进行分页挖掘,首先我们来看看我们的Java是如何做分页的。虚算法如下:



  1. 分页存储过程或者页面分页中的分页算法:
  2. int pagesize // 每页记录数
  3. int recordcount // 总记录数
  4. int pagecount // 总页数
  5. pagecount=(recordcount+pagesize-1)/pagesize
  6. 此方法得出的结果为实际页码
  7. pagecount=(recordcount-1)/pagesize
  8. 此方法得出的结果为实际页码-1
  9. 注:两个整数相除的结果始终是整数。例如:5除以2的结果为2。若要确定5除以2的余数,请使用modulo运算符(%)。若要获取作为有理数或分数的商,应将被除数或除数设置为floatdouble型。可以通过在数字后添加一个小数点来隐式执行此操作

那么,我们先来获取总记录数,总页数,每页有多少技术文章吧!好在csdn的信息都放在地下的div里面了呢,来来来,我们用firebug看一看。

  1. <div id="papelist" class="pagelist">
  2. <span> 94条 共7页</span><strong>1</strong> <a href="/sinyu890807/article/list/2">2</a> <a href="/sinyu890807/article/list/3">3</a> <a href="/sinyu890807/article/list/4">4</a> <a href="/sinyu890807/article/list/5">5</a> <a href="/sinyu890807/article/list/6">...</a> <a href="/sinyu890807/article/list/2">下一页</a> <a href="/sinyu890807/article/list/7">尾页</a>
  3. </div>

代码如下:

  1. private int totalPage;
  2. private int nowPage;
  3. /**
  4. * despt:分页算法
  5. * @return
  6. * @throws IOException
  7. */
  8. public List<ArticleEntity> goPage() throws IOException{
  9. Connection conn = Jsoup.connect(URL)
  10. .userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.")
  11. .timeout(30000)
  12. .method(Connection.Method.GET);
  13. Document doc = conn.get();
  14. Element body = doc.body();
  15. //获取总页数
  16. String totalPage = body.getElementById("papelist").select("span:eq(0)").text();
  17. String regex = ".+共(\\d+)页";
  18. totalPage = totalPage.replaceAll(regex, "$1");
  19. this.totalPage = Integer.parseInt(totalPage);
  20. this.nowPage = 1;
  21. List<ArticleEntity> list = new ArrayList<ArticleEntity>();
  22. for(nowPage = 1; this.nowPage <= this.totalPage; this.nowPage++){
  23. list.addAll(getArtitcleByPage(this.nowPage));
  24. }
  25. return list;
  26. }

至此,就可以将郭霖的csdn技术博客都可以获取了。此时你只需要将得到的信息都封装好,在需要的时候调用就行了。

完整代码如下:

  1. public class ArticleEntity {
  2. /**
  3. * ���µ�ַ����Ե�ַ
  4. */
  5. private String address;
  6. /**
  7. * ���±���
  8. */
  9. private String title;
  10. /**
  11. * ��������
  12. */
  13. private String desption;
  14. /**
  15. * ����ʱ��
  16. */
  17. private String time;
  18. public String getAddress() {
  19. return address;
  20. }
  21. public void setAddress(String address) {
  22. this.address = address;
  23. }
  24. public String getTitle() {
  25. return title;
  26. }
  27. public void setTitle(String title) {
  28. this.title = title;
  29. }
  30. public String getDesption() {
  31. return desption;
  32. }
  33. public void setDesption(String desption) {
  34. this.desption = desption;
  35. }
  36. public String getTime() {
  37. return time;
  38. }
  39. public void setTime(String time) {
  40. this.time = time;
  41. }
  42. }
  1. import java.io.IOException;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.jsoup.*;
  5. import org.jsoup.nodes.*;
  6. import org.jsoup.select.*;
  7. import com.shizongger.entity.ArticleEntity;
  8. public class MyBlog {
  9. private static final String URL = "http://blog.csdn.net/guolin_blog";
  10. private int totalPage;
  11. private int nowPage;
  12. public static void main(String[] args) {
  13. System.setProperty("http.maxRedirects", "50");
  14. System.getProperties().setProperty("proxySet", "true");
  15. // 如果不设置,只要代理IP和代理端口正确,此项不设置也可以
  16. String ip = "172.17.18.80";
  17. System.getProperties().setProperty("http.proxyHost", ip);
  18. System.getProperties().setProperty("http.proxyPort", "8080");
  19. MyBlog demo = new MyBlog();
  20. try {
  21. List<ArticleEntity> list = demo.goPage();
  22. for(ArticleEntity tmp : list) {
  23. System.out.println("文章地址:" + tmp.getAddress());
  24. System.out.println("文章标题:" + tmp.getTitle());
  25. System.out.println("文章简介:" + tmp.getDesption());
  26. System.out.println("发表时间:" + tmp.getTime());
  27. }
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. /**
  33. * despt:分页算法
  34. * @return
  35. * @throws IOException
  36. */
  37. public List<ArticleEntity> goPage() throws IOException{
  38. Connection conn = Jsoup.connect(URL)
  39. .userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.")
  40. .timeout(30000)
  41. .method(Connection.Method.GET);
  42. Document doc = conn.get();
  43. Element body = doc.body();
  44. //获取总页数
  45. String totalPage = body.getElementById("papelist").select("span:eq(0)").text();
  46. String regex = ".+共(\\d+)页";
  47. totalPage = totalPage.replaceAll(regex, "$1");
  48. this.totalPage = Integer.parseInt(totalPage);
  49. this.nowPage = 1;
  50. List<ArticleEntity> list = new ArrayList<ArticleEntity>();
  51. for(nowPage = 1; this.nowPage <= this.totalPage; this.nowPage++){
  52. list.addAll(getArtitcleByPage(this.nowPage));
  53. }
  54. return list;
  55. }
  56. public static List<ArticleEntity> getArtitcleByPage(int pageNow) throws IOException{
  57. Connection conn = Jsoup.connect(URL + "/article/list/" + pageNow)
  58. .userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.")
  59. .timeout(30000)
  60. .method(Connection.Method.GET);
  61. Document doc = conn.get();
  62. Element body = doc.body();
  63. List<ArticleEntity> resultList = new ArrayList<ArticleEntity>();
  64. Element articleListDiv = body.getElementById("article_list");
  65. Elements articleList = articleListDiv.getElementsByClass("list_item");
  66. for(Element article : articleList){
  67. ArticleEntity articleEntity = new ArticleEntity();
  68. Element linkNode = (article.select("div h1 a")).get(0);
  69. Element desptionNode = (article.getElementsByClass("article_description")).get(0);
  70. Element articleManageNode = (article.getElementsByClass("article_manage")).get(0);
  71. articleEntity.setAddress(linkNode.attr("href"));
  72. articleEntity.setTitle(linkNode.text());
  73. articleEntity.setDesption(desptionNode.text());
  74. articleEntity.setTime(articleManageNode.select("span:eq(0").text());
  75. resultList.add(articleEntity);
  76. }
  77. return resultList;
  78. }
  79. }

在控制台已经输出想要的信息,这里截取一段吧,

  1. 文章地址:/guolin_blog/article/details/51336415
  2. 文章标题:Android提醒微技巧,你真的了解DialogToastSnackbar吗?
  3. 文章简介:DialogToast所有人肯定都不会陌生的,这个我们平时用的实在是太多了。而SnackbarDesign Support库中提供的新控件,有些朋友可能已经用过了,有些朋友可能还没去了解。但是你真的知道什么时候应该使用Dialog,什么时候应该使用Toast,什么时候应该使用Snackbar吗?本篇文章中我们就来学习一下这三者使用的时机,另外还会介绍一些额外的技巧...
  4. 发表时间:2016-07-26 07:55

JAVA爬虫挖取CSDN博客文章的更多相关文章

  1. Python爬虫简单实现CSDN博客文章标题列表

    Python爬虫简单实现CSDN博客文章标题列表 操作步骤: 分析接口,怎么获取数据? 模拟接口,尝试提取数据 封装接口函数,实现函数调用. 1.分析接口 打开Chrome浏览器,开启开发者工具(F1 ...

  2. Python爬取CSDN博客文章

    0 url :http://blog.csdn.net/youyou1543724847/article/details/52818339Redis一点基础的东西目录 1.基础底层数据结构 2.win ...

  3. Hello Python!用 Python 写一个抓取 CSDN 博客文章的简单爬虫

    网络上一提到 Python,总会有一些不知道是黑还是粉的人大喊着:Python 是世界上最好的语言.最近利用业余时间体验了下 Python 语言,并写了个爬虫爬取我 csdn 上关注的几个大神的博客, ...

  4. Python爬虫抓取csdn博客

    昨天晚上为了下载保存某位csdn大牛的所有博文,写了一个爬虫来自己主动抓取文章并保存到txt文本,当然也能够 保存到html网页中. 这样就能够不用Ctrl+C 和Ctrl+V了,很方便.抓取别的站点 ...

  5. python 爬虫 爬取序列博客文章列表

    python中写个爬虫真是太简单了 import urllib.request from pyquery import PyQuery as PQ # 根据URL获取内容并解码为UTF-8 def g ...

  6. 利用爬虫爬取指定用户的CSDN博客文章转为md格式,目的是完成博客迁移博文到Hexo等静态博客

    文章目录 功能 爬取的方式: 设置生成的md文件命名规则: 设置md文件的头部信息 是否显示csdn中的锚点"文章目录"字样,以及下面具体的锚点 默认false(因为csdn中是集 ...

  7. windows下使用python的scrapy爬虫框架,爬取个人博客文章内容信息

    scrapy作为流行的python爬虫框架,简单易用,这里简单介绍如何使用该爬虫框架爬取个人博客信息.关于python的安装和scrapy的安装配置请读者自行查阅相关资料,或者也可以关注我后续的内容. ...

  8. Python 爬取CSDN博客频道

    初次接触python,写的很简单,开发工具PyCharm,python 3.4很方便 python 部分模块安装时需要其他的附属模块之类的,可以先 pip install wheel 然后可以直接下载 ...

  9. CSDN博客文章的备份及导出电子书CHM

    需要用到的工具集合下载:http://download.csdn.net/source/2881423 在CSDN.百度等写博客文章的应该很多,很多时候担心服务器有一天突然挂了,或者担心自己的号被封了 ...

随机推荐

  1. js获取本机的外网/广域网ip地址

    完整源代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...

  2. javascript中关于数组的一些鄙视题

    一.判断一个数组中是否有相同的元素 /* * 判断数组中是否有相同的元素的代码 */ // 方案一 function isRepeat1(arrs) { if(arrs.length > 0) ...

  3. [deviceone开发]-do_Dialog的基本使用示例

    一.简介 我们平常使用do_Notification的alert或者confirm都是比较简单弹窗. 更为复杂和个性化的弹窗需要用到do_Dialog, 它可以弹出一个自定义的窗口,窗口里的内容是你自 ...

  4. Navicat for Oracle实现连接Oracle

    不知道为什么,从一开始,我就不喜欢Oracle,名字好听,功能强大,但总感觉"高不可攀";或许是因为我觉得其他的数据库就可以解决数据问题,不太了解Oracle的优势:而且它长得也不 ...

  5. VMware虚拟机无法访问外网

    1.环境条件 2.VMware检查 3.虚拟机检查 1) vi /etc/sysconfig/network ----------------------------- NETWORKING=yes ...

  6. Javascript 中的window.parent ,window.top,window.self 详解

    在应用有frameset或者iframe的页面时,parent是父窗口,top是最顶级父窗口(有的窗口中套了好几层frameset或者iframe),self是当前窗口, opener是用open方法 ...

  7. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q75-Q77)

    Question 75You are designing a feature for a SharePoint 2010 solution that will be activated by defa ...

  8. [Android]仿新版QQ的tab下面拖拽标记为已读的效果

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4182929.html 可拖拽的红点,(仿新版QQ,tab下面拖 ...

  9. JavaScript学习11 数组排序实例

    JavaScript学习11 数组排序实例 数组声明 关于数组对象的声明,以前说过:http://www.cnblogs.com/mengdd/p/3680649.html 数组声明的一种方式: va ...

  10. Android之手机向导以及设置中心模块的开发

    当我们使用的新的软件的时候,我们首先需要教用户如何使用我们的软件,当用户学习完使用教程,下次再登录的时候,我们应该直接跳到我们的功能界面,下面我来展示一下我学习视频做的效果图:手机防盗这个功能模块就是 ...