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

news2024/11/15 19:34:19

本文将介绍使用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.coloradmin.cn/o/709946.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【剧前爆米花--爪哇岛寻宝】TCP实现可靠性的方法以及连接相关的三次握手四次挥手

作者&#xff1a;困了电视剧 专栏&#xff1a;《JavaEE初阶》 文章分布&#xff1a;这是一篇关于网络编程的文章&#xff0c;在这篇文章中我会具体介绍TCP是如何实现可靠性的并且分析建立断开连接的情况&#xff0c;希望对你有所帮助&#xff01; 目录 可靠性 确认应答 超时…

iOS开发进阶(一):走近iOS原生开发

文章目录 一、前言二、知识储备三、 Object-C四、启动流程五、拓展阅读 一、前言 在应用 uni-app 进行跨平台APP开发过程中&#xff0c;发现并不支持视频播放小窗功能&#xff0c;且插件市场提供的插件用户体验不好&#xff0c;遂决定自行开发 uni-app 原生插件。 uni-app原生…

力扣 450. 删除二叉搜索树中的节点

题目来源&#xff1a;https://leetcode.cn/problems/delete-node-in-a-bst/description/ C题解1&#xff1a;迭代法。删除节点需要分情况讨论&#xff1a; 找不到节点&#xff0c;返回原根节点&#xff1b;删除节点无子节点&#xff0c;那么其父节点指向空就行&#xff08;注意…

Java前端编译与优化

一个编译器的前端把*.java文件转变成*.class文件的过程称为Java前端编译。像Javac这类前端编译器对代码的运行效率几乎没任何优化措施&#xff0c;但是其做了许多针对Java语言编码过程的优化措施来降低程序员的编码复杂度、提供编码效率。 1 Javac编译器 准备过程 初始化插入…

《PyTorch深度学习实践》第十讲 卷积神经网络(基础篇)

b站刘二大人《PyTorch深度学习实践》课程第十讲卷积神经网络&#xff08;基础篇&#xff09;笔记与代码&#xff1a;https://www.bilibili.com/video/BV1Y7411d7Ys?p10&vd_sourceb17f113d28933824d753a0915d5e3a90 上一讲中MNIST数据集的例子采用的是全连接神经网络&#…

自然语言处理从入门到应用——预训练模型总览:两大任务类型

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 从大量无标注数据中进行预训练使许多自然语言处理任务获得显著的性能提升。总的来看&#xff0c;预训练模型的优势包括&#xff1a; 在庞大的无标注数据上进行预训练可以获取更通用的语言表示&#xff0c;并有利于下游…

python语法(高阶)-多线程编程

""" 演示多线程编程的使用 """ import time import threadingdef sing(msg):while True:print(msg)time.sleep(1)return Nonedef dance(msg):while True:print(msg)time.sleep(1)return Noneif __name__ __main__:# 创建一个唱歌的线程&#xf…

后台管理系统的权限(vue如何实现后台管理系统的权限,react如何实现后台管理系统的权限)

一、权限的解释 一般来说&#xff0c;在后台管理系统里肯定会使用到权限&#xff0c;权限一般分为功能级权限和数据级权限 1、功能级权限 1&#xff09;、页面级权限&#xff08;菜单&#xff09;&#xff1a; 不同的用户&#xff08;角色&#xff09;登录到管理系统后&#…

mysql load data infile 报错 1290 处理方法

mysql load data infile 命令导入数据报错"16:06:13 load data infile “/var/lib/mysql/test/employee.csv” into table emp fields terminated by ‘,’ ignore 1 lines Error Code: 1290. The MySQL server is running with the --secure-file-priv option so it cann…

Linux应用层开发--多线程进程编程

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言一、linux开发的方向二、Linux环境特点介绍Linux环境基本构成 三、进程与线程1、进程的概念2、进程的状态3、线程的概念4、线…

leetcode 559. N 叉树的最大深度

2023.7.2 这道题还是使用层序遍历&#xff0c;在N叉树的层序遍历的基础上增加一个求深度的操作即可。下面上代码&#xff1a; class Solution { public:int maxDepth(Node* root) {int depth 0;queue<Node*> que;if(root nullptr) return 0;que.push(root);while(!que…

json 压缩算法详解

概要 无论使用何种编程语言&#xff0c;json格式的数据已被广泛应用&#xff0c;不论是数据的传输还是存储&#xff0c;在很多应用场景下&#xff0c;你可能想进一步地压缩JSON字符串的长度&#xff0c;以提升传输效率&#xff0c;如果你使用的是nosql数据库&#xff0c;你可能…

2012年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题——纯享题目版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;考取过HCIE Cloud Computing、CCIE Security、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &#x1f495;兴趣爱好&#xff1a;b站天天刷&…

记一次tomcat版本升级导致的现网问题

前言 最近公司项目做安全漏洞审查&#xff0c;把一批服务的fastjson,tomcat,log4j版本做升级&#xff0c;那天上线了50个服务&#xff0c;所有服务上线之后&#xff0c;现网有客服反馈录音笔下单异常。查询了现网日志&#xff0c;发现适配服务有异常信息&#xff0c;报错信息如…

闲人闲谈PS之四十二——顾问的“禁忌之地”—制造能力计划

惯例闲话&#xff1a;上个月有幸成为乐老师乐谈IT系列培训课程的讲师&#xff0c;分享主题是&#xff0c;PS在装备制造和工程行业的应用。虽然培训规模不是很大&#xff0c;但是闲人很有信心&#xff0c;至少在小范围之内&#xff0c;参与培训的听友人来说&#xff0c;PS一直以…

什么条件下会出现死锁,如何避免?

文章目录 一、什么是死锁二、产生死锁的原因&#xff1a;三、如何避免死锁&#xff1a; 一、什么是死锁 死锁&#xff0c;简单来说就是两个或者两个以上的线程在执行过程中&#xff0c;去争夺同一个共享资源导致相互等待的现象。如果没有外部干预&#xff0c;线程会一直处于阻塞…

图像的算术操作

1.图像的加法 用途&#xff1a;图像的合成 Rain图片View图片 合成代码&#xff1a; import numpy as np import cv2 as cv import matplotlib.pyplot as pltrain cv.imread(rain.png) plt.imshow(rain[:, :, ::-1]) plt.show()view cv.imread(view.png) plt.imshow(view…

773. 滑动谜题

链接&#xff1a;773. 滑动谜题 题解&#xff1a;https://blog.csdn.net/INGNIGHT/article/details/131350054 滑动拼图 II class Solution { public:int slidingPuzzle(vector<vector<int>>& board) {// 异常判断if (board.size() < 0 || board[0].size…

怎么管理好一个团队?

一个成功的企业需要一个高效、有能力、积极的团队来支持其业务运营。管理一个团队需要领导者具备一定的技能和知识&#xff0c;怎么管理好一个团队对于许多企业领导者而言也是一项不小的挑战。对此&#xff0c;我想首先推荐一本非常优秀的团队书籍——《经理人参阅&#xff1a;…

js vuejs dagre-d3绘制流程图实用指南 有向图可视化

写在前面 之前有小伙伴问我如何使用 D3 在前端绘制流程图,今天在这里给安排上,与大家分享。 明确一点,只要你的数据计算能力足够强,使用原生D3绘制流程图绝对可以的,但是,为了让大家更容易上手,避免重复造轮子,给大家推荐一个专门绘制流程图的 D3 插件 dagre-d3。 首…