简明指南:使用Kotlin和Fuel库构建JD.com爬虫

news2025/1/18 17:13:53

亿牛云代理

概述

爬虫,作为一种自动化从网络上抓取数据的程序,广泛应用于数据分析、信息提取以及竞争对手监控等领域。不同的实现方式和编程语言都能构建出高效的爬虫工具。在本文中,我们将深入介绍如何充分利用Kotlin和Fuel库,构建一个简单而强大的JD.com爬虫,以便迅速获取商品的各种信息,包括名称、价格和评分等。
Kotlin是一门基于JVM的静态类型编程语言,以其简洁、高效、安全、跨平台等特点而著称。这门语言不仅适用于Android开发,还可用于服务器端和Web应用程序的开发。Fuel库作为一款轻量级的Kotlin HTTP客户端,提供了一套简洁易用的DSL(领域特定语言),使得发送HTTP请求和处理响应变得异常便捷。除此之外,Fuel还支持协程、异步操作、JSON处理以及文件上传等多种功能,以满足各种网络编程需求。

正文

1. 创建项目和添加依赖

首先,我们需要创建一个Kotlin项目,可以使用任何IDE或编辑器,如IntelliJ IDEA、VS Code等。然后,我们需要在项目的build.gradle文件中添加Fuel库的依赖,如下所示:

dependencies {
    implementation "com.github.kittinunf.fuel:fuel:2.3.1" // Fuel核心库
    implementation "com.github.kittinunf.fuel:fuel-coroutines:2.3.1" // Fuel协程支持库
    implementation "com.github.kittinunf.fuel:fuel-json:2.3.1" // Fuel JSON解析库
}

2. 定义数据类和常量

接下来,我们需要定义一个数据类,用来存储商品的信息,如下所示:

data class Product(
    val name: String, // 商品名称
    val price: Double, // 商品价格
    val score: Double, // 商品评分
    val comments: Int // 商品评论数
)

我们还需要定义一些常量,用来表示JD.com的域名、搜索接口、爬虫代理服务器等,如下所示:

const val BASE_URL = "https://www.jd.com" // JD.com的域名
const val SEARCH_URL = "$BASE_URL/search" // JD.com的搜索接口
const val PROXY_HOST = "www.16yun.cn" // 亿牛云爬虫代理的域名
const val PROXY_PORT = 6443 // 亿牛云爬虫代理的端口
const val PROXY_USER = "16xxxxxx" // 亿牛云爬虫代理的用户名
const val PROXY_PASS = "xxxxxxxx" // 亿牛云爬虫代理的密码

3. 发送HTTP请求和解析响应

然后,我们需要编写一个函数,用来发送HTTP请求到JD.com的搜索接口,并解析响应中的商品信息,如下所示:

suspend fun searchProducts(keyword: String, page: Int): List<Product> {
    // 构造请求参数
    val params = listOf(
        "keyword" to keyword, // 搜索关键词
        "enc" to "utf-8", // 编码格式
        "page" to page // 页码
    )
    // 发送GET请求,并使用协程等待响应
    val response = Fuel.get(SEARCH_URL, params)
        .header("User-Agent" to "Mozilla/5.0") // 设置请求头,模拟浏览器
        .proxy(PROXY_HOST, PROXY_PORT) // 设置代理服务器,绕过反爬
        .authenticate(PROXY_USER, PROXY_PASS) // 设置代理认证信息
        .awaitStringResponse() // 使用协程等待字符串响应
    // 获取响应的状态码和内容
    val (request, result, content) = response
    // 判断响应是否成功
    if (result is Result.Success) {
        // 创建一个空的商品列表
        val products = mutableListOf<Product>()
        // 使用正则表达式匹配商品信息
        val regex = """<li.+?class="gl-item".+?<em>(.+?)</em>.+?<i>(\d+\.\d+)</i>.+?<strong.+?data-done="1">(\d+\.\d+)</strong>.+?<a.+?comment="(\d+)".+?</li>""".toRegex()
        // 遍历每一个匹配结果
        for (match in regex.findAll(content)) {
            // 获取商品名称、价格、评分、评论数
            val name = match.groupValues[1]
            val price = match.groupValues[2].toDouble()
            val score = match.groupValues[3].toDouble()
            val comments = match.groupValues[4].toInt()
            // 创建一个商品对象,并添加到列表中
            val product = Product(name, price, score, comments)
            products.add(product)
        }
        // 返回商品列表
        return products
    } else {
        // 响应失败,抛出异常
        throw Exception("Request failed: ${result.error}")
    }
}

4. 使用多线程提高采集效率

最后,我们需要编写一个主函数,用来调用上面的函数,并使用多线程提高采集效率,如下所示:

fun main() = runBlocking {
    // 定义一个搜索关键词
    val keyword = "手机"
    // 定义一个页码范围
    val pages = 1..10
    // 创建一个线程池
    val executor = Executors.newFixedThreadPool(10)
    // 创建一个协程作用域
    val scope = CoroutineScope(executor.asCoroutineDispatcher())
    // 创建一个空的商品列表
    val allProducts = mutableListOf<Product>()
    // 使用协程并发发送请求
    val jobs = pages.map { page ->
        scope.launch {
            // 调用搜索函数,获取商品列表
            val products = searchProducts(keyword, page)
            // 将商品列表添加到总列表中
            allProducts.addAll(products)
            // 打印当前页的商品数量
            println("Page $page: ${products.size} products")
        }
    }
    // 等待所有协程完成
    jobs.joinAll()
    // 关闭线程池
    executor.shutdown()
    // 打印总的商品数量
    println("Total: ${allProducts.size} products")
    // 打印前10个商品的信息
    allProducts.take(10).forEach { product ->
        println(product)
    }
}

结语

本文介绍了如何使用Kotlin和Fuel库构建一个简单的JD.com爬虫,从而获取商品的名称、价格、评分等信息。本文还展示了如何使用代理IP技术,绕过网站的反爬策略,以及如何使用多线程技术,提高采集效率。本文的代码仅供参考,实际使用时可能需要根据网站的变化进行调整。希望本文能对您有所帮助,感谢您的阅读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1280622.html

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

相关文章

Autosar COM通信PDU

文章目录 Autosar 中各个PDU所在示意图PDU的分类PDU 和 SDU 的关系I-PDUN-PDUL-PDU相关协议其他参考 Autosar 中各个PDU所在示意图 PDU的分类 在Autosar 中&#xff0c;主要有 I-PDU、N-PDU和 L-PDU 三种。 L-PDU&#xff1a;Data Link Layer PDU&#xff0c;数据链路层PDUN-…

Qt/QML编程学习之心得:如何添加资源文件到QML工程(十一)

Qt作为一种GUI界面编辑工具&#xff0c;在嵌入式编程中也大受欢迎&#xff0c;而进一步QML出现了&#xff0c;QML我理解也是一种资源文件&#xff0c;因为像其他资源文件一样添加进工程的。那么一个图片如何增加进资源文件呢&#xff1f;这个的确很基础&#xff0c;就是把资源文…

JavaEE 多线程

JavaEE 多线程 文章目录 JavaEE 多线程引子多线程1. 特性2. Thread类2.1 概念2.2 Thread的常见构造方法2.3 Thread的几个常见属性2.4 启动一个线程2.5 中断一个线程2.6 等待一个线程2.7 获取当前线程引用2.8 休眠当前线程 3. 线程状态 引子 当进入多线程这一块内容时&#xff…

Redis中分布式锁的使用

在分布式系统中&#xff0c;如果使用JVM中的同步锁在高并发的场景下仍然会产生线程安全问题。首先我们来查看在多个服务器时为什么会产生线程安全问题&#xff0c;有这样一个案例&#xff0c;有一件商品购买规则为一个用户只能购买一次&#xff0c;如果使用同步锁锁住用户id&am…

vue3中自定义hook函数

使用Vue3的组合API封装的可复用的功能函数 自定义hook的作用类似于vue2中的mixin技术 自定义Hook的优势: 很清楚复用功能代码的来源, 更清楚易懂 案例: 收集用户鼠标点击的页面坐标 hooks/useMousePosition.ts文件代码&#xff1a; import { ref, onMounted, onUnmounted …

【读书笔记】微习惯

周日晚上尝试速读一本书《微习惯》&#xff0c;共七章看了下目录结构并不复杂&#xff0c;计划每章7-8分钟读完&#xff0c; 从20:15-21:00。读的时候&#xff0c;订下闹钟&#xff0c;催促着自己的进度。边读边记了一些要点和微信读书里面的划线。 第六章实践内容最为丰富&…

1949-2021年全国31省铁路里程数据

1949-2021年全国31省铁路里程数据 1、时间&#xff1a;1949-2021年 2、指标&#xff1a;时间、省份、铁路里程 3、范围&#xff1a;包括31省 4、数据缺失情况说明&#xff1a;西藏2005年之前存在缺失&#xff0c;其余30省份1978-2020年无缺失 5、来源&#xff1a;各省统计…

C++实现DFS、BFS、Kruskal算法和Prim算法、拓扑排序、Dijkstra算法

