【java爬虫】使用selenium爬取优惠券

news/2024/7/19 10:49:22 标签: 爬虫, selenium

本文将介绍使用selenium爬取某宝优惠券的方法,之所以使用selenium是因为我不会js逆向,如果你已经参透了淘宝联盟的js逆向方法,那么直接使用接口调数据就行了。

使用selenium接管chrome浏览器

由于淘宝联盟需要先登录,为了避免每次打开selenium都要重新登录,我们让selenium接管已经登录过账号的chrome浏览器进程进行爬虫

在打开的浏览器中输入某宝联盟首页,然后扫码登录即可阿里妈妈https://pub.alimama.com/portal/v2/pages/promo/goods/index.htm

优惠券卡片对应的html标签

其实我感觉爬虫真的没什么难度,因为前端再写的时候一般都会把重复的元素放到一个循环里面去创建,优惠券卡片也不例外,因此我们只需要找到数组,逐个提取其中的元素即可。

很容易发现,装有优惠券卡片的数组的

class=GoodsList__CardList-sc-84so0w-1 chSSLp

我们只需要找个这个div,然后逐个遍历数据提取信息即可。

我们首先来确定一下,本文主要爬取一张卡片的以下六个信息,分别是

  • 图片url

  • 优惠券标题

  • 券前价格

  • 券后价格

  • 佣金率

  • ​佣金

 对应上述六个数据,建立一个实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class GoodItem {

    // 优惠券标题
    private String title;
    // 图片url
    private String imgUrl;
    // 券前价格
    private Double prePrice;
    // 券后价格
    private Double postPrice;
    // 佣金率
    private Double commissionRate;
    // 佣金
    private Double commission;

}

使用selenium获取信息

获取图片url和优惠券标题比较容易,直接通过类名去一个一个找就行了,这边主要介绍一下获取价格的方法。

这里拿券前价格举例子

我们可以看到价格是由四个<span>标签组成的,每个标签都有不同的类名,我们只需要将后面三个标签对应的数字按照字符串拼接起来,然后解析成浮点型就行了。

    private Double getPrice(WebElement element) {
        StringBuilder sb = new StringBuilder();
        sb.append(element.findElement(By.className("union-number-format-integer")).getText());
        sb.append(element.findElement(By.className("union-number-format-pointer")).getText());
        sb.append(element.findElement(By.className("union-number-format-decimal")).getText());
        Double price = Double.parseDouble(sb.toString());
        return price;
    }

获取佣金率和佣金的逻辑也是相似的,只需要在调用getPrice()的时候传入特定的元素就行了

佣金率和佣金对应的class是一样的,所以我们一次拿两个div,第一个解析成佣金率,第二个解析成佣金

这里面还有一个坑,有一些商品价格超过1000,前端页面会添加一个逗号,导致解析失败,我们需要将字符串中所有的逗号都去掉

    private Double getPrice(WebElement element) {
        StringBuilder sb = new StringBuilder();
        sb.append(element.findElement(By.className("union-number-format-integer")).getText().replaceAll(",", ""));
        sb.append(element.findElement(By.className("union-number-format-pointer")).getText());
        sb.append(element.findElement(By.className("union-number-format-decimal")).getText());
        Double price = Double.parseDouble(sb.toString());
        return price;
    }

当我们爬取完一页数据后,需要点击下一页,并且待页面加载完后在开始获取数据

完整的代码如下

@Slf4j
@Service
public class SeleinumServiceImpl implements SeleinumService {

    private final String DRIVER_PATH = "E:/写作/优惠券项目/驱动/chromedriver.exe";

    @Override
    public List<GoodItem> getGoodInfo() {
        // 加载chrome驱动
        System.setProperty("webdriver.chrome.driver", DRIVER_PATH);
        ChromeOptions options = new ChromeOptions();
        options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
        // 启动浏览器
        WebDriver driver = new ChromeDriver(options);
        // 设置最长等待时间
        driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        // 实例化一个列表存放数据
        List<GoodItem> rstList = new ArrayList<>();
        // 开始遍历卡片数据
        // 遍历100组数据暂停
        for(int i=0; i<100; ) {
            WebElement element = driver.findElement(By.className("GoodsList__CardList-sc-84so0w-1"));
            List<WebElement> divList = element.findElements(By.className("union-good-card-wrap"));
            log.info("获取" + divList.size() + "个优惠券卡片");
            for(int j=0; j< divList.size(); j++) {
                GoodItem item = new GoodItem();
                // 图片url
                item.setImgUrl(divList.get(j).findElement(By.className("union-good-card-good-img-wrap-mediumn"))
                        .findElement(By.tagName("a")).findElement(By.tagName("img")).getDomAttribute("src"));
                // 优惠券标题
                item.setTitle(divList.get(j).findElement(By.className("union-good-card-title"))
                        .findElement(By.tagName("span")).getText());
                // 券前价格
                item.setPrePrice(getPrice(divList.get(j)
                        .findElement(By.className("union-good-card-coupon-reserve-price-mediumn"))));
                // 券后价格
                item.setPostPrice(getPrice(divList.get(j)
                        .findElement(By.className("union-good-card-coupon-final-price"))));
                List<WebElement> commissionList = divList.get(j).findElements(By.className("union-good-card-commision-info-item"));
                // 佣金率
                item.setCommissionRate(getPrice(commissionList.get(0)));
                // 佣金
                item.setCommission(getPrice(commissionList.get(1)));
                log.info(JSON.toJSONString(item));
                i++;
                if(i == 100) {
                    log.info("100条数据获取完毕");
                    return rstList;
                }
            }
            // 切换到下一页
            driver.findElement(By.className("GoodsList__Pagination-sc-84so0w-2"))
                    .findElement(By.className("mux-pagination-icon-next")).click();
            log.info("进入到下一页");
        }

        return rstList;

    }

