通过URL多线程异步爬取页面、图片转Base64格式

        最近学习、需要通过url爬取页面html数据信息、将图片转成base64格式,图片太大转base64存在库里对数据库造成一定的压力,然后我又将图片给压缩了一下,在不失真的情况下、中间用到了别的工具类我都列举出来了。

一、获取url

二、图片压缩转base64如果想用我的这个,可以访问:

地址:图片压缩工具类(适合所有格式的图片)_单人可khalil的博客-CSDN博客

三、将url转成 MultipartFile、可以访问:

地址:将url转MultipartFile工具类_单人可khalil的博客-CSDN博客

四、核心代码、可以参考自行根据逻辑进行修改调整。


    // 正则表达式(根据页面实际情况进行调整)
    private static final Pattern IMAGE_SRC_PATTERN = Pattern.compile("data-src\\s*=\\s*\"?(.*?)(\"|>|\\s+)");

    private static final Pattern IMAGE_OPACITY_WIDTH_PATTERN = Pattern.compile("(?<=<img.{1,5000})style\\s*=\\s*\".*?\"");




    /**
     * 爬取详细数据信息
     *
     * @param newsContent String
     * @return String
     */
    private String buildNewsContent(String newsContent) {
        try {
            if (StringUtil.isEmpty(newsContent)) {
                logger.error("error message: 获取待爬取<url><{}>为空", newsContent);
                return null;
            }
            long urlStart = System.currentTimeMillis();
            CompletableFuture<StringBuilder> stringBuilderCompletableFuture = CompletableFuture.completedFuture(buildUrl(newsContent));
            CompletableFuture.allOf(stringBuilderCompletableFuture);
            StringBuilder html = stringBuilderCompletableFuture.get();
            long urlEnd = System.currentTimeMillis();
            logger.info("获取html信息、时间:<{}>", urlEnd - urlStart);

            long htmlStart = System.currentTimeMillis();
            String getHtml = html
                    .toString()
                    .replaceAll(ConstantUtil.NEWS_MACRO_INSIGHT_A_CLASS, ConstantUtil.SPECIAL_CHARACTER_EMPTY)
                    .replaceAll(ConstantUtil.NEWS_MACRO_INSIGHT_DIV_CLASS, ConstantUtil.SPECIAL_CHARACTER_EMPTY);
            List<String> stringList = new ArrayList<>();
            stringList.add(html.toString());
            // 获取图片信息
            List<String> urlList = new ArrayList<>();
            List<String> widthList = new ArrayList<>();
            for (String s : stringList) {
                Matcher matcher = IMAGE_SRC_PATTERN.matcher(s);
                while (matcher.find()) {
                    urlList.add(matcher.group());
                }
                Matcher matcherWidth = IMAGE_OPACITY_WIDTH_PATTERN.matcher(s);
                while (matcherWidth.find()) {
                    widthList.add(matcherWidth.group(0));
                }
            }
            long htmlEnd = System.currentTimeMillis();
            logger.info("获取图片信息、时间:<{}>", htmlEnd - htmlStart);

            long start = System.currentTimeMillis();

            // 去重
            List<String> string = urlList.stream().distinct().collect(Collectors.toList());
            Map<String, String> map = new ConcurrentHashMap<>(string.size());
            List<CompletableFuture<String>> base64FutureList = string.stream()
                    .filter(base -> base.contains(ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_HTTP))
                    .map(base -> CompletableFuture.supplyAsync(() -> buildBase64(base, map), threadPoolTaskExecutor))
                    .collect(Collectors.toList());
            CompletableFuture.allOf(base64FutureList.toArray(new CompletableFuture[0]));
            for (CompletableFuture<String> stringCompletableFuture : base64FutureList) {
                if (StringUtil.isNotEmpty(stringCompletableFuture.get())
                        && StringUtil.isNotEmpty(map.get(stringCompletableFuture.get()))) {
                    getHtml = getHtml.replace(stringCompletableFuture.get(), ConstantUtil.NEWS_MACRO_INSIGHT_SRC +
                            map.get(stringCompletableFuture.get()) +
                            ConstantUtil.NEWS_MACRO_INSIGHT_CHARACTER_EMPTY);
                }

            }
            // 添加 opacity: 1;width: 100%; 用于前端图片展示和图片占比
            getHtml = buildStyle(widthList, getHtml);

            long end = System.currentTimeMillis();
            logger.info("转base64格式、时间:<{}>", end - start);
            return getHtml;
        } catch (Exception e) {
            Thread.currentThread().interrupt();
            logger.error("error message: 爬取<华鑫视点>详细信息失败、原因:", e);
            return null;
        }
    }

    /**
     * 添加 样式 opacity: 1;width: 100%;
     *
     * @param widthList List<String> widthList
     * @param getHtml   String
     * @return String
     */
    private String buildStyle(List<String> widthList, String getHtml) {
        for (String style : widthList) {
            if (style.contains(ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_VERTICAL_ALIGN)) {
                style = style.replace(ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_STYLE, ConstantUtil.SPECIAL_CHARACTER_EMPTY)
                        .replace(ConstantUtil.NEWS_MACRO_INSIGHT_CHARACTER_EMPTY, ConstantUtil.SPECIAL_CHARACTER_EMPTY);
                if (!style.contains(ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_OPACITY_WIDTH)) {
                    getHtml = getHtml.replace(style, style + ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_OPACITY_WIDTH);
                }
            }
        }
        return getHtml;
    }

    /**
     * 获取 html 信息
     *
     * @param newsContent String
     * @return StringBuilder
     */
    private StringBuilder buildUrl(String newsContent) {
        try {
            //建立连接
            URL url = new URL(newsContent);
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
            httpUrlConn.setDoInput(true);
            httpUrlConn.setRequestMethod(ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_GET);
            httpUrlConn.setRequestProperty(ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_USER_AGENT,
                    ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_MOZILLA);
            //获取输入流
            InputStream input = httpUrlConn.getInputStream();
            //将字节输入流转换为字符输入流
            InputStreamReader read = new InputStreamReader(input, StandardCharsets.UTF_8);
            //为字符输入流添加缓冲
            BufferedReader br = new BufferedReader(read);
            // 读取返回结果
            StringBuilder html = new StringBuilder();
            String data;
            while ((data = br.readLine()) != null) {
                html.append(data);
            }
            // 释放资源
            br.close();
            read.close();
            input.close();
            httpUrlConn.disconnect();
            return html;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 通过 url 转成 base64格式
     *
     * @param base String
     * @return String
     */
    private String buildBase64(String base, Map<String, String> map) {
        // 获取src
        String src = base.replace(ConstantUtil.NEWS_MACRO_INSIGHT_DATA_SRC_SYN, ConstantUtil.SPECIAL_CHARACTER_EMPTY)
                .replace(ConstantUtil.NEWS_MACRO_INSIGHT_CHARACTER_EMPTY, ConstantUtil.SPECIAL_CHARACTER_EMPTY);
        // 随机名称
        String randomMixVerifyCode = MessageUtil.getRandomMixVerifyCode(6);
        int count = 0;
        MultipartFile multipartFile = null;
        while (count <= ConstantUtil.NEWS_MACRO_INSIGHT_NEWS_COUNT) {
            // 转成 MultipartFile
            multipartFile = FileUtil.urlToMultipartFile(src, randomMixVerifyCode + ConstantUtil.WIND_STOCK_SHARE_PNG);
            if (!FileUtil.isMultipartFileEmpty(multipartFile)) {
                break;
            }
            count++;
        }
        // 压缩图片
        // 返回base64
        String base64 = ConstantUtil.NEWS_MACRO_INSIGHT_DATA_IMAGE_PNG_BASE64 + ImageUtil.compressImageByMultipartFile(multipartFile);
        map.put(base, base64);
        return base;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Selenium是一个用于Web自动化测试的工具,它可以模拟用户在浏览器中的操作,例如点击链接、填写表单、提交数据等。Selenium支持多线程异步爬取,这些功能可以提高爬取效率。 如果您使用Selenium进行Web爬取,可以采用以下一些方法来提高爬取效率: 1. 使用headless模式:在headless模式下,Selenium可以在后台运行,不需要显示浏览器界面,这可以减少资源消耗,提高爬取效率。 2. 合理设置等待时间:在进行Web爬取时,页面加载需要一定的时间,而等待时间过长会浪费时间,等待时间过短又会导致页面没有加载完全。因此,您需要根据实际情况合理设置等待时间。 3. 使用代理IP:如果您需要大规模爬取数据,可以使用代理IP,这可以有效地避免被封IP。 4. 使用分布式爬虫:使用分布式爬虫可以将任务分配给多个机器或进程,这可以大大提高爬取效率。 总的来说,Selenium具有多线程异步爬取的优势,可以提高爬取效率,但在使用时需要注意合理设置等待时间、使用代理IP等。 ### 回答2: 使用selenium多线程异步爬取的效率取决于具体情况和使用的方式。 在一些特定的情况下,使用selenium多线程可能会更高效。多线程可以同时执行多个任务,可以将爬取任务分配给不同的线程并行执行,从而提高整体的爬取效率。这对于需要同时处理多个任务的情况,如同时爬取多个网页或者进行大规模数据抓取时,可以充分利用CPU和网络资源,提高整体的爬取速度。然而,需要注意的是,使用多线程也存在线程间的竞争和同步问题,如果处理不当可能会导致资源争用和性能下降。 另一方面,异步爬取也具有高效的特点。异步爬取利用非阻塞的方式发送和处理请求,可以在发送请求的同时处理其他任务,从而提高整体的爬取效率。相比于传统的同步请求方式,异步爬取可以充分利用网络带宽,减少等待时间,提高爬取速度。尤其适用于需要大量请求或者请求响应时间较长的情况下,如爬取API数据或者动态网页内容。然而,异步爬取也需要适当的协程调度和处理异步回调,一些网站可能会限制同时并发的请求数目,如果不加控制可能会导致反爬机制的触发。 总之,使用selenium多线程异步爬取的效率取决于具体需求和实现方式。需要根据实际情况选择合适的方法,并对其进行调优,以提高爬取效率。 ### 回答3: 使用Selenium多线程异步爬取的效率取决于具体的爬取任务和网站结构。在一些情况下,使用Selenium多线程可能效率更高,而在其他情况下,异步爬取可能效率更高。 首先,使用Selenium多线程可以同时打开多个浏览器窗口,每个窗口都可以执行独立的操作。这对于需要同时执行多个操作的任务非常有用,例如需要在不同的页面中执行交互操作然后获取数据的情况。多线程可以提高同时处理任务的能力,从而加快爬取的速度。 然而,Selenium多线程也存在一些限制。首先,每个浏览器窗口都需要占用相应的系统资源,包括内存和处理器。如果需要打开大量的窗口,可能会导致系统资源不足,从而影响整体效率。此外,Selenium在打开和关闭浏览器窗口时也会产生一定的时间开销,这可能影响爬取速度。 相比之下,异步爬取通过利用非阻塞式的编程方式,可以同时发送多个请求并处理响应。这种方式可以提高请求的并发性,从而加快爬取的速度。异步爬取也可以避免浏览器窗口的开销,并节省系统资源。在一些数据库查询较多而网页渲染较少的任务中,异步爬取可能更适合。 总之,使用Selenium多线程异步爬取的效率取决于具体情况。需要根据任务的特点和网站的结构来选择合适的方法,以提高爬取速度和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值