博客数据抓取

要求:抓取博客的粉丝数、关注数、圆龄、文章数、阅读数、评论数、积分、排名、推荐数、反对数等数据。

首先,来看下标准的博客界面,博客首页含有昵称、圆龄、粉丝、关注以及随笔、文章、评论等数据。

右键页面,审查元素,可以看到以下HTML代码。

1 <div id="blog-news">
2     <div id="profile_block">
3         昵称:<a href="http://home.cnblogs.com/u/giiku/">Giiku</a><br>
4         园龄:<a href="http://home.cnblogs.com/u/giiku/" title="入园时间:2015-07-18">1天</a><br>
5         粉丝:<a href="http://home.cnblogs.com/u/giiku/followers/">0</a><br>
6         关注:<a href="http://home.cnblogs.com/u/giiku/followees/">0</a>
7         <div id="p_b_follow"></div>
8     </div>
9 </div>                  

那么既然可以从HTML里面看到页面的数据,那么是否我们只要获取该页面的HTML文本,就可以抓取这些数据呢?

通过URL,先读取一下http://www.cnblogs.com/giiku/的html文本。

            //打开URL
            URL myURL = new URL(url);
            URLConnection conn = myURL.openConnection();
            //获取输入流
            InputStream in = (InputStream) conn.getContent();
            BufferedReader buf = new BufferedReader(new InputStreamReader(in,
                    "UTF-8"));
            String line = "";
            StringBuilder html = new StringBuilder();
            //获取html文本
            while ((line = buf.readLine()) != null) {
                html.append(line);
            }

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8"/>
<title>Giiku - 博客园</title>
<link type="text/css" rel="stylesheet" href="/bundles/blog-common.css?v=VDh8zSH1vx51MDqRT7hK220akQ58FjlaaeGuWBPhfOA1"/>
<link id="MainCss" type="text/css" rel="stylesheet" href="/skins/Custom/bundle-Custom.css?v=Z683z9azGWin6jOfOyAHK6FgPVxm_nmCnl3EFztc2eE1"/>
<link title="RSS" type="application/rss+xml" rel="alternate" href="http://www.cnblogs.com/giiku/rss"/>
<link title="RSD" type="application/rsd+xml" rel="EditURI" href="http://www.cnblogs.com/giiku/rsd.xml"/>
<link type="application/wlwmanifest+xml" rel="wlwmanifest" href="http://www.cnblogs.com/giiku/wlwmanifest.xml"/>
<script src="http://common.cnblogs.com/script/jquery.js" type="text/javascript"></script>
<script type="text/javascript">var currentBlogApp = ‘giiku‘, cb_enable_mathjax=false;</script>
<script src="/bundles/blog-common.js?v=FPlxjK7DBkhdjUge-xvpcctYZfiyO32cepQZO-j3WJk1" type="text/javascript"></script>
</head>
<body>
<a name="top"></a>

<!--done-->
<div id="home">
<div id="header">
    <div id="blogTitle">
    <a id="lnkBlogLogo" href="http://www.cnblogs.com/giiku/"><img id="blogLogo" src="/Skins/custom/images/logo.gif" alt="返回主页" /></a>            

<!--done-->
<h1><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/giiku/">Giiku</a></h1>
<h2></h2>

    </div><!--end: blogTitle 博客的标题和副标题 -->
    <div id="navigator">

<ul id="navList">
<li><a id="MyLinks1_HomeLink" class="menu" href="http://www.cnblogs.com/">博客园</a></li>
<li><a id="MyLinks1_MyHomeLink" class="menu" href="http://www.cnblogs.com/giiku/">首页</a></li>
<li><a id="MyLinks1_NewPostLink" class="menu" rel="nofollow" href="http://i.cnblogs.com/EditPosts.aspx?opt=1">新随笔</a></li>
<li><a id="MyLinks1_ContactLink" class="menu" rel="nofollow" href="http://msg.cnblogs.com/send/Giiku">联系</a></li>
<li><a id="MyLinks1_Syndication" class="menu" href="http://www.cnblogs.com/giiku/rss">订阅</a>
<!--<a id="MyLinks1_XMLLink" class="aHeaderXML" href="http://www.cnblogs.com/giiku/rss"><img src="http://www.cnblogs.com/images/xml.gif" alt="订阅" /></a>--></li>
<li><a id="MyLinks1_Admin" class="menu" rel="nofollow" href="http://i.cnblogs.com/">管理</a></li>
</ul>
        <div class="blogStats">

<!--done-->
随笔- 0&nbsp;
文章- 0&nbsp;
评论- 0&nbsp;

        </div><!--end: blogStats -->
    </div><!--end: navigator 博客导航栏 -->
