CSDN爬虫(五)——CSDN用户(所有)爬取+常用爬虫正则整理

CSDN爬虫(五)——CSDN用户(所有)爬取+常用爬虫正则整理

说明

  • 开发环境:jdk1.7+myeclipse10.7+win74bit+mysql5.5+webmagic0.5.2+jsoup1.7.2
  • 爬虫框架:webMagic
  • 建议:建议首先阅读webMagic的文档,再查看此系列文章,便于理解,快速学习:http://webmagic.io/
  • 开发所需jar下载(不包括数据库操作相关jar包):点我下载
  • 该系列文章会省略webMagic文档已经讲解过的相关知识。

概述

  • 我们会从CSDN个人中心出发,首先爬取一个用户的个人信息。然后根据该用户的好友关系去爬取好友信息。依次类推,爬取所用用户。
  • 爬取CSDN所有用户是根据“粉丝、关注”去爬取“粉丝、关注”,必然会涉及到“死循环”。到后期肯定会出现大量“脏数据”(重复数据),就要考虑到过滤脏数据的问题。
  • 虽然用webMagic框架爬虫会用到大量的正则表达式,并且爬虫类的正则在网上也很少能找到资料,但是也是比较固定。

CSDN用户(所有)爬取代码预览

package com.wgyscsf.spider;

import java.util.List;

import org.jsoup.select.Elements;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;

import com.wgyscsf.utils.MyStringUtils;

/**
 * @author 高远</n>
 * 编写日期   2016-9-24下午7:25:36</n>
 * 邮箱  wgyscsf@163.com</n>
 * 博客  http://blog.csdn.net/wgyscsf</n>
 * TODO</n>
 */
public class CsdnMineSpider implements PageProcessor {
    private final String TAG = CsdnMineSpider.class.getSimpleName();
    private Site site = Site
            .me()
            .setDomain("my.csdn.net")
            .setSleepTime(1000)
            // 便于测试,休眠较长时间。
            .setUserAgent(
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31");

    @Override
    public void process(Page page) {
        // 列表页: 这里进行匹配,匹配出列表页进行相关处理。
        if ((page.getUrl()).regex("http://my.csdn.net/\\w+").match()) {
            // 获取最外层节点
            // TODO:应该是get(1),不知道为什么
            Elements mainElements = page.getHtml().getDocument()
                    .getElementsByTag("div").get(2).children();
            // 个人资料
            Elements profileElements = mainElements.get(0).getElementsByTag(
                    "div");
            // 个人技能
            Elements skillElements = mainElements.get(1)
                    .getElementsByTag("div");
            // 关系模块:关注和被关注
            Elements relationElements = mainElements.get(2).getElementsByTag(
                    "div");

            // 获取用户id
            String id_mine = MyStringUtils.getLastSlantContent(skillElements
                    .get(0).getElementsByTag("a").get(0).attr("href"));
            // 开始获取个人资料
            String headImg = profileElements.get(0)
                    .getElementsByClass("person-photo").get(0)
                    .getElementsByTag("img").attr("src");
            String fansNums = profileElements.get(0)
                    .getElementsByClass("fans_num").get(0)
                    .getElementsByTag("b").get(0).text();
            String nickname = profileElements.get(0)
                    .getElementsByClass("person-nick-name").get(0)
                    .getElementsByTag("span").get(0).text();
            // 这里只能精确到个人资料,没法继续分,因为好多用户该栏目只填写部分内容
            String personDetail = profileElements.get(0)
                    .getElementsByClass("person-detail").get(0).text();

            // 开始组织个人资料,保存数据操作
            System.out.println(TAG + ":用户id:" + id_mine + ",昵称:" + nickname
                    + ",粉丝:" + fansNums + ",个人资料概述:"
                    + personDetail + ",其它信息....");

            // 当前爬取页面信息爬取结束,将当前页面设置为“跳过”,下次再加入爬虫队列,直接过滤,提高爬取效率。
            page.setSkip(true);
            // 测试,看是否再被爬取。
            page.addTargetRequest("http://my.csdn.net/wgyscsf");
            /*
             * 核心部分,从关系模块出发,去遍历所有相关用户!
             */
            // 开始获取关注与被关注以及访客的个人中心。同时加入爬虫队列。
            String html = relationElements.get(0).html();
            List<String> all = new Html(html)
                    .xpath("//div[@class=\"mod_relations\"]").links().all();
            // 加入到爬虫队列
            page.addTargetRequests(all);

        }
    }

    @Override
    public Site getSite() {
        return site;
    }

    public static void main(String[] args) {
        Spider.create(new CsdnMineSpider())
                .addUrl("http://my.csdn.net/wgyscsf").thread(1)// 便于测试,只开一个线程,正常爬起来,可以开15不成问题。
                .pipeline(null)
                .run();
    }

}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

关键代码解释

