用 tensorflow.js 做了一个动漫分类的功能(一)

news2024/11/22 21:57:45

前言:

浏览某乎网站时发现了一个分享各种图片的博主,于是我顺手就保存了一些。但是一张一张的保存实在太麻烦了,于是我就想要某虫的手段来处理。这样保存的确是很快,但是他不识图片内容,最近又看了 mobileNet 的预训练模型,想着能让程序自己对图片分类,以下就通过例子从内容采集到分类的过程。

内容和资源的采集,反手就是某虫了。在网络上,经过近几年的营销渲染,可能首选是用 Python 做脚本。而这次是用 PHP 的 QueryList 来做采集,下面也就是采集的编码过程和踩坑解决方法,最后再对采集图片进行标注和训练。

环境:

PHP7.4

QueryList4.0

QueryList-CurlMulti

编码:

以下例子是基于 TP5.1,所以只需要安装上面两个依赖包。采集启动通过自定义命令实现,接下来分别以普通采集和多线程采集两种方式展示。

1. 普通采集

<?php/**
 * @Notes: 公众号:ZERO开发
 * @Interface getCondition
 * @Return mixed
 * @Author: bqs
 * @Time: 2021/4/19 15:28
 */namespaceapp\common\command;

usethink\console\Command;
usethink\console\Input;
usethink\console\Output;
usethink\console\input\Argument;
usethink\console\input\Option;
usethink\Db;
usethink\facade\Hook;
usethink\facade\Log;
useQL\QueryList;

classQueryListSpiderSingleextendsCommand{

    protectedfunctionconfigure(){
        $this->setName('querylist:single')
            ->setDescription('采集');
    }

    protectedfunctionexecute(Input $input, Output $output){
        ini_set('memory_limit', '512M');

        $output->writeln("=========date:" . date('Y-m-d H:i:s') . "===============");

        // 北桥苏奥特曼//$slImgsUrl = "https://zhuanlan.zhihu.com/p/377571373";
        $slImgsUrl = "https://zhuanlan.zhihu.com/p/344680014";

        // 原生query_list
        $list = QueryList::get($slImgsUrl)->find('.RichText')->find('noscript')->find('img')->attrs('src');

        $path = 'E:\2setsoft\1dev\phpstudy_pro\WWW\4test\tensorflowJs\js-ml-code\t7\动漫分类\train\奥特曼\\';
        foreach($list as $key => $value) {
            $index = $key + 1 + 42;

            $filename = $index < 10 ? str_pad($index, 2, "0", STR_PAD_LEFT) : $index;
            $filend = pathinfo($value, PATHINFO_EXTENSION);
            $file = file_get_contents($value);
            file_put_contents($path . $filename . "." . $filend, $file);

            $output->writeln($index . "--" . $value . "已保存--");
        }

        $output->writeln("============date:" .date("Y-m-d H:i:s") . "采集完成==============");
    }
    
}

2. 多线程采集

<?php/**
 * @Notes: 文件描述
 * @Interface getCondition
 * @Return mixed
 * @Author: bqs
 * @Time: 2021/4/19 15:28
 */namespaceapp\common\command;

usethink\console\Command;
usethink\console\Input;
usethink\console\Output;
usethink\console\input\Argument;
usethink\console\input\Option;
usethink\Db;
usethink\facade\Hook;
usethink\facade\Log;
useQL\QueryList;
useQL\Ext\CurlMulti;

