您的位置:首页 > 其它

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

2017-10-23 16:48 330 查看


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: