简易小爬虫项目

最近疏于学习,干脆就把去年跟同学做的职潮人小程序中的爬取职位这部分的代码拿出来,加以改进瞎搞一波吧。

代码Github地址: https://github.com/zhouhuanghua/project

之前的可以爬取拉勾BOSS智联还有一些校招网站的,现在只拿拉勾的做个典型吧。

(#说起来也可惜,前后端都基本做完了,网站备案也弄好了,then不知道为啥突然就没了兴趣......宣告失败#)

说回主题,这次做完的效果是这样的 (#说好的不再搞前端的,哎

看一下重点吧,这个是架构图(镇楼图)

 

那么,问题来了

1, 为什么需要RabbitMQ?

答:看图中的几个服务小伙子,各自的责任是分离的,我只干我的你也不能影响我,所以拿到结果直接丢到MQ上面(强行解释了MQ发挥着异步+解耦的作用)。

2, 为什么使用binlog处理增量数据?

答:项目结构里,爬虫系统和查询平台分在了不同的模块,可以独立运行,我不想它们之间共用一些东西。

代码这里只讲一下里面用到的责任链设计模式。其它的话可以去GitHub克隆下来看(点击这里前往)。

定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系, 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。之前的博客(点击这里前往)里面有更详细的介绍。

常见的有两种写法,也就是外部控制链路流向和内部控制链路流向。

外部控制的比较简单,就是把所有处理对象收集起来遍历,根据每个处理的返回值确定是否继续和终止。伪代码如下

List<Handler> handlerList = ...;
for (Handler h : handlerList) {
    R result = h.process(xxx);
    if (result xxx) {
        break;
    }
}

内部的就复杂一点,有点递归的意思,就是由处理者决定是否将请求交给下一个处理者处理。

首先定义处理者接口,抽象方法是crawl

public interface IStrategy {

    default boolean isNormalPage(Document document) {
        return Objects.nonNull(document.selectFirst("div[class=job-name]"));
    }

    void crawl(String url, ObjectWrapper<Document> docWrapper, CrawlStrategyChain strategyChain);
}

然后添加两个处理者实现类,Jsoup和Chrome

public class JsoupStrategy implements IStrategy {

    private final Map<String, String> COMMON_HEADER_MAP = MapUtils.buildMap(
            "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
            "Accept", "application/json, text/plain, */*",
            "Cookie", "token");

    @Override
    public void crawl(String url, ObjectWrapper<Document> docWrapper, CrawlStrategyChain strategyChain) {
        try {
            Document document = Jsoup.connect(url).headers(COMMON_HEADER_MAP).get();
            if (isNormalPage(document)) {
                docWrapper.setObj(document);
                return;
            }
        } catch (Throwable t) {
            log.warn("Jsoup加载网页[url={}]异常,t={}", url, ThrowableUtils.getStackTrace(t));
        }
        strategyChain.doCrawl(url, docWrapper);
    }
}
public class ChromeStrategy implements IStrategy {

    @Override
    public void crawl(String url, ObjectWrapper<Document> docWrapper, CrawlStrategyChain strategyChain) {
        WebDriver webDriver = BrowserDriverFactory.openChromeBrowser();
        try {
            webDriver.get(url);
            Document document = Jsoup.parse(webDriver.getPageSource());
            if (isNormalPage(document)) {
                docWrapper.setObj(document);
                return;
            }
        } catch (Throwable t) {
            log.warn("Chrome加载网页[url={}]异常,t={}", url, ThrowableUtils.getStackTrace(t));
        } finally {
            OptionalOperationUtils.consumeIfNonNull(webDriver, WebDriver::quit);
        }
        strategyChain.doCrawl(url, docWrapper);
    }
}

接着,定义一个链调用对象

public final class CrawlStrategyChain {
    private int pos = 0;
    private int n;
    private IStrategy[] strategies;

    private CrawlStrategyChain() {
    }

    public static CrawlStrategyChain build(IStrategy[] strategies) {
        CrawlStrategyChain instance = new CrawlStrategyChain();
        instance.strategies = Objects.requireNonNull(strategies, "CrawlStrategyChain构造参数strategies不能为空!");
        instance.n = strategies.length;
        return instance;
    }

    public void doCrawl(String url, ObjectWrapper<Document> docWrapper) {
        if (pos < n) {
            strategies[pos++].crawl(url, docWrapper, this);
        }
    }
}

最后,看下是怎么使用的

聪明的你看明白了没有呀?不明白的话没关系,赶紧去下载代码本地跑几遍吧!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值