classQueryListSpiderextendsCommand{

    protectedfunctionconfigure(){
        $this->setName('query:list')
            ->setDescription('采集');
    }

    protectedfunctionexecute(Input $input, Output $output){
        ini_set('memory_limit', '512M');

        $output->writeln("=========date:" . date('Y-m-d H:i:s') . "===============");

        // 地址与目录映射
        $dirMap = [
            "假面骑士" => "https://zhuanlan.zhihu.com/p/376119915",
            "龙珠" => "https://zhuanlan.zhihu.com/p/340048917",
            "火影忍者" => ["https://zhuanlan.zhihu.com/p/352717188", "https://zhuanlan.zhihu.com/p/393213201", "https://zhuanlan.zhihu.com/p/358228745"],
            "海贼王" => ["https://zhuanlan.zhihu.com/p/357683518", "https://zhuanlan.zhihu.com/p/338160632"]
        ];

        // 采集地址
        $multiArr = [];
        $multiArr = array_reduce(array_values($dirMap), function($res, $value){
            $res = array_merge($res, (array)$value);
            return $res;
        }, []);

        // 采集映射
        $multiMap = [];
        foreach($dirMap as $key => $value) {
            if (!is_array($value)) {
                $multiMap[$value] = $key;
            } else {
                $temp = array_fill_keys($value, $key);
                $multiMap = array_merge($multiMap, $temp);
            }
        }

        // 开始使用多线程采集
        $ql = QueryList::use (CurlMulti::class);
        $ql->curlMulti($multiArr)
        ->success(function(QueryList $ql, CurlMulti $curl, $r)use($multiMap){

            $path = 'E:\2setsoft\1dev\phpstudy_pro\WWW\4test\tensorflowJs\js-ml-code\t7\动漫分类\train\\';
            $queryUrl = $r['info']['url'];
            $className = $multiMap[$queryUrl] ?? "";
            $targetDir = $path . $className;
            $path = $targetDir . '\\';

            $endFileIndex = 0;
            $existFileList = $this->scanFile($targetDir);
            if ($existFileList) {
                // 取出所有数字文件名最大值
                $endFileName = max($existFileList);
                $endFileIndex = explode(".", $endFileName)[0];
            }

            $data = $ql->find('.RichText')->find('noscript')->find('img')->attrs('src');

            foreach($data as $key => $value) {
                $index = $key + 1 + $endFileIndex;

                $filename = $index < 10 ? str_pad($index, 2, "0", STR_PAD_LEFT) : $index;
                $filend = pathinfo($value, PATHINFO_EXTENSION);
                $file = file_get_contents($value);
                file_put_contents($path . $filename . "." . $filend, $file);
            }
        })
        // 每个任务失败回调
        ->error(function($errorInfo, CurlMulti $curl){
            echo"Current url:{$errorInfo['info']['url']} \r\n";
            print_r($errorInfo['error']);
        })
        ->start([
            // 最大并发数'maxThread' => 10,
            // 错误重试次数'maxTry' => 5,
        ]);

        $output->writeln("============date:" . date("Y-m-d H:i:s") . "采集完成==============");
    }

    // 扫描目录下所有文件protectedfunctionscanFile($path){
        $result = [];
        $files = scandir($path);
        foreach ($files as $file) {
            if ($file != '.' && $file != '..') {
                if (is_dir($path . '/' . $file)) {
                    $this->scanFile($path . '/' . $file);
                } else {
                    $result[] = basename($file);
                }
            }
        }
        return $result;
    }

}

问题解决:

由于普通采集的请求使用 GuzzleHttp 客户端,而多线程采集是 CURL,所以运行时报 curl 状态码 60 错误。

1. 解决方法:

(1). 下载 cacert

下载地址:https://curl.haxx.se/ca/cacert.pem

(2). 修改 php.ini , 并重启

在 php.ini 中找到 curl.cainfo 改为文件的绝对路径如:curl.cainfo =E:\2setsoft\1dev\phpstudy_pro\Extensions\php\php7.4.3nts\cacert.pem

图片训练:

以上的图片已经采集的差不多了,因为博主的图片有限,我也没有再去其他地方找,整个文件夹下的图片在 200 张左右。按理说图片当然是越多越好,但是整个分类标注起来耗时(看文章的配图,应该已经知道有哪几类了吧),所以就这样了。最后就是读取图片转换 Tensor 进行训练,后一篇再具体介绍吧,提醒一下。下一篇需要提前安装 Node, Http-Server,Parcel 工具。

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

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