</div><!--end: header 头部 -->

<div id="main">
    <div id="mainContent">
    <div class="forFlow">

<!--done-->

    </div><!--end: forFlow -->
    </div><!--end: mainContent 主体内容容器-->

    <div id="sideBar">
        <div id="sideBarMain">

<!--done-->
<div class="newsItem">
<h3 class="catListTitle">公告</h3>
    <div id="blog-news"></div><script type="text/javascript">loadBlogNews();</script>
</div>

            <div id="blog-calendar" style="display:none"></div><script type="text/javascript">loadBlogDefaultCalendar();</script>

            <div id="leftcontentcontainer">
                <div id="blog-sidecolumn"></div><script type="text/javascript">loadBlogSideColumn();</script>
            </div>

        </div><!--end: sideBarMain -->
    </div><!--end: sideBar 侧边栏容器 -->
    <div class="clear"></div>
    </div><!--end: main -->
    <div class="clear"></div>
    <div id="footer">

<!--done-->
Copyright &copy;2015 Giiku
    </div><!--end: footer -->
</div><!--end: home 自定义的最大容器 -->
</body>
</html>

html

通过读取的html文本发现,访问该URL,服务器反馈给我们的信息,只有一部分数据,根本不存在圆龄、粉丝、关注等数据。原因在于这些数据是通过异步加载的方式读取的,所以只需要知道对应加载的URL链接,就可以获取这些数据。使用谷歌浏览器,右键审查元素,点击Network,就可以看到访问博客首页时,对资源的请求情况。

从上图,可以发现访问http://www.cnblogs.com/mvc/blog/news.aspx?blogApp=giiku该地址,服务器将会提供园龄、粉丝、关注等数据。现在分析下该URL,该URL是由"http://www.cnblogs.com/mvc/blog/news.aspx?blogApp="以及用户账号组合而成的。那么相当于只要我们知道用户的账号,我们就可以获取这部分数据。

假设已经获取到该页面的文本了,那么现在开始对文本数据进行处理,提取出需要的数据。

1 <div id="blog-news">
2     <div id="profile_block">
3         昵称:<a href="http://home.cnblogs.com/u/giiku/">Giiku</a><br>
4         园龄:<a href="http://home.cnblogs.com/u/giiku/" title="入园时间:2015-07-18">1天</a><br>
5         粉丝:<a href="http://home.cnblogs.com/u/giiku/followers/">0</a><br>
6         关注:<a href="http://home.cnblogs.com/u/giiku/followees/">0</a>
7         <div id="p_b_follow"></div>
8     </div>
9 </div>  

先需要设置几个关键字,来定位下数据的大概位置以及判断是否存在该数据。这里选取“入园时间”、“followers”、“followees”作为关键字。

通过关键字定位到大概位置,再找到开口<a>的结束位置以及闭合</a>的位置,这样就可以获取到标签a的文本内容了。

    public String getAContent(String html, String keyword){
        int index = html.indexOf(keyword);
        index = html.indexOf(">", index);
        html = html.substring(index+1, html.indexOf("</a>", index));
        return html;
    }

现在我们来获取文章数、阅读数、评论数、积分、排名、推荐数、反对数等数据。

关于文章数,刚才上文在也看到了,博客首页是有显示文章数的,是可以直接抓取下来的。但是存在一个问题,由于大家的BLOG页面布局都不同,在你的BLOG里可能显示文章-0,而在他的BLOG里可能就Article-0。对于“文章”这一名词有很多的表示方法,所以如何确定关键字就成了一个问题。同时阅读数、评论数、推荐数及反对数需要我们到具体的文章里面去查看,然后进行总计。那么我们就必须要准备一个List来存放该博客所有的文章的链接,然后通过访问每一个链接,获取数据。这里我们新建一个实体类Article,存放文章的URL、文章的阅读数、评论数、推荐数、反对数。

现在来考虑下如何获取所有文章的链接?这里获取的方式有很多种,我来介绍一下,我发现的一种。

