java爬虫

都说python比java写爬虫更容易,我特意用python写了爬虫,对比java写爬虫,确实python更容易,主要是完善的支持库和语法特性占了优势。在GitHub上java爬虫有几个项目还是很不错的,有兴趣的可以去看看。

一、列举爬虫

爬虫主要是依赖于基础的tcp协议或者高级http协议,根据不同的工作场景分为2种:

1、数据爬虫

     爬取方式:主要是寻找服务端接口地址进行模拟请求获得数据,主要适用于请求回来是一串数据而不是一个网页的场景。基本要素是伪装用户骗取服务器信任得到数据。

     防范方式:

        a、服务端进行严格的授权策略。具体做法是生成短暂过期token,通常用于cookie中。

        b、服务端进行频繁业务请求记录。比如1秒内请求了10几次,服务器会将此ip锁住一段时间拒绝提供任何服务。

        c、请求头检测。服务端对请求头进行检测,鉴定是否为爬虫,这种方式检测成爬虫的几率太小,爬虫程序稍微伪装一下即可。

    实现方案:

        推荐使用vertx,详情查阅vertx文档。

2、页面爬虫

     爬取方式:等待页面与js渲染完成后根据返回的网页xml节点进行解析,主要适用于请求回来是一个网页而不是一串数据的场景。基本要素是根据网页节点做数据解析,得到页面上需要的数据。

    防范方式:

        a、使用自动生成ui的前端框架,增加页面xml的复杂度,提高解析的难度。

   实现方案:

        htmlunit

在此我只想介绍 页面爬虫的实现htmlunit。数据爬虫的实现太多了

二、介绍htmlunit

htmlunit是一个拿来做html测试的东西,它可以模拟一个浏览器,在页面上的所有行为完全可以用代码控制。

官网 http://htmlunit.sourceforge.net/

三、实现一个页面爬虫

1、maven支持

<dependency>
    <groupId>net.sourceforge.htmlunit</groupId>
    <artifactId>htmlunit</artifactId>
    <version>2.34.1</version>
</dependency>

2、抓取页面

/访问的目标网址
private static String TARGET_URL = "https://www.naifen123.cn/item-2266.html";
public static void main(String[] args) throws FailingHttpStatusCodeException, IOException {
    // 模拟一个浏览器
    WebClient webClient = new WebClient(BrowserVersion.CHROME);
    // 设置webClient的相关参数
    webClient.setCssErrorHandler(new SilentCssErrorHandler());
    //设置ajax
    webClient.setAjaxController(new NicelyResynchronizingAjaxController());
    //设置支持js
    webClient.getOptions().setJavaScriptEnabled(false);
    //CSS渲染禁止
    webClient.getOptions().setCssEnabled(false);
    //超时时间
    webClient.getOptions().setTimeout(50000);
    //设置js抛出异常:false
    webClient.getOptions().setThrowExceptionOnScriptError(false);
    //允许重定向
    webClient.getOptions().setRedirectEnabled(true);
    //允许cookie
    webClient.getCookieManager().setCookiesEnabled(true);
    // 模拟浏览器打开一个目标网址
    HtmlPage page = webClient.getPage(TARGET_URL);
    // 等待JS驱动dom完成获得还原后的网页
    webClient.waitForBackgroundJavaScript(10000 * 3);
    //业务
    service(page);
    webClient.close();
    System.out.println("Success!");
}
private static void service(HtmlPage page) {
    System.out.println("******** 业务开始 ***********************************");
    //标题头
    HtmlHeading1 topName = (HtmlHeading1) page.getByXPath("//h1[@class='q_left aqnfxq1_tl_lf']").get(0);
//配方含量
//中国标准-主要配方
HtmlDivision formulaDiv1 = (HtmlDivision) page.getByXPath("//div[@id='bzdiv_3']/div[@class='nf123_yynl clearfix']").get(0);
//主要配方
Map<DomText, List<DomNode>> formulaMap1 = new HashMap<>();
List<DomNode> formula = new ArrayList<>(formulaDiv1.getChildNodes());
DomText key = (DomText) formula.get(0);
formula.remove(0);
formulaMap1.put(key, formula);
//中国标准-主要配方详情表
List<HtmlTable> formulaTables = page.getByXPath("//div[@id='bzdiv_3']/div[@class='nf123_xxyypf clearfix']/table");
List<List<String>> formulaSet = new ArrayList<>();
formulaTables.forEach(t -> {
    t.getRows().forEach(r -> {
        if (r.asText().trim().length() > 0) {
            List<String> com = new ArrayList<>();
            for (int i = 0; i < 3; i++) {
                com.add(r.getCells().get(i).asText());
            }
            formulaSet.add(com);
        }
    });
});
//原料分析
//原料注意
List<HtmlDivision> materialDiv1 = page.getByXPath("//div[@class='aqnfxqb_lf_b']/div[@class='aqnfxq3_1_2 aqnfxq5_2']");
Map<String, String> material1 = new HashMap<>();
if (materialDiv1 != null && !materialDiv1.isEmpty()) {
    HtmlDivision materialDiv = materialDiv1.get(0);
    materialDiv.getChildNodes().forEach(n -> {
        if (n.asText().trim().length() > 0) {
            material1.put(n.getChildNodes().get(0).asText(), n.getChildNodes().get(1).asText());
        }
    });
}
List<HtmlDivision> materialDiv2 = page.getByXPath("//div[@class='aqnfxqb_lf_b']/div[@class='aqnfxq5_4']");
List<String> material2 = new ArrayList<>();
if (materialDiv2 != null && !materialDiv2.isEmpty()) {
    HtmlDivision materialDiv = materialDiv2.get(0);
    String str = materialDiv.asText().trim();
    if (str.length() > 0) {
        str = str.replaceAll("。", "");
        String[] com = str.split(",");
        System.out.println("------" + com.toString());
        material2.addAll(Arrays.stream(com).collect(Collectors.toList()));
    }
}
System.out.println(topName.asText());
System.out.println("原料注意:");
material1.entrySet().forEach(m -> {
    System.out.println(m.getKey() + " : " + m.getValue());
});
System.out.println("原料详情:");
material2.forEach(m -> {
    System.out.println(m);
});
}

我这里只演示了抓取页面上的数据,htmlunit还提供了很多功能,比如模拟点击,悬停,选择、表单获取,登录,操作cookie、增加html标签元素等等,可以理解成 htmlunit 就是一个程序中内嵌的浏览器,可以做到浏览器的绝大多数功能。

欢迎关注我的个人公众号

   

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值