第五章 Electron|Node 使用cheerio 爬虫

一、cheerio是什么可以做什么 👇 👇 👇

Cheerio是一个快速、灵活且精益的jQuery核心实现,用于在Node.js环境中解析HTML文档。它可以帮助您在服务器端轻松地从HTML文档中提取数据,比如从网页中提取文章标题、内容、图片等信息。

二、为什么选择cheerio 👇 👇 👇

使用Cheerio的好处是它非常轻量级,因此可以很快地加载和解析HTML文档。此外,Cheerio的API与jQuery非常相似,因此如果您熟悉jQuery,那么学习和使用Cheerio也会非常容易。

三、安装依赖 👇 👇 👇

yarn add cheerio

我安装的版本

四、爬虫的资源以及资源分析 👇 👇 👇

这里以电脑壁纸 高清电脑壁纸大全 高清手机壁纸 彼岸桌面壁纸为例。本文只为学习,请不要对网站进行恶意攻击。

打开网站以后分析页面,页面结构我们只需要三个部分。一是分类,而是图片显示区域以及分页。

1、获取分类 👇 👇 👇

打开浏览器控制台

使用cheerio对应的代码如下,这里面的话有个核心的就是中文乱码的处理啊。

getPageInfo() {
    // {responseType: 'arraybuffer', responseEncoding: 'utf-8'} 这里是配置返回结果中文乱码的解决方案
    axios.get(this.source, {responseType: 'arraybuffer', responseEncoding: 'utf-8'}).then((res: any) => {
        // 中文乱码的解决方案
        let utf8decoder = new TextDecoder("GBK")
        const $: any = cheerio.load(utf8decoder.decode(res.data))
        // 分类
        const classify = $('.menu .cate')[0]['children']
        if (classify?.length) {
            const data = classify.filter((item: Element) => item.tagName === 'a')
            this.classifyList = data.map((item: Element) => {
                return !item.attributes[0].value.includes('http') && {
                    name: (item.children[0] as unknown as Text).data,
                    path: item.attributes[0].value
                }
            })
        }
    })
},

2、获取资源 👇 👇 👇

具体实现的代码如下。分页的逻辑也是一样的。自行分析,分页的获取代码也写在了一起。

getClassifyInfo(item: ClassifyType) {
    this.currentClassify = item
    this.currentIndex = 1
    this.currentResult = []
    axios.get(`${this.source}${item.path}`, {responseType: 'arraybuffer', responseEncoding: 'utf-8'}).then((res: any) => {
        // 中文乱码的解决方案
        let utf8decoder = new TextDecoder("GBK")
        const $: any = cheerio.load(utf8decoder.decode(res.data))
        this.splicing($)
    })
},
splicing($: any) {
    // 获取页面上的图片
    const list = $('#main .list ul li img')
    for (let i = 0; i < list.length; i++) {
        if ((list[i] as Element).attributes[0] && (list[i] as Element).attributes[1]) {
            this.currentResult.push({
                name: (list[i] as Element).attributes[1].name,
                path: (list[i] as Element).attributes[0].value
            })
        }
    }
    // 获取分页
    const page = $('#main .page').children()
    if (page[page.length - 1]) {
        let val: Text = page[page.length - 2].children[0]
        this.pageTotal = (val.data as any) - 0 || 0
    }
},

我使用的是pinia状态管理器,整个爬虫的代码如下:

完整代码

import { defineStore } from 'pinia';
import axios from "axios";
// @ts-ignore
const cheerio = require('cheerio')

export interface ClassifyType {
    name: string
    path: string
}

/**
 * @Description: 壁纸
 * @CreationDate 2023-05-31 17:04:13
 */
interface WallpaperModule {
    source: string // 源
    classifyList: ClassifyType[] // 分类
    currentClassify?: ClassifyType // 当前分类
    pageTotal: number // 总页数
    currentIndex: number // 当前分页
    currentResult: ClassifyType[] // 当前搜索出来的结果
}