随便打开一个博客,进入首页,你会发现首页会陈列最新的几篇博文,如果博主博文比较多的话,提供了一个分页的机制。点击“下一页”,然后在第二页里就会显示该博主共有几页博文。现在看下该URL:http://www.cnblogs.com/huxiao-tee/default.html?page=2。page=2表示了现在查看的是第二页,现在改下数据,改成page=1。相当于回到了首页,也不显示共几页博文了。那么我们知道了,在博文的第二页,我们可以看到博主共有几页博文。如果该博主只有一页博文呢?我们令page=2会怎样的?通过实践观察发现,如果指定的page页数大于实际存在的页面,那么显示的页面就是博文的第一页。然后博文第一页是没有显示博主共几页的博文的。通过这一发现,我们可以访问每个博客第二页的URL,如果能获取到“共x页”的数据,那么就获得了所有文章的页数了。如果不能获取该数据,说明文章只有一页(甚至连一页也没有,当然也包括在一页的情况中)。

    //获取页数
    public int getPages(String html){
        int index = html.indexOf(PAGES);
        System.out.println(index);
        if(index == -1){
            return 1;//不一定是0 可能是1
        }
        int begin = html.indexOf("共", index);
        int end = html.indexOf("页", begin);
        System.out.println(html);
        String str = html.substring(begin+1, end);
        return Integer.parseInt(str);
    }

现在知道了页数这个数据了该如何利用呢?首先这个URL:http://www.cnblogs.com/huxiao-tee/default.html?page=2的变量是页数,如果我们知道了总页数,就可以获取第一页到最后一页的URL的数据。通过这些URL,就可以抓取每一页文章的链接了,然后就可以获得所有文章的链接,相当于也知道了文章的数量。这里怎么抓取文章链接,具体做法跟上面差不多,根据关键字定位,获取相应的数据。

现在来讲下,如果获取文章的阅读数、评论数、推荐数、反对数的数据。

通过读取文章的URL,获取文本的html发现,这部分数据也是通过异步加载的。直接读取文章的URL,是获得不了这部分数据的。到谷歌浏览器的控制台里查看,发现

http://www.cnblogs.com/mvc/blog/ViewCountCommentCout.aspx?postId=4590118 返回了阅读数

http://www.cnblogs.com/mvc/blog/GetComments.aspx?postId=4590118&blogApp=huxiao-tee&pageIndex=0&anchorCommentId=0&_=1437286041334 返回了关于评论的json其中包括评论数

http://www.cnblogs.com/mvc/blog/BlogPostInfo.aspx?blogId=166017&postId=4590118&blogApp=huxiao-tee&blogUserGuid=63156ca7-762b-e311-8d02-90b11c0b17d6&_=1437286041383 返回了包含推荐数、反对数信息的页面

URL都是常量和变量组合而成的,变量相当于请求参数。我们只要知道这些请求参数,就可以获取这些数据。通过观察URL,我们需要postId(文章编号)、blogApp(用户名)、blogUserGuid(用户唯一标识)、blogId(博客编号)。第二个URL中包含pageIndex=0&anchorCommentId=0这两个参数,这里仅仅获取评论数的话,都默认为0就可以了。然后还有一个变量时没有名字,第二个URL中是_=1437286041334,第三个URL中是_=1437286041383,那么这个数据是什么呢?其实是一个long类型的时间,表示当前请求数据的时间 ,以便返回最新的数据。所以我们总共需要postId、blogApp、blogUserGuid 、time这4项数据。time的话,可以通过new Date()然后转换成long类型来获取。postId、blogApp、BlogUserGuid可以通过文章的URL中获取,其中blogApp、BlogUserGuid只需要获取一次,因为一个博客里面他们是唯一的。

任意一篇文章中都包含以下JS,其中包括了cb_blogId、cb_blogApp、cb_blogUserGuid、cb_entryId变量。通过发现比较就可以知道cb_entryId就是postId,文章的URL中其实也包含了postId。那么这些请求参数,我们都知道了。现在就可以通过编码,获取这些参数,然后再根据参数构建URL,到指定的页面中抓取数据。

    <script type="text/javascript">var allowComments=true,isLogined=true,cb_blogId=166017,cb_entryId=4590118,cb_blogApp=currentBlogApp,cb_blogUserGuid=‘63156ca7-762b-e311-8d02-90b11c0b17d6‘,cb_entryCreatedDate=‘2015/6/20 4:04:00‘;loadViewCount(cb_entryId);</script>
时间: 2024-10-14 00:08:53

博客数据抓取的相关文章

博客数据抓取总结

今天下午的总结让我发现了自己的几个缺点,立此为证,以求改变. 第一点,事前观察不够仔细.事先在源代码上发现了几个数据就急着着手去做,没有观察完所有的数据,导致做到一半才发现有些是js代码执行后才出现的数据,与一般静态源代码的数据的抓取方式不同. 第二点,坚持耐性尚缺.遇到了因为版本问题等而导不出数据到Excel,动态数据抓取不了,网站各种标记不同等问题,而暂时放弃去做另外的项目.其实这个时候我还有更好的解决方案,就是求助老师.这也就是我的第三点,要记得在关键时候适当得求助别人,不管是老师还是同学

[搬运自我的CSDN博客] python抓取javascript动态生成HTML内容的实践

