用PHP异步协程控制python爬虫脚本,实现多协程分布式爬取
背景
公司需要爬取指定网站的产品数据。但是个人对python的多进程和协程不是特别熟悉。所以,想通过php异步协程,发起爬取url请求控制python爬虫脚本,达到分布式爬取的效果。
准备
- 1.准备一个mongodb数据库用于存放爬取数据
- 2.引入flask包,方便php通过调用url发起请求控制脚本
- 3.引入selenium、BeautifulSoup4、webdriver等python包
- 4.使用php的swoole异步协程发送url请求
python爬虫脚本
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
from flask import Flask,jsonify,request
from pymongo import MongoClient
from datetime import datetime
from gevent import pywsgi
import sys
import requests
import re
from tornado.httpserver import HTTPServer
from tornado.wsgi import WSGIContainer
from tornado.ioloop import IOLoop#创建一个服务,赋值给APP
app = Flask(__name__)@app.route('/get_ic_product_list',methods=['post']) #指定接口访问的路径,支持什么请求方式get,post
def get_ic_product_list():# url = 'https://www.ic.com/psen/ClassList2.aspx?id=3'# url = 'https://www.ic.com/ClassList2.aspx?id=3'chrome_options = webdriver.ChromeOptions()chrome_options.add_argument('--no-sandbox')chrome_options.add_argument('--headless')chrome_options.add_argument('--disable-gpu')chrome_options.add_argument('--ignore-certificate-errors')browser = webdriver.Chrome()conn = MongoClient('192.168.0.143', 27017)try:uri = request.form.get('url')# 是否按照零库存处理 yes-是 no-否isContinue = request.form.get('is_continue_stock', 'yes')# uri = sys.argv[1]# isContinue = sys.argv[2]if uri == '':return jsonify({'status': 0, 'msg': 'uri is null'})browser.get(uri)browser.implicitly_wait(3)time.sleep(2)# 连接mongodatabase = conn.iccollection = database.ic_product# 时间格式化nowtime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')spiderTime = datetime.now().strftime('%Y%m%d')spidertime = int(spiderTime)# 总页数pageTag = browser.find_element(By.CLASS_NAME, 'P_Page')total_page = pageTag.text.strip().split('/')[1]# 分类列表,不按照stock=0处理cateMap = ['21', '43', '175','179','184','241','250','268','306','317','325','343','397','394','409','467','547','556','606','638','657','678','1150','1158','2315','2383']if total_page:t_page = int(total_page)if t_page > 20:totalPage = 55else:totalPage = t_pageelse:totalPage = 20stop = 0soup = BeautifulSoup(browser.page_source, 'html.parser')tables = soup.findAll(name="table", attrs={"class": "prilist"})if len(tables) > 0:for table in tables:# 阶梯价price_tb = table.findAll('tr')price = [tb.text.strip() for tb in price_tb]# 行数据cols = table.parent.parentitem = [col.text.strip() for col in cols]time.sleep(2)print('==========item==========')print(item)# 库存为0,终止程序stock = item[11]if stock == '-':stop += 1continuepos = item[3].find('Promotion')if pos != -1:sku = str(item[3].replace('(Promotion)', ''))else:sku = item[3]# 格式化数据collection.insert_one({'datasheet': str(item[0]),'img_url': str(item[1]),'productDescEn': str(item[2]),'part': sku,'manufacturer': str(item[5]),'description': str(item[7]),'pdfLinkUrl': str(item[10]),'availability': str(item[11]),'price': price,'created_at': nowtime,'spider_time': spidertime,'sync_time': 20010101,'updated_at': '2001-01-01 00:00:00',})# 接口请求在clickfor i in range(totalPage):print('==========i==========')print(i)browser.find_element(By.XPATH, './/div[@id="Pager1"]/a[9]').click()soup = BeautifulSoup(browser.page_source, 'html.parser')tables = soup.findAll(name="table", attrs={"class": "prilist"})print('==========stop==========')print(stop)if stop>10 and isContinue=='yes':breakif len(tables) < 1:return jsonify({'status': 0, 'msg': 'product list empty'})print('==========tables==========')print(tables)mongoData = []for table in tables:# 阶梯价price_tb = table.findAll('tr')price = [tb.text.strip() for tb in price_tb]# 行数据cols = table.parent.parentitem = [col.text.strip() for col in cols]time.sleep(2)print('==========item==========')print(item)# 库存为0,终止程序stock = item[11]if stock == '-':stop += 1continuepos = item[3].find('Promotion')if pos != -1:sku = str(item[3].replace('(Promotion)', ''))else:sku = item[3]# 格式化数据mongoData.append({'datasheet': str(item[0]),'img_url': str(item[1]),'productDescEn': str(item[2]),'part': sku,'manufacturer': str(item[5]),'description': str(item[7]),'pdfLinkUrl': str(item[10]),'availability': str(item[11]),'price': price,'created_at': nowtime,'spider_time': spidertime,'sync_time': 20010101,'updated_at': '2001-01-01 00:00:00',})# 插入mongomongoData and collection.insert_many(mongoData)print('================mongoData================')print(mongoData)del price, tablestime.sleep(5)return jsonify({'status': 1,'msg': 'ok'})except Exception as error:return jsonify({'status':0,'msg':error})finally:conn.close()browser.close()if __name__ == '__main__':app.run(host='0.0.0.0',port=8005,debug=True) # 启动服务器# Tornado启动服务
# s = HTTPServer(WSGIContainer(app))
# s.listen(8005) # 监听 8080 端口
# IOLoop.current().start()
php协程调用curl请求封装
在laravel 框架下创建command服务
此处有用到redis队列的,有不熟悉的请阅读redis相关资料
<?php
/*** 爬取IC任务*/
namespace App\Console\Commands;use App\Models\IcProductCategoryModel;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
use Swoole\Timer;class SpiderIcProductList extends Command
{/*** The name and signature of the console command.** @var string*/protected $signature = 'spider:ic_product';/*** The console command description.** @var string*/protected $description = '每天定时爬取IC网站数据';/*** Create a new command instance.** @return void*/public function __construct(){parent::__construct();}/*** Execute the console command.** @return int*/public function handle(){$this->getProduct();return 0;}public function getProduct(){/*** ic product_num> 0, 分类约345个* 目前15min【900 * 1000】爬取10个分类,一天能爬取960个分类,一天能爬2次*/Timer::tick(60 * 15 * 1000,function (){$categoryModel = new IcProductCategoryModel();$key = $categoryModel::getCategoryQueue();echo 'time:' .date('H:i:s') .space();if (Redis::lLen($key) > 0) {$data = Redis::lRange($key,0,9);foreach ($data as $categoryId){go(function () use ($categoryId){$client = new \Swoole\Client(SWOOLE_SOCK_TCP);// 尝试与指定 TCP 服务端建立连接(IP和端口号需要与服务端保持一致,超时时间为0.5秒)if ($client->connect("127.0.0.1", 9505, 0.5)) {// 建立连接后发送内容$data = ['service' => 'RemoteApiSpider','method' => 'getProduct','param' => ['category_id' => $categoryId,'platform' => PLATFORM_IC,],];$sendData = jsonE($data);echo 'send=' .$sendData .' ,'. date('H:i:s') .space();$client->send($sendData);// 打印接收到的消息echo $client->recv();// 关闭连接$client->close();} else {echo "connect failed.";}});}Redis::lTrim($categoryModel::getCategoryQueue(),10,-1);unset($data);}});echo 'spider product end time:' .date('H:i:s') .space();}
}
创建服务端Server
<?phpnamespace App\Console\Commands;use App\Services\RemoteApiSpider;
use App\Services\TcpService;
use App\Services\TestService;
use Swoole\Database\MysqliConfig;
use Swoole\Database\MysqliPool;
use Swoole\Server;class Swoole extends Base
{protected $ws;/*** The name and signature of the console command.** @var string*/protected $signature = 'swoole {action} {--d}';/*** The console command description.** @var string*/protected $description = 'swoole service command';/*** Create a new command instance.** @return void*/public function __construct(){parent::__construct();}/*** Execute the console command.** @return int*/public function handle(){global $argv;$action = $this->argument('action');$argv[0] = 'wk';$argv[1] = $action;$argv[2] = $this->option('d') ? '-d' : '';$this->startServer();return 0;}public function startServer(){$server = new \Swoole\Server("127.0.0.1", 9505);// 设置异步任务的工作进程数量$log_path = storage_path() . '/logs/server.log';$server->set(['daemonize' => true,'log_file' => $log_path,'task_worker_num' => 50,]);//收到请求时触发$server->on('receive', function(\Swoole\Server $server, $fd, $from_id, $data) {//投递异步任务$task_id = $server->task($data);echo "异步任务投递成功: id=$task_id , recv={$data} " .his() . space();$server->send($fd, "task_id[{$task_id}],recv={$data},数据已接收,处理中... " .his() . space());});// 处理异步任务$server->on('Task', array($this, 'onTask'));// $server->on('task', function (\Swoole\Server $server, $task_id, $from_id, $data) {
// echo "新的待处理异步任务[id=$task_id] ".his() . space();
// /**
// $data = ['data' => [],'code' => '200','msg' => 'false']
// */
// $service = new RemoteApiSpider();
// $service->setDebug(true);
// if($data && is_string($data)){
// $data = jsonD($data);
// }
// $ret = false;
// if($data['code']==200 && $data['msg'] == 'ok'){
// if(isset($data['data']['category_id']) && $data['data']['category_id']){
// $categoryId = $data['data']['category_id'];
// $ret = $service->getProduct($categoryId);
// }
// }
// // todo 处理异步任务
// // 返回任务执行的结果
// $msg = "task_id[{$task_id}] ,category_id:" .$data . " ,ret:".$ret . " ," . his() . space();
// $server->finish($msg);
// });// 处理异步任务的结果$server->on('finish', function (\Swoole\Server $server, $task_id, $data) {echo "异步任务[$task_id] 处理完成: $data ". his() . space();});$server->start();}public function process(){$server = new TcpService();// 定义连接建立回调函数$server->onConnect = function ($conn) {echo "onConnect -- accepted " . stream_socket_get_name($conn, true) . "\n";};// 定义收到消息回调函数$server->onMessage = function ($conn, $msg) {echo "onMessage --" . $msg . "\n";$service = new RemoteApiSpider();$service->setDebug(true);$content = $service->getProduct($msg);fwrite($conn, "received " . $msg . "\n");};// 定义连接关闭回调函数$server->onClose = function ($conn) {echo "onClose --" . stream_socket_get_name($conn, true) . "\n";};// 启动服务器主进程$server->run();}public function onTask($serv, $task_id, $from_id, $data){//传类名、方法、参数实现公共使用try {if (!$data) {throw new \Exception(' task_id=' . $task_id . ',暂无需要处理的task任务', 400);}if (is_string($data)) {$data = jsonD($data);}echo 'recv: ' . jsonE($data) . space();$className = "App\Services\\{$data['service']}";if (!class_exists($className)) {throw new \Exception(' task_id=' . $task_id . ',未找到服务类名', 401);}$class = new $className;$func = $data['method'];if(isset($data['param'])){$ret = $class->$func($data['param']);}else{$ret = $class->$func();}return jsonE($ret);} catch (\Exception $e) {$msg = ' task_id=' . $task_id . ' ,error: ' . $e->getMessage();echo jsonE($msg) . space();}$serv->finish($msg);//每分钟执行一下service下的start方法,发送二维数组请求给tcp服务端,服务端调用service下的process方法实现业务逻辑//服务端拿到数据后,处理后结果格式:['code'=> 200,'msg'=> 'ok','data' => maxid]
// $data = [
// 'service' => 'TestService',
// 'method' => 'process',
// 'param' => ['debug'=> true,'send' =>'sucess'],
// ];//暂时留空 2.3部分会完善}}
curl发送异步请求调用python脚本
<?php
/*** 爬取接口封装*/
namespace App\Services;use App\Library\Oneyac\Oneyac;
use App\Models\HqchipProductCategoryModel;
use App\Models\HqchipProductMongoModel;
use App\Models\IcProductCategoryModel;
use App\Models\IcProductMongoModel;
use App\Models\LcscProductCategoryModel;
use App\Models\LcscProductMongoModel;
use App\Models\OneyacProductCategoryModel;
use App\Models\OneyacProductMongoModel;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;class RemoteApiSpider extends Base
{/*** 根据分类循环分页爬取产品列表* @param $data* @return int* @throws \GuzzleHttp\Exception\GuzzleException*/public function getProduct($data){$cateId = 0;$categoryId = $data['category_id'] ?? $cateId;$platform = $data['platform'] ?? PLATFORM_LCSC;$platform = strtolower(trim($platform));$categoryId = (int)$categoryId;switch ($platform) {case PLATFORM_IC:$cateModel = new IcProductCategoryModel();Redis::hDel($cateModel::getCategoryListKey(),$categoryId);//TODO 调用python API接口爬取产品数据//s2 20分钟处理4个 与 s1 20分钟处理6个 $header = [];$header['Content-Type'] = 'application/json;charset=UTF-8';$query_param['page'] = 1;$res = $this->getIcProduct($categoryId, $platform,$query_param, $header);$res && $cateId = $categoryId;break;}return $cateId;}/*** 获取ic产品信息* @param $categoryId* @param $platform* @param $query_param* @param $header* @return bool* @throws \GuzzleHttp\Exception\GuzzleException*/public function getIcProduct($categoryId, $platform, $query_param, $header){$module = 'product_list';$this->getPlatformConf(PLATFORM_IC,$module);$msg = ' ' . $platform . '_' . $module . ' ';echo $msg. ' ,category_id:' . $categoryId . ' spidering' .space();try {//$uri = 'https://www.ic.com/psen/ClassList2.aspx?id=3';$uri = $this->base_uri . $this->uri . '?id=' . $categoryId;# todo 3的倍数推入s2,其他推入s1$config = config('ic');# 重点:此处可以部署到不同服务器进行爬取,我这里只部署了2台服务,s1与s2if(($categoryId%3)===0){//s2$curl = $config['spider_uri']['s2'] ?: 'http://192.168.0.124:8005/get_ic_product_list';}else{//s1$curl = $config['spider_uri']['s1'] ?: 'http://192.168.0.127:8005/get_ic_product_list';}$response = curlPost($curl,['url' => $uri,'is_continue_stock' => 'yes']);$flag = false;if(isset($response) && !empty($response)){$response = is_array($response) ? $response : jsonD($response);$flag = ($response['msg']=='ok' && $response['status']==1);}if ($flag) {$this->debug && Log::info($msg . 'category_id:' . $categoryId . ' ,mongo-batch-insert:' . $flag);} else {throw new \Exception($msg.'ic爬虫异常,请检查python爬虫');}unset($response);return $flag;}catch (\Exception $e){Log::error($msg .'爬取产品异常,异常原因:'.$e->getMessage());return false;}}
nginx配置
server {listen 8080;server_name spidertest.test *.spidertest.test;root "D:/WWW/spidertest/";location / {proxy_pass http://127.0.0.1:8005;}charset utf-8;
}
- 注:
1.在不同服务器上部署python爬虫脚本,并配置nginx服务。配置完成后安装下面命令启动脚本。接下来开启异步多线程执行python爬虫脚本即可。
2.记得启动swoole服务。命令如下:
php artisan swoole start
运行
python脚本启动

postman测试:

php启动协程命令:

爬取回来的数据结果:
相关文章:
用PHP异步协程控制python爬虫脚本,实现多协程分布式爬取
背景 公司需要爬取指定网站的产品数据。但是个人对python的多进程和协程不是特别熟悉。所以,想通过php异步协程,发起爬取url请求控制python爬虫脚本,达到分布式爬取的效果。 准备 1.准备一个mongodb数据库用于存放爬取数据2.引入flask包&a…...
VUE3写后台管理(3)
VUE3写后台管理(3) 1.环境1.node2.vite3.Element-plus4.vue-router5.element icon6.less7.vuex8.vue-demi9.mockjs10.axios11.echarts 2.首页1.布局Main2.头部导航栏CommonHeader3.左侧菜单栏CommonLeft4.首页Home1.从后端获取数据显示到前端table的三种…...
机器学习笔记之最优化理论与算法(十二)无约束优化问题——共轭梯度法
机器学习笔记之最优化理论与方法——共轭梯度法 引言回顾:共轭方向法的重要特征线性共轭梯度法共轭方向公式的证明过程 关于线搜索公式中参数的化简关于线搜索公式中步长部分的化简关于线搜索公式中共轭方向系数的化简参数化简的目的 非线性共轭梯度法(FR,PRP方法)关…...
JVM中的java同步互斥工具应用演示及设计分析
1.火车站售票系统仿真 某火车站目前正在出售火车票,共有50张票,而它有3个售票窗口同时售票,下面设计了一个程序模拟该火车站售票,通过实现Runnable接口实现(模拟网络延迟)。 伪代码: Ticket类…...
数据治理-数据质量
实现数据质量的前提就是数据本身是可靠和可信的。 导致数据质量低下的因素 组织缺乏对低质量数据影响的理解,缺乏规划、孤岛式系统设计、不一致的开发过程、不完整的文档、缺乏标准或缺乏治理等。 所有组织都会遇到与数据质量有关的问题。数据质量需要跨职能的承诺…...
[sqoop]hive3.1.2 hadoop3.1.1安装sqoop1.4.7
参考: Hadoop3.2.4Hive3.1.2sqoop1.4.7安装部署_hadoop sqoop安装_alicely07的博客-CSDN博客 一、安装 1、解压 tar -zxvf sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /home/data_warehouse/module mv sqoop-1.4.7.bin__hadoop-2.6.0 sqoop-1.4.72、配置文件 sqoop-env.s…...
js事件的详细介绍
11.事件 1.什么是事件 js属于事件驱动编程,把驱动,执行,调用通过一些交互,触发一些函数事件:发起-->执行绑定事件-->触发事件on 绑定 emit触发 off解绑2.事件分类 鼠标事件 点击事件 onclick 双击事件 ondblclick 按下事件 onmousedown 抬起事件 onmouseup 鼠标进…...
虚幻4学习笔记(12)操控导入的角色、动画蓝图、播放蒙太奇和打包、角色重定向
虚幻4学习笔记 操控导入的角色设置鼠标旋转关掉动态模糊 动画蓝图、播放蒙太奇和打包角色走路奔跑动画shift 奔跑F 跳舞移动打断 跳舞 打包角色重定向姿势调整解决跑步 腿分太开隐藏剑 B站UP谌嘉诚课程:https://www.bilibili.com/video/BV164411Y732 操控导入的角色…...
hive with tez:无法从链中的任何提供者加载aws凭据
环境信息 hadoop 3.1.0 hive-3.1.3 tez 0.9.1 问题描述 可以从hadoop命令行正确地访问s3a uri。我可以创建外部表和如下命令: create external table mytable(a string, b string) location s3a://mybucket/myfolder/; select * from mytable limit 20; 执行正…...
Ubuntu修改静态IP、网关和DNS的方法总结
Ubuntu修改静态IP、网关和DNS的方法总结 ubuntu系统(其他debian的衍生版本好像也可以)修改静态IP有以下几种方法。(搜索总结,可能也不太对) /etc/netplan (use) Ubuntu 18.04开始可以使用netplan配置网络࿰…...
Eureka服务器注册
一。Eureka服务器注册 1.pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://mav…...
Windows安装GPU版本的pytorch详细教程
文章目录 chatGLM2-6B安装教程正式安装 chatGLM2-6B ChatGLM2-6B版本要装pytorch2.0,而且要2.0.1 ,因此CUDA不能用12.0 ,也不能用10.0,只能用11.x 版本。 安装教程 pip install直接下载安装 官网: https://pytorch.…...
理解Kruskal算法的前提----深入理解并查集【超简单~】
并查集的实现思路 并查集主要分为两个部分:第一部分就是需要找到点对应的祖宗节点,第二部分,是要将属于同一个集合节点的祖宗节点进行统一,也就是结合操作。 Find函数实现 // parent数组用来存储下标值所对应的父节点值 // 比如…...
Jenkins+Gitee+Docker+Ruoyi项目前后端分离部署
前言 描述:本文主要是用来记录 如何用标题上的技术,部署到云服务器上通过ip正常访问。 一、总览 1.1、Docker做的事 拉取 mysql 镜像拉取 redis 镜像拉取 jdk 镜像拉取 nginx 镜像 解释说明:前端项目的打包文件放在 nginx容器运行。后端…...
笙默考试管理系统-MyExamTest----codemirror(23)
笙默考试管理系统-MyExamTest----codemirror(23) 目录 笙默考试管理系统-MyExamTest----codemirror(23) 一、 笙默考试管理系统-MyExamTest 二、 笙默考试管理系统-MyExamTest 三、 笙默考试管理系统-MyExamTest 四、 笙…...
重学Java (一) 泛型
1. 前言 泛型编程自从 Java 5.0 中引入后已经超过15个年头了。对于现在的 Java 码农来说熟练使用泛型编程已经是家常便饭的事情了。所以本文就在不对泛型的基础使用在做说明了。 如果你还不会使用泛型的话,可以参考下面两个链接 Java 泛型详解The Java™ Tutorial…...
Docker 部署 Redis 服务
拉取最新版本的 Redis 镜像: $ sudo docker pull redis:latest在本地预先创建好 data 目录和 conf/redis.conf 文件。 使用以下命令来运行 Redis 容器: $ sudo docker run -itd --name redis --privilegedtrue -p 6379:6379 -v /home/ubuntu/docker/redis/data:/data -v /ho…...
阿里云产品试用系列-负载均衡 SLB
阿里云负载均衡(Server Load Balancer,简称SLB)是云原生时代应用高可用的基本要素。通过将流量分发到不同的后端服务来扩展应用系统的服务吞吐能力,消除单点故障并提升应用系统的可用性。阿里云SLB包含面向4层的网络型负载均衡NLB…...
drf 对象级权限
drf 对象级权限 Django REST Framework(DRF)提供了对象级别权限(Object-level permissions)来控制特定对象的访问权限。 简单来说:通过视图类中的self.get_object(pk)得到一个obj对象(视图对象),在与requ…...
八大排序(二)--------冒泡排序
本专栏内容为:八大排序汇总 通过本专栏的深入学习,你可以了解并掌握八大排序以及相关的排序算法。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:八大排序汇总 🚚代码仓库:小小unicorn的代码仓库…...
颠覆式突破:无需模拟器,在Windows系统上直接运行Android应用的革命性方案
颠覆式突破:无需模拟器,在Windows系统上直接运行Android应用的革命性方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 想象一下,…...
如何用RSPrompter提升遥感图像分割效果?基于SAM的实战技巧分享
如何用RSPrompter提升遥感图像分割效果?基于SAM的实战技巧分享 遥感图像分割一直是计算机视觉领域的难点之一。传统方法往往需要大量标注数据,而标注成本高昂,尤其是对于高分辨率遥感影像。2023年Meta发布的Segment Anything Model(SAM)展现了…...
快速体验Qwen3-ASR-0.6B:上传音频秒出文字,支持52种语言
快速体验Qwen3-ASR-0.6B:上传音频秒出文字,支持52种语言 1. 模型简介 Qwen3-ASR-0.6B是阿里云通义千问团队推出的开源语音识别模型,专为高效准确的语音转文字任务设计。这个0.6B参数的轻量级模型在精度和效率之间取得了出色平衡,…...
终极指南:如何用billboard.js实现机器学习预测结果的可视化展示
终极指南:如何用billboard.js实现机器学习预测结果的可视化展示 【免费下载链接】billboard.js 📊 Re-usable, easy interface JavaScript chart library based on D3.js 项目地址: https://gitcode.com/gh_mirrors/bi/billboard.js billboard.j…...
专业流媒体视频下载工具技术解析与使用指南
专业流媒体视频下载工具技术解析与使用指南 价值主张:高效解决流媒体内容本地化需求 在数字内容消费日益普及的今天,用户对在线视频资源的本地保存需求持续增长。m3u8-downloader作为一款专业的流媒体下载工具,专注于解决m3u8格式视频的高效…...
GlitchTip:开源错误追踪平台完全指南:Sentry替代方案的完整教程
GlitchTip:开源错误追踪平台完全指南:Sentry替代方案的完整教程 背景 在应用开发和运维过程中,错误追踪是保障服务质量的关键环节。Sentry 作为业界领先的错误追踪服务,提供了强大的错误收集和分析能力,但其云服务版…...
重塑前端图片处理流程:compressorjs的高效压缩技术突破之路
重塑前端图片处理流程:compressorjs的高效压缩技术突破之路 【免费下载链接】compressorjs compressorjs: 是一个JavaScript图像压缩库,使用浏览器原生的canvas.toBlob API进行图像压缩。 项目地址: https://gitcode.com/gh_mirrors/co/compressorjs …...
【笔试真题】- 阿里系列-2026.03.25-研发岗
📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围在线刷题 bishipass.com 阿里系列-2026.03.25-研发岗 1. K小姐的仓位配货表 问题描述 说明:阿里系列近期多条业务线笔试题基本共用同一套公开机试,淘天、阿里云等方向都可参考本场。…...
KV260实战:从PYNQ安装到跑通第一个AI例程,手把手带你玩转边缘AI开发板
KV260边缘AI开发实战:从PYNQ部署到图像分类全流程指南 当你第一次拿到KV260开发板时,可能会被它小巧的外表所迷惑——这块巴掌大的开发板实际上搭载了赛灵思的Kria K26 SOM系统模块,内含可编程逻辑和四核ARM Cortex-A53处理器,专为…...
经典游戏无法运行?DDrawCompat让老游戏在新系统重生
经典游戏无法运行?DDrawCompat让老游戏在新系统重生 【免费下载链接】DDrawCompat DirectDraw and Direct3D 1-7 compatibility, performance and visual enhancements for Windows Vista, 7, 8, 10 and 11 项目地址: https://gitcode.com/gh_mirrors/dd/DDrawCom…...