/**
 * @Description: 壁纸爬取
 * @Author: Etc.End(710962805@qq.com)
 * @Copyright: TigerSong
 * @CreationDate 2023-05-31 17:01:36
 */
export const wallpaperModule = defineStore({
    id: 'wallpaper',
    state(): WallpaperModule {
        return {
            source: 'http://www.netbian.com',
            classifyList: [],
            pageTotal:0,
            currentIndex: 1,
            currentResult: []
        }
    },
    actions: {
        getPageInfo() {
            // {responseType: 'arraybuffer', responseEncoding: 'utf-8'} 这里是配置返回结果中文乱码的解决方案
            axios.get(this.source, {responseType: 'arraybuffer', responseEncoding: 'utf-8'}).then((res: any) => {
                // 中文乱码的解决方案
                let utf8decoder = new TextDecoder("GBK")
                const $: any = cheerio.load(utf8decoder.decode(res.data))
                // 分类
                const classify = $('.menu .cate')[0]['children']
                if (classify?.length) {
                    const data = classify.filter((item: Element) => item.tagName === 'a')
                    this.classifyList = data.map((item: Element) => {
                        return !item.attributes[0].value.includes('http') && {
                            name: (item.children[0] as unknown as Text).data,
                            path: item.attributes[0].value
                        }
                    })
                }
            })
        },
        getClassifyInfo(item: ClassifyType) {
            this.currentClassify = item
            this.currentIndex = 1
            this.currentResult = []
            axios.get(`${this.source}${item.path}`, {responseType: 'arraybuffer', responseEncoding: 'utf-8'}).then((res: any) => {
                // 中文乱码的解决方案
                let utf8decoder = new TextDecoder("GBK")
                const $: any = cheerio.load(utf8decoder.decode(res.data))
                this.splicing($)
            })
        },
        splicing($: any) {
            // 获取页面上的图片
            const list = $('#main .list ul li img')
            for (let i = 0; i < list.length; i++) {
                if ((list[i] as Element).attributes[0] && (list[i] as Element).attributes[1]) {
                    this.currentResult.push({
                        name: (list[i] as Element).attributes[1].name,
                        path: (list[i] as Element).attributes[0].value
                    })
                }
            }
            // 获取分页
            const page = $('#main .page').children()
            if (page[page.length - 1]) {
                let val: Text = page[page.length - 2].children[0]
                this.pageTotal = (val.data as any) - 0 || 0
            }
        },
        next(type: string) {
            if (this.currentClassify) {
                this.currentResult = []
                this.currentIndex = type === 'left' ? this.currentIndex - 1 : this.currentIndex + 1
                axios.get(`${this.source}${this.currentClassify.path}index_${this.currentIndex}.htm`, {responseType: 'arraybuffer', responseEncoding: 'utf-8'}).then((res: any) => {
                    // 中文乱码的解决方案
                    let utf8decoder = new TextDecoder("GBK")
                    const $: any = cheerio.load(utf8decoder.decode(res.data))
                    this.splicing($)
                })
            }
        }
    },
    getters: {},
});

五、编写渲染页面 👇 👇 👇

这里的话有个小问题,就是直接访问我们爬取的图片会返回401,只需要再index.html里面头部加入一个配置

<meta name="referrer" content="no-referrer" />
<template>
    <div>
        <div class="wallpaper-classify">
            <template v-for="(item, index) in classifyList">
                <div class="wallpaper-classify-item" v-if="item.name" :key="index" @click="getClassifyInfo(item)">{{item.name}}</div>
            </template>
        </div>
        <div style="display: flex;flex-direction: row;flex-wrap: wrap;justify-content: center;align-items: center;">
            <template v-for="(item, index) in currentResult">
                <el-image :preview-src-list="[item.path]" style="width: 300px;height: 169px;margin: 0 26px 20px 0;" :src="item.path" :alt="item.name"></el-image>
            </template>
        </div>
        <div v-if="pageTotal > 0" style="display: flex;justify-content: center;align-items: center;">
            <div style="margin-left: 20px;">当前在第 <span style="color: #009169">{{currentIndex}}</span> 页</div>
            <el-button size="small" style="margin-left: 20px;" v-if="currentIndex > 1" @click="goPage('left')">
                <template #icon>
                    <i-noto-backhand-index-pointing-left/>
                </template>
                上一页
            </el-button>
            <el-button size="small" style="margin-left: 20px;" v-if="currentIndex < pageTotal" @click="goPage('right')">
                <template #icon>
                    <i-noto-backhand-index-pointing-right/>
                </template>
                下一页
            </el-button>
            <div style="margin-left: 20px;">共 <span style="color: #009169">{{pageTotal}}</span> 页</div>
        </div>
    </div>