<注:CSDN博客在美国访问特别卡,所以转移到cnblogs来发文章> 本实验在Ubuntu14.04上完成.使用的浏览器是火狐(Firefox 33.0),python版本是2.7.6. 大家都知道用urllib配合正则表达式抓取静态HTML的内容很方便,但是如果网页中有javascript动态生成的内容,urllib就无能为力了. 此时我们要借助一个额外的工具:selenium.它的工作原理是操纵(火狐)浏览器浏览目标网页,等待网页中的javascript全部执行完毕后再对HTML源码进行

利用Selenium制作python数据抓取,以及对Selenium资源介绍

当当当~第三篇博客开始啦~ 这次的话题是数据抓取.终于到了核心部分的探讨,我的心情也是非常激动啊!如果大家baidu或者google(如果可以的话)数据抓取或者data crawling,将会找到数以千计的例子.但是大多数的代码非常的冗长,并且许多代码还是抓取静态数据之后,对动态JS写成的数据却毫无办法.或者,利用HTML解析网址后,再找到JS写的数据页面来寻找到所想要的数据. 但是!不知各位是否有发现过,如果打开chrome或者safari或者各种浏览器的审查元素.网页上能看到的数据,其实都会

Phantomjs+Nodejs+Mysql数据抓取(2.抓取图片)

概要 这篇博客是在上一篇博客Phantomjs+Nodejs+Mysql数据抓取(1.抓取数据) http://blog.csdn.net/jokerkon/article/details/50868880 后进行的第二部分,请各位读者在看这篇博客之前先浏览上一篇,因为这里面有部分代码会沿用到上一部分的抓取结果. 好,现在开始正式的抓取图片的讲解 首先,我们先来看看代码: var page =require('webpage').create(); var address='http://pro

C# 微信 生活助手 空气质量 天气预报等 效果展示 数据抓取 (一)

第一次在博客园写博客写的不好,大家见谅.最近工作辞了,然后感冒发烧输了一个星期的液,感觉很烦躁,心情不是很好,在帝都感觉压力大,废话不说了开始正题把! 还没有完全完成,后续考虑开源! 可以关注微信公众帐号体验一下先看下 效果把 先介绍下工具 我用的有 httpwatch,fiddler 国家环保部的数据链接 http://datacenter.mep.gov.cn/report/air_daily/airDairyCityHour.jsp 原以为直接get请求就可以了 试了下 发现没有获取了 然

Twitter数据抓取

说明:这里分三个系列介绍Twitter数据的非API抓取方法,内容主要来自于Tom Dickinson的博客. Tom Dickinson Milton Keynes,I am currently a PhD student at KMI, currently researching extraction of memorable events from social media. My areas of expertise lie in data mining, machine learnin

【转载】国内网站博客数据统计选免费Google Analytics还是百度统计

[转载]国内网站博客数据统计选免费Google Analytics还是百度统计 Google Analytics谷歌统计是我用的第一个网站统计工具,当然现在也一直在用.Google Analytics凭借其强大的功能和超强的稳定性.快速的反应能力.广泛的数据应用功能,受到了广大站长的追捧. 使用Google Analytics的站长们应该不在少数吧,每天登录Google Analytics免费网站上查看网站的流量也是我们这些站长们必须做的事情,认真分析Google Analytics当中的数据信

网络爬虫+HtmlAgilityPack+windows服务从博客园爬取20万博文

网络爬虫+HtmlAgilityPack+windows服务从博客园爬取20万博文 1.前言 最新在公司做一个项目,需要一些文章类的数据,当时就想到了用网络爬虫去一些技术性的网站爬一些,当然我经常去的就是博客园,于是就有下面的这篇文章. 2.准备工作 我需要把我从博客园爬取的数据,保存起来,最好的方式当然是保存到数据库中去了,好了我们先建一个数据库,在来一张表,保存我们的数据,其实都很简单的了啊,如下图所示 BlogArticleId博文自增ID,BlogTitle博文标题,BlogUrl博文地

大数据抓取采集框架(摘抄至http://blog.jobbole.com/46673/)

摘抄至http://blog.jobbole.com/46673/ 随着BIG DATA大数据概念逐渐升温,如何搭建一个能够采集海量数据的架构体系摆在大家眼前.如何能够做到所见即所得的无阻拦式采集.如何快速把不规则页面结构化并存储.如何满足越来越多的数据采集还要在有限时间内采集.这篇文章结合我们自身项目经验谈一下. 我们来看一下作为人是怎么获取网页数据的呢? 1.打开浏览器,输入网址url访问页面内容.2.复制页面内容的标题.作者.内容.3.存储到文本文件或者excel. 从技术角度来说整个过程