  • 正则 http://my.csdn.net/\\w+"表示过滤出以http://my.csdn.net/"开头的网址链接。不过该正则存在一定的问题,就是只对网址前面部分进行了限制,并没有对后面进行限制。只要以http://my.csdn.net/"开头的网址全部会被加入到爬虫队列,存在大量的“脏数据”网址。比较合理的是:http://my.csdn.net/"后面可以出现除了“/”的任意字符。正则的准确性直接影响到爬虫的效率,越准确越好。这里不再修改。
  • profileElements.get(0).getElementsByClass("person-detail").get(0).text();该代码片段是为了获取用户的个人资料,该资料比较多,包括行业、职业、地区(国、省、市、区等)、姓名等信息。经过分析没有好的依据对信息进行归类,这里只是获取粗略信息。经过分析,甚至说CSDN官方最开始对该块没有进行合理的安排,导致用户的信息没有统一的格式。
  • 以下代码片段是该部分的核心代码,实现了递归式的爬取所有用户。relationElements元素来自于mainElements.get(2).getElementsByTag("div");,属于“关系模块”,包括关注的人和被关注的人以及访客信息。在这个模块中可以获取部分其它用户的id,只不过是部分的,最多只有6个人信息。CSDN官方没有提供获取所有粉丝或者关注者的信息。不过,只要这仅仅的用户信息,我们就可以爬取所有的用户。方便的是,顺便可以过滤掉“死鱼”用户(没有相互关系的用户)。

        // 开始获取关注与被关注以及访客的个人中心。同时加入爬虫队列。
        String html = relationElements.get(0).html();
        List<String> all = new Html(html)
                .xpath("//div[@class=\"mod_relations\"]").links().all();
        // 加入到爬虫队列
        page.addTargetRequests(all);
    
       
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 需要说明的是,爬取所有用户,其实不是一定要定位到“关系”模块。我们甚至可以简单粗暴的直接获取http://my.csdn.net/user_id"中所用有效链接,直接加入到爬虫队列。到时候直接通过正则http://my.csdn.net/\\w+"过滤出有效链接即可。代码如下:

        // 直接取出该网页下的所有网址链接,简单粗暴,不用进行判断。
        // 只要在进入爬取用户信息的时候加正则匹配即可。
        // 但是会出现过多的“脏数据”,增加判断,影响爬取效率。
        List<String> all = page.getHtml().links().all();
        System.out.println(all);// 测试打印的网址链接
        // 加入到爬虫队列
        page.addTargetRequests(all);
    
       
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 正如前文概述中所说,递归时的爬取用户信息,会出现大量已经爬取过的页面,我们需要“过滤”掉这些信息。核心的代码是page.setSkip(true);,爬取之后,直接设置为“跳过”,下次爬取会直接跳过该链接。webMagic的作者对该方法的解释如下:

    /**

    • Set whether to skip the result.
    • Result which is skipped will not be processed by Pipeline. 
      *
    • @param skip whether to skip the result
    • @return this 
      */
  • 过滤代码如下:

        // 当前爬取页面信息爬取结束,将当前页面设置为“跳过”,下次再加入爬虫队列,直接过滤,提高爬取效率。
        page.setSkip(true);
        // 测试,看是否再被爬取。
        page.addTargetRequest("http://my.csdn.net/wgyscsf");
    
       
       
    • 1
    • 2
    • 3
    • 4
    • 5

爬取结果预览

  • 爬取所有用户 
    这里写图片描述
  • 爬取所有http://my.csdn.net/user_id"内网址 
    这里写图片描述

常用爬虫正则

  • http://my.csdn.net/\\w+" :过滤出所有以http://my.csdn.net/开头的网址。
  • ^http://blog.csdn.net/((?!/).)*$:过滤出以http://blog.csdn.net/开头,并且后面不能再出现“/”的所有网址链接。
  • ^http://blog.csdn.net/\\w+/article/list/[0-9]*[1-9][0-9]*$:过滤出http://blog.csdn.net/后面是任意字符,并且紧接着/article/list/,且/article/list/后面只能是数字的所有网址链接。
  • http://blog.csdn.net/\\w+/article/details/\\w+:效果同上,只是最后允许任意字符,不仅仅限于数字。

测试正则的方式

    Pattern pattern = Pattern
            .compile("^http://blog.csdn.net/\\w+/article/list/[0-9]*[1-9][0-9]*$");
    Matcher matcher = pattern
            .matcher("http://blog.csdn.net/wgyscsf/article/list/32423");
    boolean b = matcher.matches();
    // 当条件满足时,将返回true,否则返回false
    System.out.println(b);

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

操作代码(代码已全部迁移至github,欢迎star)

https://github.com/scsfwgy/WebMagic_CSDN_Demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值