    // 获取券前券后价格
    private Double getPrice(WebElement element) {
        StringBuilder sb = new StringBuilder();
        sb.append(element.findElement(By.className("union-number-format-integer")).getText().replaceAll(",", ""));
        sb.append(element.findElement(By.className("union-number-format-pointer")).getText());
        sb.append(element.findElement(By.className("union-number-format-decimal")).getText());
        Double price = Double.parseDouble(sb.toString());
        return price;
    }

}

最后看一下程序运行时的效果

可以看出来,selenium获取卡片的速度还是相对较慢的,有点像人在操作。

好啦,本文内容到此结束啦,有什么想法欢迎评论区和我讨论。


http://www.niftyadmin.cn/n/1008833.html

相关文章

JSP网上订餐管理系统用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 JSP 网上订餐管理系统是一套完善的web设计系统&#xff0c;对理解JSP java SERLVET mvc编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&a…

从入门到精通:解锁Linux开发工具和编译器的力量

目录 一.编辑器vim的使用1.vim的基本概念2.vim的使用二.编译器gcc/g1.编译器的使用2.编译器是如何完成的&#xff1f;3.动态库与静态库 一.编辑器vim的使用 1.vim的基本概念 vim是一个方便编程的功能特别丰富的文本编辑器&#xff0c;凭借他简洁的三种模式以及丰富的快捷键操…

JavaScript删除元素、移除、remove、removeChild、querySelector

文章目录 删除元素本身删除子元素删除父元素htmlJavaScriptremoveremoveChildquerySelector 删除元素本身 方法1.1 event.target.remove();方法1.2 event.target.parentNode.removeChild(event.target);方法2.1 idDeleteSelf.remove();方法2.2 idDeleteSelf.parentNode.re…

LwIP RAW API TCP服务端客户端编程及问题

TCP RAW API 1.1 新建TCP控制块 函数原型&#xff1a; struct tcp_pcb * tcp_new(void) 1.2 绑定控制块 tcp_bind() 用于服务端程序 将本地的 IP 地址、端口号与一个控制块进行绑定 函数原型&#xff1a; err_t tcp_bind(struct tcp_pcb *pcb, const p_addr_t *ipaddr, …

HTML5 游戏开发实战 | 俄罗斯方块

俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏&#xff0c;它曾经造成的轰动与造成的经济价值可以说是游戏史上的一件大事。这款游戏看似简单但却变化无穷&#xff0c;游戏过程仅需要玩家将不断下落的各种形状的方块移动、翻转&#xff0c;如果某一行被方块充满了&…

【networkx全教程】python DAG有向无环图 包含 edge 边缘标注text教程

1 基础教程 常用网站: 官方文档Github (latest development)NetworkX官方介绍: 登录后复制 NetworkX (NX) is a Python package for the creation, manipulation, and study of the structure, dynamics, and functions of complex networks.<https://networkx.lanl.go…

Win 10 重装系统(PE方式)

前言&#xff1a; 最近这个笔记本&#xff08;ThinkPad E480&#xff0c;使用了四年左右&#xff09;用起来很卡&#xff0c;经常开机状态时&#xff0c;合上之后&#xff0c;再打开屏幕就卡死了&#xff0c;鼠标和键盘按了都没有反应&#xff0c;无奈之下只能强制按电源关机后…

IP编址数据转发

目录 一、IP编址 1.1、二进制、十进制和十六进制 1.2、进制之间的转换 1.3、IP编址 1.4、子网掩码 1.5、二进制和十进制转换 1.6、IP地址分类 1.7、IP地址类型 1.8、地址规划 二、VLSM与CIDR 2.1、有类IP编址的缺陷 2.2、变长子网掩码 VLSM 2.3、缺省情况下的掩码 …