背景&#xff1a; 实现要求&#xff1a; 根据图的抽象数据类型的定义&#xff0c;请采用邻接矩阵来存储图1&#xff0c;采用邻接表来存储图2&#xff0c;并完成如下操作&#xff1a;对图1无向图进行深度优先遍历和广度优先遍历。对图1无向图采用Kruskal算法和Prim算法得出最小…

uni-app 微信小程序之自定义navigationBar顶部导航栏

文章目录 1. 实现效果2. App.vue3. pages.json 配置自定义4. 顶部导航栏 使用 微信小程序自定义 navigationBar 顶部导航栏&#xff0c;兼容适配所有机型 1. 实现效果 2. App.vue 在App.vue 中&#xff0c;设置获取的 StatusBar&#xff0c;CustomBar 高度&#xff08;实现适配…

【云原生Prometheus篇】Prometheus PromQL语句详解 1.0

文章目录 一、前言1.1 Prometheus的时间序列1.1.1 指标名称1.1.2 标签1.1.3 使用的注意事项 1.2 样本数据格式1.3 Prometheus 的聚合函数 二 、PromQL 理论部分2.1 PromQL简介2.2 PromQL的数据类型2.3 时间序列选择器2.3.1 瞬时向量选择器 &#xff08;Instant Vector Selector…

python装饰器解析(关键点:高阶函数、嵌套函数)(参数化装饰器、类装饰器)

文章目录 Python装饰器解析什么是Python装饰器基础理解 如何创建装饰器&#xff08;关键点&#xff1a;高阶函数、嵌套函数&#xff09;创建基础装饰器 使用装饰器使用示例 装饰器的返回值参数化装饰器创建参数化装饰器语法示例使用示例 类装饰器创建类装饰器语法示例使用示例 …

使用postman请求x5接口

x5接口简介 1.接口样例 {"header"{"appid":"bpmnew_fanwei","sign":"C033162E86E4CADE80C7EB44D68A5AD2","sign_type":"md5","url":"https://oa.mioffice.cn/api/bpm/xm/app/show/tod…

MySQL索引优化实战二

分页查询优化 很多时候我们业务中实现分页功能时可能会用如下SQL来实现&#xff1a; select * from employees LIMIT 10000,10表示从表中中区从10001行开始的10行记录&#xff0c;看似只查了10条记录&#xff0c;但是这条SQL是先读取10010条记录&#xff0c;然后抛弃前10000条…

【个人笔记】-python-强化学习-类-在内存中的值

{int} 数值 {int} 200 {float} 数值 {float} 0.9 {narray:维度} 数值 {narray:(1,)} [2.] {bool} True {bool} False {类名} 对象1 {类名} 对象2

LLM 开发模式 RAG,MRKL,Re-Act,Plan-Execute 模式对比

本心、输入输出、结果 文章目录 LLM 开发模式 RAG&#xff0c;MRKL&#xff0c;Re-Act&#xff0c;Plan-Execute 模式对比前言RAG、MRKL、Re-Act和Plan-Execute模式的一些对比花有重开日&#xff0c;人无再少年实践是检验真理的唯一标准 LLM 开发模式 RAG&#xff0c;MRKL&…

MySQL进阶_EXPLAIN重点字段解析

文章目录 第一节.准备1.1 版本信息1.2 准备 第二节.type2.1 system2.2 const2.3 eq_ref2.4 ref2.5 ref_or_null2.6 index_merge2.7 unique_subquery2.8 range2.9 index2.10 all 第三节. Extra3.1 No tables used3.2 No tables used3.3 Using where3.4 No matching min/max row3…

基于springboot实现的垃圾分类管理系统

一、系统架构 前端&#xff1a;html | layer | jquery | css 后端&#xff1a;springboot | mybatis 环境&#xff1a;jdk1.8 | mysql | maven 二、 代码及数据库 三、功能介绍 01. 登录页 02. 系统设置-用户管理 03. 系统设置-页面管理 04. 系统设置-角色管…

Python练习题(二)

&#x1f4d1;前言 本文主要是【Python】——Python练习题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&am…

三极管在数字电路中的应用

一、认识三极管 三极管拥有3个引脚&#xff0c;分别对应3个级&#xff1a;基极(Base)、发射极&#xff08;Emitter&#xff09;、集电极(Collector)&#xff0c;如下图所示&#xff1b;下图横向左侧的是基极&#xff0c;带箭头的那个引脚就是发射极&#xff0c;另一个就是集电…

ElementPlus中 使用ElLoading.service, spinner: ‘el-icon-loading‘不生效

let downloadLoadingInstance ElLoading.service({ text: "正在下载数据&#xff0c;请稍候",spinner: el-icon-loading, background: "rgba(0, 0, 0, 0.7)", })使用以上代码时&#xff0c;加载的圆圈出不来&#xff0c;使用f12查看&#xff0c;即使能出…