使用Jsoup获取数据

本文详细介绍了如何使用Java的Jsoup库进行网页数据抓取,包括环境准备、基本的抓取示例、根据C_URL定制请求头、使用RestTemplate调用第三方接口,以及优化和注意事项,适合IT开发者学习和实践爬虫技术。
摘要由CSDN通过智能技术生成

引言:

我们在工作中会遇见一些业务就是将某个网址的数据给获取下来,我们首先想到的就是爬虫,接下来演示的就是使用Java的Jsoup框架进行获取数据,

1、环境准备

首先无论我们平常使用什么框架基本上都是先引入他的依赖,Jsoup也不例外我们在maven中引入我们的Jsoup依赖

<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.17.1</version>
</dependency>
2、演示简单的demo

我们在引入依赖之后我们就可以创建一个Java类开始操作一个简单的获取数据代码

@Test
    public void test() throws IOException {
        //设置商品链接
        String url = "https://search.xxx.com/Search";
        try {
            //发送HTTP请求获取页面内容
            Document doc = Jsoup.connect(url).get();
            //解析D0获取商品信息
            Elements goods = doc.select(".gl-item");
            for (Element element : goods) {
                //获取商品名称
                String name = element.select(".p-name").text();
                //获取商品价格
                String price = element.select(".p-price").text();
                //输出商品信息
                System.out.println("商品名称:" + name);
                System.out.println("商品价格:" + price);
                System.out.println("---");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

这段代码就是一段演示的demo,我们传进去一个URL,然后设置连接,在使用get方法就可以获取一个Document的,然后从里面获取元素或者是标签都可以了,

3、进阶版本

我们上面的是一个简单的demo,平常不是很推荐使用,我们最好是根据网址接口的C_URL命令进行设置请求头的方式来获取Document,因为使用上面的方法有时候是获取不到Document,

        3.1、如何获取C_URL命令

        3.2、获取之后如何使用

我们在获取到这个命令之后可以粘贴到postman上进行发送请求,然后根据请求头设置我们代码里面的请求头,下面是一段演示代码

private static Document getOneAndTotalDocument(String url) {

        for (int i = 1; i <= Constant.MAX_ERROR_3; i++) {
            try {
                Document document = Jsoup.connect(url)
                        .header("authority", "xxx.xxxx.xxxx")
                        .header("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
                        .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
                        .header("cache-control", "max-age=0")
                        .header("if-none-match", "W/\"cacheable:a697d3df8be1f56329f78f02f21727ef\"")
                        .header("referer", "https://converse.co.jp/collections/shoes?page=2")
                        .header("sec-ch-ua", "\"Not_A Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Microsoft Edge\";v=\"96\"")
                        .header("sec-ch-ua-mobile", "?0")
                        .header("sec-ch-ua-platform", "Windows")
                        .header("sec-fetch-dest", "document")
                        .header("sec-fetch-mode", "navigate")
                        .header("sec-fetch-site", "same-origin")
                        .header("sec-fetch-user", "?1")
                        .header("upgrade-insecure-requests", "1")
                        .header("user-agent", RequestUtils.randomUserAgent())
                        .get();
                return document;
            } catch (Exception e) {
                if (i == Constant.MAX_ERROR_3) {
                    e.printStackTrace();
                    log.error("抓取失败!相关链接{},错误信息{}", url, e.getMessage());
                }
            }
        }
        return null;
    }
4、获取Document之后操作

我们获取Document之后一切都简单了,我们可以从里面获取各种所看到的页面数据,只要是页面上有的我们基本上都可以获取到,下面是我写的一部分代码,可以进行参考

 private static List<ConverseVo> getConverseSkuDetail(String spuUrl) {

        List<ConverseVo> converseList = new ArrayList<>();
        Document document = getSkuDttailDocument(spuUrl);


        String Kids = document.select(".breadcrumb a").text();
        if (Kids.contains(CHILDREN) || Kids.contains(BABY)) {
            return null;
        }


        Elements elements = document.select(".product-single__variants.no-js option");

        List<ConverseVo> voList = elements.stream().map(element -> {
            ConverseVo converseVo = new ConverseVo();
            String value = element.attr("value");
            if (!StringUtils.hasText(value)) {
                return null;
            } else {
                String priceAndProperties = element.select("option").text();
                String[] splits = priceAndProperties.split("-");
                String split = splits[0];
                String Properties = split.split(" ")[0];
                converseVo.setProperties(Properties);

                String price = splits[1].replaceAll("[^\\d]", "");
                converseVo.setPriceReplace(price);
                String valueId = element.attr("value");
                converseVo.setId(valueId);

            }

            String Discounts = document.select(".product__price-savings").text();
            if (StringUtils.hasText(Discounts)) {
                String[] split = Discounts.split("%");
                BigDecimal discount = BigDecimal.valueOf(Integer.valueOf(split[0]));
                BigDecimal discounts = discount == null || discount.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ONE : BigDecimal.valueOf(100).subtract(discount).multiply(BigDecimal.valueOf(0.01));
                converseVo.setDiscount(discounts);
            } else {
                converseVo.setDiscount(BigDecimal.valueOf(1));
            }

            converseVo.setHreFurl(spuUrl);

            Pattern pattern = Pattern.compile("[^/]+$");
            Matcher matcher = pattern.matcher(spuUrl);

            if (matcher.find()) {
                String output = matcher.group();
                converseVo.setArticleNumber(output);
            }
            return converseVo;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        List<String> volueList = voList.stream().map(ConverseVo::getId).collect(Collectors.toList());

        Elements stockElements = document.select(".hide.js-product-inventory-data div");
        HashMap<String, String> stockMap = new HashMap<>();
        for (Element element : stockElements) {
            String dataId = element.attr("data-id");
            String stock = element.attr("data-quantity");
            stockMap.put(dataId, stock);
        }

        ArrayList<String> dataIds = new ArrayList<>(stockMap.keySet());

        Collection<String> intersection = CollectionUtils.retainAll(volueList, dataIds);

        if (!CollectionUtils.isEmpty(intersection)) {

            voList.forEach(item -> {
                ConverseVo converseVo = new ConverseVo();
                converseVo.setArticleNumber(item.getArticleNumber());
                converseVo.setHreFurl(item.getHreFurl());
                converseVo.setPriceReplace(item.getPriceReplace());
                converseVo.setProperties(item.getProperties());
                converseVo.setId(item.getId());
                converseVo.setDiscount(item.getDiscount());
                if (intersection.contains(item.getId())) {

                    String stock = stockMap.get(item.getId());
                    converseVo.setStock(stock);
                }
                converseList.add(converseVo);

            });

        }

        return converseList;
    }
5、使用RestTemplate调用第三方接口

上面了是一种最平常使用Document来对数据的获取数据,其实我们可以在网页页面找到第三方接口,我们使用RestTemplate来进行调用然后获取Json数据然后进行封装一个Vo进行返回,下面是一个使用RestTemplate调用第三方接口的方法,可以进行参考

private String postStock(String pid) {

        String url = "https://www.XXXX.co.XXX/on/demandware.store/Sites-tbl-jp-Site/ja_JP/Cart-AddProduct";

        HttpHeaders headers = new HttpHeaders();
        headers.add("authority", "www.XXXX.co.XXXX");
        headers.add("accept", "*/*");
        headers.add("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
        headers.add("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
        headers.add("origin", "https://www.XXXX.co.XXX");

        JSONObject entries = new JSONObject();
        entries.put("pid", pid);
        entries.put("quantity", "1");

        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("pid", entries.getStr("pid"));
        formData.add("quantity", entries.getStr("quantity"));

        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(formData, headers);

        ResponseEntity<JSONObject> response = restTemplate.exchange(url, HttpMethod.POST, entity, JSONObject.class);
        JSONObject object = response.getBody();

        Integer stock = getMaxStock(object, pid);

        if (stock == null) {
            return null;
        }

        String string = stock.toString();
        return string;
    }
6、技术总结以及注意事项
        6.1、注意事项

在整个代码里面没有比较突出的技术,也就是根据Jsoup框架官网跑的demo,稍微注意一点的就是有个别的朋友在按照我的方法获取C_URL的命令放在poatman上跑不成功的原因大概有一点,是postman版本过低,那就需要获取上面我给大家截图如何获取C_URL命令标注的的下面那个,然后使用postman的导入进行发送请求,poatman的如下,这个只是postman上的问题,不影响别的,

        6.2、方法调用

使用RestTemplate调用第三方接口,因为我之前使用了hutool的工具类发送请求,以及Http的那个,但是用着不是很方便,而且这个RestTemplate有一个很方便的地方就是可以自定义返回结果类型,在这里先说一下简单的使用,直接注入RestTemplate就可以了,其余什么都不用,然后也可以进行一些配置,下一篇文章讲解

        6.3、优化类容

至于优化类容也就是方法的一些优化,比如使用Lambda表达式什么的,不要使用for循环,该判空判空,如果有人获取的网址数据比较慢,个人建议使用多线程去执行任务,看公司业务,使用多线程也要注意任务数量,否则会出现一些问题

最后如果大家有问题的话或者好的建议,大家可以私信或者评论指出

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值