百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

Java爬虫:使用Jvppeteer(Puppeteer)爬淘宝商品就这么简单?

liuian 2025-05-05 17:00 73 浏览

大家都知道,想要爬取某宝的商品,如果只是用HttpURLConnection发个请求,失败率是很高的。一般想要保证成功率的话,都会选择真实的浏览器去抓取。

以前常用的解决方案是selenium或phantomjs,但是它两的环境配置太麻烦了,对程序员极度不友好,自从谷歌推出Puppeteer后,puppeteer迅速流行起来,获得大家一致称赞。它是一个NodeJS库,但今天并不是要使用它来爬取某宝商品,而是使用Java语言写的Jvppeteer,Jvppeteer与Puppeteer是同样的实现原理。


思路:

  1. 使用多线程,一个线程负责一个页面的爬取,接下来的内内容会使用page代替页面
  2. 创建与线程池线程数相同的page队列,放在LinkedBlockingQueue队列里,每当有爬取任务时,就从队列里取出一个page,爬取任务完成时,将page放回队列的后面。这样做的原因是重复利用page,减少页面的创建频率,但是要注意的是一个页面不能利用太久或者次数太多,防止出现crash的情况
  3. 拦截图片和多媒体资源的加载,多媒体资源和图片的加载会极大影响页面的加载速度,从而影响爬虫效率,所以要拦截(可选)。
  4. 我们选择获取整个页面内容,然后解析得到商品信息

代码实现

1.启动

 //指定启动路径,启动浏览器
        String path = new String("F:\\java教程\\49期\\vuejs\\puppeteer\\.local-chromium\\win64-722234\\chrome-win\\chrome.exe".getBytes(), "UTF-8");
        ArrayList<String> argList = new ArrayList<>();
        LaunchOptions options = new OptionsBuilder().withArgs(argList).withHeadless(false).withExecutablePath(path).build();
        argList.add("--no-sandbox");
        argList.add("--disable-setuid-sandbox");
        Browser browser = Puppeteer.launch(options);