相关文章

【Kafka】三.Kafka怎么保证高可用 学习总结

Kafka 的副本机制 Kafka 的高可用实现主要依赖副本机制。 Broker 和 Partition 的关系 在分析副本机制之前&#xff0c;先来看一下 Broker 和 Partition 之间的关系。Broker 在英文中是代理、经纪人的意思&#xff0c;对应到 Kafka 集群中&#xff0c;是一个 Kafka 服务器节…

Blazor入门100天 : 身份验证和授权 (4) - 自定义字段

目录 建立默认带身份验证 Blazor 程序角色/组件/特性/过程逻辑DB 改 Sqlite将自定义字段添加到用户表脚手架拉取IDS文件,本地化资源freesql 生成实体类,freesql 管理ids数据表初始化 Roles,freesql 外键 > 导航属性完善 freesql 和 bb 特性 本节源码 https://github.com/…

数据备份学习笔记2

Linux实现本地备份的命令&#xff1a; mkdir -p /root/backup/date "%Y-%m-%d" tar -zcvPf /root/backup/date "%Y-%m-%d"/test20230221.tar.gz /root/test20230221/ 我们再看下tar命令选项&#xff1a; tar -czvf txt3.tar.gz txt3 tar -xvf txt4.tar.g…

二叉查找树(C++)

背景&#xff1a; 最近我要学习二叉平衡树了&#xff0c;在学习二叉平衡树之前&#xff0c;我需要学会二叉搜索树&#xff0c;因为二叉平衡树就是根据二叉搜索树的思想进行优化的。 二叉查找树简介&#xff1a; 二叉查找树是什么呢&#xff1f;&#xff08;也叫二叉搜索树&…

国产无线蓝牙耳机哪个好?2023国产无线蓝牙耳机排行

随着蓝牙耳机的快速发展&#xff0c;近几年国产蓝牙耳机更是呈指数式爆发&#xff0c;越来越多的国产蓝牙耳机品牌被人们看到、认可。那么&#xff0c;国产无线蓝牙耳机哪个好&#xff1f;下面&#xff0c;我来给大家推荐几款国产蓝牙耳机&#xff0c;一起来看看吧。 一、南卡…

C语言实现动态管理通讯录信息系统(静态通讯录plus版)

文章目录前言&#xff1a;一.动态管理思想1.通讯录结构体声明发生变化2.通讯录结构体初始化发生变化3.通讯录能够动态增容4.通讯录销毁数据二.优化通讯录可持续读写信息1.保存通讯录中的信息到文件中2.加载文件信息到通讯录中三.源码1.text.c2.contact.c3.contact.h前言&#x…

Kotlin新手教程七(委托)

委托模式是软件设计模式中的一项基本技巧。在委托模式中&#xff0c;有两个对象参与处理同一个请求&#xff0c;接受请求的对象将请求委托给另一个对象来处理。kotlin中使用by实现委托。 一、类委托 类的委托实际就是一个类中定义的方法实际是调用另一个类中的对象的方法来实现…

5.7 BGP属-ORIGIN

配置BGP ORIGIN属性控制选路 1. 实验目的 熟悉BGP ORIGIN属性控制选路的应用场景掌握BGP ORIGIN属性控制选路的配置方法2. 实验拓扑 实验拓扑如图5-7所示: 图5-7:BGP ORIGIN属性控制选路 3. 实验步骤 (1)配置IP地址 …

实验室通风橱通风柜的构成

一、实验室通风橱通风柜简介通风柜是一个密闭的同时又能排风的工作空间。其设计目的是为了控制、稀释以及排除这个密闭空间内产生制造的烟气、气雾和微粒&#xff0c;同时它也是实验室预防泄露控制的重要组成部分。在大多数实验室中&#xff0c;通风柜是保护实验室操作者免受有…

ubantu python完整安装示例(python3.7.1演示)

