使用SpringBoot和VWCawler轻松抓取CSDN的文章

有关VW-Cralwer的介绍可以看这里,简单轻便开源的一款Java爬虫框架。

下面结合比较流行的框架SpringBoot抓取CSDN的数据(有关的Spingboot的使用可以参考这里)

配置POM

使用Springboot做架构,redis做数据存储,vw-crawler做爬虫模块,最终的pom如下

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <vw-crawler.version>0.0.4</vw-crawler.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <!--这里不需要web服务,只需要Application即可-->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.github.vector4wang</groupId>
        <artifactId>vw-crawler</artifactId>
        <version>0.0.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.7</version>
    </dependency>
</dependencies>

redis相关配置

因为已经添加了redis的相关依赖,只需要在application.properties里配置redis的链接参数即可,如下

# Redis数据库索引(默认为0)
spring.redis.database=1
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

代码里的使用

@Component
public class DataCache {
    @Autowired
    private StringRedisTemplate redisTemplate;
    public void save(Blog blog) {
        redisTemplate.opsForValue().set(blog.getUrlMd5(), JSON.toJSONString(blog));
    }
    public Blog get(String url) {
        String md5Url = Md5Util.getMD5(url.getBytes());
        String blogStr = redisTemplate.opsForValue().get(md5Url);
        if (StringUtils.isEmpty(blogStr)) {
            return new Blog();
        }
        return JSON.parseObject(blogStr, Blog.class);
    }
}

比较简单,一个保存一个获取即可,这里使用StringRedisTemplate时为了更直观的在redis客户端中查看内容。

爬虫

页面数据model

使用流行的注解方式来填充数据

@CssSelector(selector = "#mainBox > main > div.blog-content-box > div.article-title-box > h1", resultType = SelectType.TEXT)
private String title;

@CssSelector(selector = "#mainBox > main > div.blog-content-box > div.article-info-box > div > span.time", dateFormat = "yyyy年MM月dd日 HH:mm:ss")
private Date publishDate;

@CssSelector(selector = "#mainBox > main > div.blog-content-box > div.article-info-box > div > div > span", resultType = SelectType.TEXT)
private String readCountStr;

private int readCount;

@CssSelector(selector = "#article_content",resultType = SelectType.TEXT)
private String content;

@CssSelector(selector = "body > div.tool-box > ul > li:nth-child(1) > button > p",resultType = SelectType.TEXT)
private int likeCount;

/**
 * 暂时不支持自动解析列表的功能,所以加个中间变量,需要二次解析下
 */
@CssSelector(selector = "#mainBox > main > div.comment-box > div.comment-list-container > div.comment-list-box",resultType = SelectType.HTML)
private String comentTmp;

private String url;

private String urlMd5;

private List<String> comment;

使用选择器来精确定位数据,使用chrome浏览器的可以这样快速获取


如图,也支持xpath的快捷选择(vw-crawler后续会支持xpath定位元素),当然了,有些元素如"阅读数:xxx",是不能自动转化为整型,所以还需要第二次解析处理

爬虫配置

这里需要配置请求头如“User-Agent”,目标页URL的正则表达式,列表页URL的正则,还有爬虫的线程数和超时等等,如下

new VWCrawler.Builder().setUrl("https://blog.csdn.net/qqhjqs").setHeader("User-Agent",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36")
                .setTargetUrlRex("https://blog.csdn.net/qqhjqs/article/details/[0-9]+").setThreadCount(5)
                .setTimeOut(5000).setPageParser(new CrawlerService<Blog>() {
            @Override
            public void parsePage(Document doc, Blog pageObj) {
                pageObj.setReadCount(Integer.parseInt(pageObj.getReadCountStr().replace("阅读数:", "")));
                pageObj.setUrl(doc.baseUri());
                pageObj.setUrlMd5(Md5Util.getMD5(pageObj.getUrl().getBytes()));
            }
            @Override
            public void save(Blog pageObj) {
                dataCache.save(pageObj);
            }
        }).build().start();

需要实现CrawlerService,看下源码

public boolean isExist(String url){
        return false;
}
public boolean isContinue(Document document){
    if (document == null) {
        return false;
    }
    return true;
}

public abstract void parsePage(Document doc, T pageObj);

public abstract void save(T pageObj);

可以看到parsePage可以处理数据的二次解析,save则负责保存数据,isExist和isContinue是处理爬取过程中的一些判断逻辑

  • isExist 是url的二次判重,你可以通过查找数据库来判断即将要抓取的URL是否存在数据库中,存在则返回true,不存则正常抓取即返回false;
  • isContinue 是在解析页面数据前判断一下该页面是否有WAF(Web Application Firewal),如果有则返回false,没有则正常进行解析即返回true;

要在springboot全部初始化完毕之后再去启动爬虫, 所有需要这样配置

@Component
@Order
public class Crawler implements CommandLineRunner {
    @Autowired
    private DataCache dataCache;
    @Override
    public void run(String... strings) {
        // 爬虫配置
    }
}

启动

直接右键执行CrawlerApplication即可
最终抓取如图

相关链接

VW-Crawler SpringBoot

该爬虫地址:传送门

CSDN:http://blog.csdn.net/qqhjqs?viewmode=list
博客:http://blog.wangxc.club
简书://www.greatytc.com/u/223a1314e818
Github:https://github.com/vector4wang
Gitee:https://gitee.com/backwxc

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容