2.page队列

  //启动一个线程池多线程抓取
        int threadCount = 5;
        ThreadPoolExecutor executor = new ThreadPoolExecutor(threadCount, threadCount, 30, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        CompletionService service = new ExecutorCompletionService(executor);
        //打开5个页面同时抓取,这些页面可以多次利用,这样减少创建网页带来的性能消耗
        LinkedBlockingQueue<Page> pages = new LinkedBlockingQueue<>();
        for (int i = 0; i < threadCount; i++) {
            Page page = browser.newPage();
            //拦截请求,可选
//            page.onRequest(request -> {
//                if ("image".equals(request.resourceType()) || "media".equals(request.resourceType())) {
//                    //遇到多媒体或者图片资源请求,拒绝,加载页面加载
//                    request.abort();
//                } else {//其他资源放行
//                    request.continueRequest();
//                }
//            });
//            page.setRequestInterception(true);
            pages.put(page);//往队列后面放,阻塞
        }

3.定义爬取线程

static class CrawlerCallable implements Callable<Object> {

        private LinkedBlockingQueue<Page> pages;
        
        public CrawlerCallable(LinkedBlockingQueue<Page> pages) {
            this.pages = pages;
        }

        @Override
        public Object call() {
            Page page = null;
            try {
                page = pages.take();
                PageNavigateOptions navigateOptions = new PageNavigateOptions();
                navigateOptions.setWaitUntil(Arrays.asList("domcontentloaded"));
                System.out.println("gotothreadName:"+Thread.currentThread().getName());
                page.goTo("https://item.taobao.com/item.htm?id=541605195654", navigateOptions);
                String content = page.content();
              //解析商品
                return parseItem(content);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (page != null) {
                    try {
                        pages.put(page);//把已经抓取完的网页放回队列里
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }
        
    }

4.关闭线程池,获取结果

 //结果集
        List<Future<Object>> futures = new ArrayList<>();
        //抓取100次
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            Future<Object> future = service.submit(new CrawlerCallable(pages));
            futures.add(future);
        }

        //关闭线程池
        executor.shutdown();
        //获取结果
        int i = 0;
        for (Future<Object> result : futures) {
            Object item = result.get();
            i++;
            System.out.println(i + ":" + Constant.OBJECTMAPPER.writeValueAsString(item));
        }
        long end = System.currentTimeMillis();
        System.out.println("时间:" + (end - start));

在俺电脑测试,100个爬取任务只需要15s,速度还是非常的快。速度的快慢受到根据电配置以及带宽的影响,配置越好,速度越快。

相关推荐

PHPMAILER实现PHP发邮件功能php实例

这篇文章主要为大家详细介绍了PHPMAILER实现PHP发邮件功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下本文实例为大家分享了PHPMAILER实现PHP发邮件功能的具体代码,供大家参考,具...

Cacti监控服务器配置教程(基于CentOS+Nginx+MySQL+PHP环境搭建)

具体案例:局域网内有两台主机,一台Linux、一台Windows,现在需要配置一台Cacti监控服务器对这两台主机进行监控环境说明:1、Linux主机操作系统:CentOS6.2IP地址:192.1...

如何在webmin中配置多个PHP版本_怎么配置php

请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习1.前言如何在webmin中配置多个PHP版本?本教程将会给您一些启示和操作案例。Web...

详解Drupal安装步骤_drools安装

DrupalDrupal是一个基于PHP语言编写的开源的内容管理系统(CMS:ContentManagementSystem),和Wordpress等CMS一样提供主题。在这里详细介绍一下安装Dr...

nternet 信息服务(IIS) 升级为IIS 6.0

 WindowsServer2003中Internet信息服务(IIS)升级为IIS6.0,其安全性更高。默认情况下,WindowsServer2003没有安装IIS6.0,要通过...

Php JIT 使用详解_php的!

简介PHP8引入的JIT(Just-In-Time编译器)是该版本的一个重要性能特性,首次让PHP有了运行时即时编译的能力,从解释型语言迈向了“编译执行”的方向。什么是JIT?JIT...

php 常见配置详解_php cgi配置

以下是PHP常见的配置项及其含义:error_reporting:设置错误报告级别,可以控制PHP显示哪些错误。例如,设置为E_ALL将显示所有错误,而设置为0将禁止显示任何错误。displa...

技巧:PHP版本怎样隐藏在Linux服务器

通常情况下,大多数安装web服务器软件的默认设置存在信息泄露,这些软件其中之一就是PHP。PHP是如今最流行的服务端html嵌入式语言之一。而在如今这个充满挑战的时代,有许多黑客会尝试发现你服务端的漏...

PHP八大安全函数解析_php安全设置

在现代互联网中,我们经常要从世界各地的用户中获得输入数据。但是,我们都知道“永远不能相信那些用户输入的数据”。所以在各种的Web开发语言中,都会提供保证用户输入数据安全的函数。在PHP中,有些非常有...

win7下apache+mysql+php安装配置_win7 mysql安装配置教程

一.首先下载好要用的apache版本:http://httpd.apache.org/download.cgimysql版本:http://dev.mysql.com/downloads/mys...

phpmyadmin取消最大文件限制的更改解决方法

用phpmyadmin导入大数据库的时候出现:Nodatawasreceivedtoimport.Eithernofilenamewassubmitted,orthefi...

成功安装 Magento2.4.3最新版教程「技术干货」

外贸独立站设计公司xingbell.com经过多次的反复实验,最新版的magento2.4.3在oneinstack的环境下的详细安装教程如下:一.vps系统:LinuxCentOS7.7.19...

CentOS、Nginx、PHP、MySQL的安装和配置记录

安装LNMP安装wget工具(可选) yuminstall-ywget下载Nginx wgethttp://www.atomicorp.com/installers/ato...

PHP扩展开发之路(二)_php扩展直接执行php代码

昨日,Jamlee发布了PHP扩展开发之路(一),今日再来续集,哈哈,会不会更有趣呢!不说多的,直接来!##0x2helloworld!,你的第一个php扩展##阅读前必看小贴士:如果你不想在本...

比较常见类型漏洞讲解(一)_常见漏洞的特点及危害

这里介绍一些手动挖掘漏洞时比较容易找到的漏洞,根据不同类型的漏洞来介绍。演示准备目标主机:Metasploitable2攻击目标:目标主机的dvwa系统攻击机:KaliSessionId盗用不知道你们...