前言

之前写过一篇用jsoup爬取csdn博客的文章JAVA爬虫挖取CSDN博客文章 ,当时博主还在上一家公司实习,由于公司办公网络需要代理才能访问外网,那一篇的代码逻辑与代理密切相关,可能有些不熟悉jsoup怎么使用的朋友看了会感觉越看越糊涂,且当时以为爬取所有文章需要用到分页,可能会误导读者。所以今天再次整理那个篇博客的思路,在没有代理的网络的环境下实现代码功能,如果你的也是处在代理才能访问外网的网络,那么参考本文最后一段的解决方案。

思路和步骤

还是以《第一行代码–安卓》的作者为例,将他在csdn发表的博客信息都挖取出来,因为郭神是我在大学期间比较崇拜的对象之一。郭神的博客地址为郭霖博客

在动手实验之前,假设你已经基本掌握了如下的技能:JAVA基础编程,简单的正则表达式,JS或者jQuery的编程能力,此外还学过http协议的一些知识。如果你还未掌握正则表达式,可以去我的JAVA正则表达式详解 博客看看,如果你还没有掌握jQuery的基础知识,可以去我的jQuery实战专栏动手实验一番。如果上诉技能你都掌握了,那么就只差一个jsoup了,这个哥们是干嘛使的呢?用一句话来描述:这哥们能使Java程序像jQuery那样的语法来操作html的Dom节点元素,jsoup也有像jQuery一样的选择器功能,比如getElementById,getElemementsByClass等语法与JavaScript像极了,此外jsoup还有select选择器功能。所以,这里只要稍微掌握jsoup语法就可以像JS操作Dom一样的用Java来处理请求到的html网页。jsoup的中文官方教程地址http://www.open-open.com/jsoup/。

工欲善其事必先利其器。开始之前,你应该有一定的工具,比如一款熟悉的ide,用来调试和查看变量。一个web调试工具,如火狐的firebug之类的。总之,就是有一个java web程序员日常开发和调试使用的工具就差不多了。

第一步:新建一个Java Se项目。这个项目如果是一个Maven项目,那么需要添加如下的依赖配置:

<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.10.2</version>
</dependency>

如果这个项目不是Maven项目,那么你需要下载jsoup-1.10.2.jar包,然后在你的项目右键新建一个lib目录,把下载的jar包放进去,并把jar包添加到classpath。

第二步:分析代码编写思路:先创建一个Conection链接,这个链接包含向CSDN服务器发起请求的url地址,userAgent参数,timeOut参数已经Http请求类型等。接着向服务器发送get请求Document doc = conn.get();注意:很多网络原因导致这一步出现异常,比如timeOut时间设置太短也会报错,这里我设置为5000毫秒。如果这一步你的程序没有报错,说明已经获取了请求的html文档。然后我们可以将html的body标签里面的内容赋值给遍历Element数据类型的实例body。处理body标签的内容jsoup正式出场,除了jsoup还会夹杂简单的正则内容。

用firebug可以看到。首页与博客文章相关的内容在这个div class=”list_item_new”标签下面,而这个div下面包含3个div,分别是:div id=”article_toplist” class=”list”表示置顶的文章,div id=”article_list” class=”list”博文列表所在的div,div id=”papelist” class=”pagelist”底下分页信息所在的div。抛开置顶这个div,我们只关注文章列表的div和分页信息div。如果你仔细的分析,那么会发现我们关心的每篇文章而每篇文章的标签如下div:`


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

<div class="list_item article_item"><div class="article_title">   <span class="ico ico_type_Original"></span><h1><span class="link_title"><a href="/guolin_blog/article/details/51336415">Android提醒微技巧,你真的了解Dialog、Toast和Snackbar吗?            </a></span></h1>
</div><div class="article_description">
Dialog和Toast所有人肯定都不会陌生的,这个我们平时用的实在是太多了。而Snackbar是Design Support库中提供的新控件,有些朋友可能已经用过了,有些朋友可能还没去了解。但是你真的知道什么时候应该使用Dialog,什么时候应该使用Toast,什么时候应该使用Snackbar吗?本篇文章中我们就来学习一下这三者使用的时机,另外还会介绍一些额外的技巧...        </div><div class="article_manage"><span class="link_postdate">2016-07-26 07:55</span><span class="link_view" title="阅读次数"><a href="/guolin_blog/article/details/51336415" title="阅读次数">阅读</a>(7458)</span><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></div><div class="clear"></div></div>

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

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;/*** java爬取csdn博客的简单的案例,如果你只爬取某个博主的首页文章,那么参考本程序员* 如果你想爬取某位博主的所有文章,请参考Main.java* @author shizongger* @date 2017/02/09*/
public class Main1 {//需要进行爬取得博客首页
//  private static final String URL = "http://blog.csdn.net/guolin_blog";private static final String URL = "http://blog.csdn.net/sinyu890807/article/list/2";public static void main(String[] args) throws IOException {//获取url地址的http链接ConnectionConnection conn = Jsoup.connect(URL)    //博客首页的url地址.userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.0") //http请求的浏览器设置.timeout(5000)   //http连接时长.method(Connection.Method.GET);  //请求类型是get请求,http请求还是post,delete等方式//获取页面的html文档Document doc = conn.get();Element body = doc.body();//将爬取出来的文章封装到Artcle中,并放到ArrayList里面去List<Article> resultList = new ArrayList<Article>();Element articleListDiv = body.getElementById("article_list");Elements articleList = articleListDiv.getElementsByClass("list_item");for(Element article : articleList){Article articleEntity = new Article();Element linkNode = (article.select("div h1 a")).get(0);         Element desptionNode = (article.getElementsByClass("article_description")).get(0);Element articleManageNode = (article.getElementsByClass("article_manage")).get(0);articleEntity.setAddress(linkNode.attr("href"));articleEntity.setTitle(linkNode.text());articleEntity.setDesption(desptionNode.text());articleEntity.setTime(articleManageNode.select("span:eq(0").text());resultList.add(articleEntity);}//遍历输出ArrayList里面的爬取到的文章System.out.println("文章总数:" + resultList.size());for(Article article : resultList) {System.out.println("文章绝对路劲地址:http://blog.csdn.net" + article.getAddress());}}}

现在可以将当前页数的文章挖掘出来了,但是郭神的技术文章不止一页啊,还要进一步分页挖掘。以前我是想Java的分页思路是怎么写的,我们可以逆着它的分页思路来。但是现在感觉与它怎么分页无关,但是如果你了解Java分页那么更好的理解接下来怎么做。

要想爬取它的所有文章,可以对他的博客每一个页面分别进行请求。
首页地址可以是:

http://blog.csdn.net/guolin_blog

也可以是:

http://blog.csdn.net/guolin_blog/article/list/1

那么第二页以后的url地址如下:

http://blog.csdn.net/guolin_blog/article/list/index

index表示请求的页数。

现在的任务就是来抓取总页数了。来来来,我们用firebug看一看。

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

可以看到总页数位于上诉div下的第一个span标签,幸运的是这个div有一个独一无二的id号,而这个span与div的关系是父节点与子节点的关系,获取图中红圈内字符串的代码是”body.getElementById(“papelist”).select(“span:eq(0)”).text();”。而span标签里面的内容” 100条 共7页”是汉字,空格和数字混合组成,这时候正则表达式闪亮登场。为了选取”共x页”里面的x的值,正则的语法关键代码是:String regex = “.+共(\d+)页”;

至此,就可以将郭霖的csdn技术博客都可以获取了。此时你只需要将得到的信息都封装好,在需要的时候调用就行了。
完整代码如下:
Article.java

/*** 文章的JavaBean.* date:2017-02-09*/
public class Article {/*** 文章链接的相对地址*/private String address;/*** 文章标题*/private String title;/*** 文章简介*/private String desption;/*** 文章发表时间*/private String time;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getDesption() {return desption;}public void setDesption(String desption) {this.desption = desption;}public String getTime() {return time;}public void setTime(String time) {this.time = time;}
}

Main.java

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;import org.jsoup.*;
import org.jsoup.nodes.*;
import org.jsoup.select.*;import com.shizongger.javaspider.Article;/*** @author shizongger* @date 2017/02/09*/
public class Main {private static final String URL = "http://blog.csdn.net/guolin_blog";public static void main(String[] args) throws IOException {Connection conn = Jsoup.connect(URL).userAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0").timeout(5000).method(Connection.Method.GET);Document doc = conn.get();Element body = doc.body();//获取总页数String totalPageStr = body.getElementById("papelist").select("span:eq(0)").text();String regex = ".+共(\\d+)页";totalPageStr = totalPageStr.replaceAll(regex, "$1");int totalPage = Integer.parseInt(totalPageStr);int pageNow = 1;List<Article> articleList = new ArrayList<Article>();for(pageNow = 1; pageNow <= totalPage; pageNow++){articleList.addAll(getArtitcleByPage(pageNow));}//遍历输出博主所有的文章for(Article article : articleList) {System.out.println("文章标题:" + article.getTitle());System.out.println("文章绝对路劲地址:http://blog.csdn.net" + article.getAddress());System.out.println("文章简介:" + article.getDesption());System.out.println("发表时间:" + article.getTime());}}public static List<Article> getArtitcleByPage(int pageNow) throws IOException{Connection conn = Jsoup.connect(URL + "/article/list/" + pageNow).userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.").timeout(5000).method(Connection.Method.GET);Document doc = conn.get();Element body = doc.body();List<Article> resultList = new ArrayList<Article>();Element articleListDiv = body.getElementById("article_list");Elements articleList = articleListDiv.getElementsByClass("list_item");for(Element article : articleList){Article articleEntity = new Article();Element linkNode = (article.select("div h1 a")).get(0);         Element desptionNode = (article.getElementsByClass("article_description")).get(0);Element articleManageNode = (article.getElementsByClass("article_manage")).get(0);articleEntity.setAddress(linkNode.attr("href"));articleEntity.setTitle(linkNode.text());articleEntity.setDesption(desptionNode.text());articleEntity.setTime(articleManageNode.select("span:eq(0").text());resultList.add(articleEntity);}return resultList;}
}

两个注意之处

  1. Conection的timeOut不宜过短。如果把timeOut设置为20毫秒,则会报错。
    Exception in thread “main” java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:527)
    at sun.net.www.http.HttpClient.(HttpClient.java:211)
    at sun.net.www.http.HttpClient.New(HttpClient.java:308)
    at sun.net.www.http.HttpClient.New(HttpClient.java:326)
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1202)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1138)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1032)
    at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:966)
    at org.jsoup.helper.HttpConnectionResponse.execute(HttpConnection.java:651)atorg.jsoup.helper.HttpConnectionResponse.execute(HttpConnection.java:651) at org.jsoup.helper.HttpConnectionResponse.execute(HttpConnection.java:628)
    at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:260)
    at org.jsoup.helper.HttpConnection.get(HttpConnection.java:249)
    at com.shizongger.javaspider.Main1.main(Main1.java:32)

2.当你处于内网时,需要代理才能发送http请求,在Jsoup.connect(URL)之前,你必须设置代理。

        System.setProperty("http.maxRedirects", "50");System.getProperties().setProperty("proxySet", "true");String ip = "代理服务器地址";System.getProperties().setProperty("http.proxyHost", ip);System.getProperties().setProperty("http.proxyPort", "代理的端口");

本文可运行案例托管在免积分下载地址,本文目的用于技术交流,望与天下Coder共勉!

JAVA爬虫挖取CSDN博客文章(续)相关推荐

  1. python爬虫爬取csdn博客专家所有博客内容

    python爬虫爬取csdn博客专家所有博客内容: 全部过程采取自动识别与抓取,抓取结果是将一个博主的所有 文章存放在以其名字命名的文件内,代码如下 #coding:utf-8import urlli ...

  2. C/C++ | Qt 实现爬虫功能,爬取CSDN博客文章

    话不多说,先看程序运行截图: 注意: 本人没有看过爬虫相关的书籍,第一次写这种程序,这个程序是半屌子的,原理很简单,没有学习过爬虫的朋友,也可以写. 程序思路如下: 1.下载要爬网站的页面. 2.用正 ...

  3. 用selenium爬取csdn博客文章,并用4种方法提取数据

    为了方便susu学习selenium,下面代码用selenium爬取博客文章的标题和时间,并用selenium自带的解析,etree,bs4,scrapy框架自带的selector等4种方式来解析网页 ...

  4. 用java爬虫来提高CSDN博客访问量,浏览量

    首先明确一点,采用爬虫来提高访问量,这样是不对滴,同学们请不要使用. 咋们用的java的jsoup来进行爬虫,也可以用http就是代码有点多,咋们省着点来. 一.首先,项目中引入如下jar包,让爬虫变 ...

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

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

  6. 【爬虫+数据可视化】Python爬取CSDN博客访问量数据并绘制成柱状图

    以下内容为本人原创,欢迎大家观看学习,禁止用于商业及非法用途,谢谢合作! ·作者:@Yhen ·原文网站:CSDN ·原文链接:https://blog.csdn.net/Yhen1/article/ ...

  7. 大屏监控系统实战(6)-爬虫初探:爬取CSDN博客之星年度总评选投票统计数据

    一.介绍 我们先来做个简单的,我们的目标是爬取CSDN博客之星年度总评选的首页信息. 首页的地址:http://m234140.nofollow.ax.mvote.cn/wxvote/43ced329 ...

  8. python+shell 备份 CSDN 博客文章,CSDN博客备份工具

    python+shell 备份 CSDN 博客文章,CSDN博客备份工具 在 csdn 写了几年的博客了.多少也积累了两三百篇博文,近日,想把自己的这些文章全部备份下来,于是开始寻找解决方案. 我找到 ...

  9. http://demo.netfoucs.com大量盗取CSDN博客文章,抹去作者版权信息

    有这样一个寄生虫意义的网站,http://demo.netfoucs.com, 自己不创作任何内容,但是全文抓取CSDN博客上的文章,还把原文中作者信息和版权有关的信息抹掉. 这是侵权网站抓取的我的博 ...

  10. CSDN博客文章写作技巧

    CSDN博客文章写作技巧 1. CSDN博客文章段落缩进问题的解决办法 1.1 解决办法   由于在写文档的时候,段落首习惯了缩进两个字符,发现使用 Tab 键无法解决这个问题,同时使用多个空格代替的 ...

最新文章

  1. HDU5982. Relic Discovery
  2. 18.实现标准的Dispose模式
  3. 【转】Android子线程真的不能更新UI么
  4. n分频器 verilog_基于Verilog的分频器实现
  5. 计算机知识应用,计算机知识应用基础复习大纲
  6. 几个 PHP 的“魔术常量”
  7. IT入门?推荐首选学习HTML5大前端
  8. golang使用pprof检查goroutine泄露
  9. 到底是什么反射,泛型,委托,泛型
  10. Matlab-信号处理工具箱
  11. 惠普扫描应用程序当前正由此计算机上的其,惠普打印机 打印扫描的时候显示“由于另一个程序或另一台计算机正在使用联网的HP成像设备因此无法执行”...
  12. 马斯洛提出动机理论_马斯洛的需要层次理论
  13. Qt如何调用xlsl的方法!
  14. 高等数学(预备知识之两角和差、二倍角与半角公式)
  15. 2019 9月 月末总结
  16. rasp 系统_RASP 完爆 WAF 的5大理由!
  17. mysql删除与另外一张表有交集的表的记录
  18. android 横向头像栏,Android实现个人资料页面头像背景模糊显示包(状态栏)
  19. PWM呼吸灯之三角波、锯齿波、正弦函数波
  20. 【SSLGZ 2812】2017年10月30日提高组T2 凤凰院真凶

热门文章

  1. 【PMP】PMBOK 笔记 第10章 项目沟通管理
  2. CSM32RV20开发(二):Si24R1 通信模式调试
  3. python哪里下载-python从哪下载
  4. 小程序上传图片加水印
  5. 【C++】分数加减法
  6. python图片内容长度识别_python 图片中的表格识别
  7. python中的value是什么意思_Python self[name]=value是什么意思?
  8. Android 解决华为手机图片底色变绿问题
  9. Raid5数据恢复算法原理- raid5数据恢复案例
  10. typora的安装和使用