</template>

<script lang="ts">
import {defineComponent, onMounted, reactive} from "vue";
import appStore from "@/pinia";
import {storeToRefs} from "pinia";
import {ClassifyType} from "@/pinia/modules/wallpaper.modules.ts";

export default defineComponent({
    setup() {

        const { classifyList, currentResult, pageTotal, currentIndex } = storeToRefs(appStore.wallpaperModule)

        const getClassifyInfo = (item: ClassifyType) => {
            appStore.wallpaperModule.getClassifyInfo(item)
        }

        const goPage = (type: string) => {
            appStore.wallpaperModule.next(type)
        }

        onMounted(() => {
            appStore.wallpaperModule.getPageInfo()
        })

        return {
            classifyList,
            getClassifyInfo,
            currentResult,
            pageTotal,
            currentIndex,
            goPage,
        }
    }
})
</script>

<style scoped lang="scss">
    .wallpaper-classify {
        display: flex;
        padding: 20px 10px;
        justify-content: center;
        align-items: center;
    }
    .wallpaper-classify-item {
        cursor: pointer;
        & + & {
            margin-left: 12px;
        }
        &:hover {
            color: #03a9a9;
            border-bottom: 1px solid #03a9a9;
        }
    }
</style>

到这这一步就完成所有的代码了。你还可以接着扩展,比如下载图片等等

我是Etc.End。如果文章对你有所帮助,能否帮我点个免费的赞和收藏😍。

 👇 👇 👇 👇 👇 👇 👇 👇 👇 👇 👇 👇

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
使用ElectronNode.js程序封装成安卓应用需要经过一些额外的步骤,因为Electron主要是用于构建桌面应用程序。下面是一个大致的步骤: 1. 确保你已经安装了Node.js和Electron。 2. 在你的Node.js项目中,确保你的代码可以在Electron中正常运行。 3. 安装`electron-packager`: ```bash npm install electron-packager -g ``` 4. 创建一个新的文件夹,用于存放Electron项目的源代码。 5. 在新文件夹中创建一个新文件,命名为`main.js`,作为Electron应用的入口文件。 6. 在`main.js`中,编写Electron应用的主要逻辑和窗口配置。 7. 在终端中,导航到项目文件夹,并使用以下命令打包你的Electron应用: ```bash electron-packager . MyApp --platform=android --arch=armv7 --electron-version=<electron-version> --overwrite ``` 其中,`. `表示当前目录,`MyApp`是生成的安卓应用的名称,`--platform=android`表示指定打包为安卓平台,`--arch=armv7`表示指定打包为ARMv7架构,`--electron-version=<electron-version>`表示指定Electron的版本号,`--overwrite`表示覆盖已存在的输出目录。 8. 打包完成后,在输出目录中将会生成安卓应用的文件。你可以使用Android Studio将其导入,并进行进一步的构建、调试和签名。 需要注意的是,尽管使用Electron可以将Node.js程序封装为安卓应用,但这种方式可能会导致应用的体积较大,因为Electron本身包含了Chromium等组件。同时,Electron主要用于构建桌面应用,对于移动端应用可能会涉及到一些适配和性能方面的问题。因此,在封装Node.js程序为安卓应用时,需要综合考虑相关因素,并进行测试和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Etc.End

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值