文章目录前言准备源码包1.下载2.解压准备工作&#xff08;重要&#xff09;1.下载cmake(用于编译源码&#xff09;2.下载必要的Module注意事项编译安装链接并验证配置环境变量1.移除原3.5link2.更换默认python3 的版本为3.73.添加路径前言 为什么需要使用源码编译安装&#xf…

分享项目 - Vue3 + TS + element-ui-plus 项目 -- Table表格表单

文章目录前言项目地址以及怎么阅读别人的代码整体代码分页数据作者是怎么处理的 usePagination顺藤摸瓜找到 api 接口的封装api 接口再往底层找全局请求封装与请求拦截器 service.ts前言 今天看一个 ts 项目的 table 模块&#xff0c;亲身体验这是公司后台管理系统一定会使用到…

Springboot @Test 给Controller接口 写 单元测试

前言 最近有小伙伴问到怎么给 controller的接口写单元测试。 单元测试是开发必不可少的一个环节。 既然有人问到了&#xff0c;那我觉得可能不止一个人不会&#xff0c;那就按照惯例&#xff0c;出手。 正文 内容&#xff1a; 主要是get 和 post 两种请求方式的接口 的 单元测…

centos7 开机自启动自定义脚本

centos7 开机自启动自定义脚本背景配置自启动jar1.首先书写自启动脚本2.在rc.local中加入脚本reboot测试docker版本的自启动背景 项目中有遇到2个问题&#xff0c; 1&#xff1a; 使用java启动jar包 2&#xff1a; docker容器中自启动个服务。 这2个都要使用linux的开机自启动问…

AcWing 1017. 怪盗基德的滑翔翼

怪盗基德是一个充满传奇色彩的怪盗&#xff0c;专门以珠宝为目标的超级盗窃犯。而他最为突出的地方&#xff0c;就是他每次都能逃脱中村警部的重重围堵&#xff0c;而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。有一天&#xff0c;怪盗基德像往常一样偷走了一颗珍贵…

【图像分类】卷积神经网络之LeNet5网络模型实现MNIST手写数字识别

写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 在上一篇博文中我们对LeNet5网络模型的结构进行了剖析,本篇博文,我们将使用PyTorch搭建LeNet5实现MNIST手写数字…

使用vmware制作云平台redhat7.9镜像模板

一、概述 1.1 redhat7.9 定制镜像上传到云平台。 这个制作镜像得方式适用于多种iso 镜像。 将iso 镜像通过vmware 创建出一台虚机&#xff0c;对虚机做一些基础配置。在虚机上安装kvm 虚拟化得工具&#xff0c; 将iso 镜像在导入虚机种通过kvm创建一下虚机&#xff0c; 虚机创…

Embedding 理解

Word Embedding 单词表示最简单的是 one-hot 但是它的缺点是 矩阵表示过于稀疏&#xff0c;占用空间对相关的词语无法得知它们的含义是相近的。 Word Embedding 解决了上述两个缺点&#xff0c;一个 Word Embedding 直观的例子如下图所示。 每个维度表示一个特征&#xff0…

简述操作系统的文件系统

前言 文件系统是操作系统中负责管理持久数据的子系统&#xff0c;将用户的文件保存在硬盘等硬件设备中&#xff0c;即使断电了数据也不会丢失。 对于用户而言&#xff0c;文件是存储的最小单位&#xff0c;再少的数据也需要以文件的形式存储在外部存储器中。以硬盘为例&#…

金三银四,我不允许你们不知道这些软件测试面试题

01、您所熟悉的测试用例设计方法都有哪些&#xff1f;请分别以具体的例子来说明这些方法在测试用例设计工作中的应用。 答&#xff1a;有黑盒和白盒两种测试种类&#xff0c;黑盒有等价类划分法&#xff0c;边界分析法&#xff0c;因果图法和错误猜测法。白盒有逻辑覆盖法&…

DataX及DataX-Web

大数据Hadoop之——数据同步工具DataX数据采集工具-DataX datax详细介绍及使用 一、概述 DataX 是阿里云DataWorks数据集成的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、…