在选择使用 Node.js 或 Go 来实现站点爬取和内容分析时,需要根据项目需求和各语言的特点来权衡。以下是两者的对比: 1. 性能 Go:Go 是编译型语言,性能优越,适合处理高并发任务。Go 内置的 goroutines 使得实现并发爬取非常方便,处理大量网络请求时性能更好。 Node.js:Node.js 是基于事件驱动的异步非阻塞模型,对于 I/O 密集型任务表现良好。但因为是解释型语言,性能稍逊于 Go。尽管可以使用异步机制处理并发,但在处理大量任务时可能会遇到内存和性能瓶颈。 适用场景:如果需要高并发、高性能的爬取,Go 更适合。 2. 开发速度和生态 Go:Go 的语法简单易学,开发速度快,错误处理方式清晰,适合编写健壮的爬虫程序。然而,Go 在网页解析和处理库的生态上不如 Node.js 丰富,需要手动处理 HTML 解析等操作。 Node.js:Node.js 拥有丰富的库和工具,例如 axios、cheerio、puppeteer 等,可以快速实现爬虫。借助这些库,Node.js 能轻松解析 HTML、操作浏览器和处理 JavaScript 渲染页面。 适用场景:如果优先考虑开发速度和库的丰富性,Node.js 更适合。 3. 并发和内存管理 Go:Go 的 goroutines 非常轻量,可以处理大量的并发任务。同时,Go 的内存管理方式更加高效,适合爬取大规模的网站。 Node.js:Node.js 的事件循环机制适合处理一定规模的并发任务,但在处理过多并发请求时,可能会面临内存压力和事件循环阻塞的问题。 适用场景:Go 更适合高并发和内存密集型的爬虫任务。 4. 复杂网页处理 Go:如果需要处理动态页面(例如 JavaScript 渲染内容),Go 并不是最好的选择,虽然有一些浏览器自动化库(如 chromedp),但开发复杂程度较高。 Node.js:借助 puppeteer 或 playwright,Node.js 可以轻松控制浏览器,处理复杂的动态内容和用户行为模拟。 适用场景:如果需要处理 JavaScript 渲染的动态内容,Node.js 是更好的选择。 总结 选择 Go:适合高并发、大规模爬取、需要高性能的情况,或者对动态内容处理需求较少的项目。 选择 Node.js:适合快速开发、处理动态网页、或者依赖丰富的第三方库的项目。 如果项目涉及大量动态内容和复杂的网页处理,Node.js 会更方便。如果关注高性能和高并发任务处理,Go 则是更优的选择。 ...
减少 Tailwind 中重复和冗长的 className
有几种方法可以减少 Tailwind 中重复和冗长的 className: 1. 使用 @apply 语法 在自定义的 CSS 文件中,使用 Tailwind 的 @apply 语法将常用的样式组合成一个自定义的类。例如: /* styles.css */ .btn-primary { @apply bg-blue-500 text-white py-2 px-4 rounded; } 然后在组件中使用: <button className="btn-primary">Click me</button> 这样可以减少 JSX 文件中的 className 冗余。 2. 封装组件 将常用的样式封装成可复用的组件。例如,将按钮样式封装为一个 Button 组件: const Button = ({ children, className, ...props }) => ( <button className={`bg-blue-500 text-white py-2 px-4 rounded ${className}`} {...props} > {children} </button> ); // 使用 <Button className="my-2">Click me</Button>; 通过这种方式,可以保持代码的简洁并提高复用性。 3. 使用 clsx 或 classnames 库 这些库可以帮助你有条件地组合多个 className,减少重复性。例如: ...
Err Ossl Evp Unsupported
一个比较老的Vue项目,在启动时候,报错: opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ], library: 'digital envelope routines', reason: 'unsupported', code: 'ERR_OSSL_EVP_UNSUPPORTED' 问题原因是nodejs升级到17后,openssl3.0 对允许算法密钥大小增加了严格的限制,临时的解决办法是配置node_options. # Windows 环境 $env:NODE_OPTIONS="--openssl-legacy-provider" #or set NODE_OPTIONS=--openssl-legacy-provider # Linux or Mac export NODE_OPTIONS=--openssl-legacy-provider 上述的方法是一次性的,也可以在package.json中对script进行修改,如 ... "serve" : "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve" ...
PHP代码质量工具之Laravel Pint
作为开发人员,我们有责任尽可能保持代码的最佳状态。这不仅有助于维护和扩展代码,还能避免出现错误。 在 PHP 中,有许多工具可以帮助我们实现高质量和无错误的代码,包括 PHP Mess detector、PHP CodeSniffer、PHPStan 和 Psalm。这些工具都很不错,但要集成到 Laravel 项目中并不容易。 后面我们会介绍五款专门用于帮助你及早捕捉错误、提高 Laravel 代码质量、确保编码风格统一的工具,让你在 Laravel 项目中轻松遵循最佳实践,现在我们先来说说 Laravel Pint。 我们还将介绍文本编辑器集成和使用这些工具的持续集成。 前提条件 本教程假定您已设置好 PHP 开发环境。本教程还假定您有 PHP 和 Laravel 方面的经验。 要充分利用本教程,我强烈建议您跟读本教程,以便亲自了解和测试这些工具是如何工作的。 为此,请克隆以下 repo:food-order-app-laravel-tdd: git clone https://github.com/anchetaWern/food-order-app-laravel-tdd cd food-order-app-laravel-tdd git checkout tdd 接下来,将 .env.example 文件重命名为 .env,并用本地数据库密码更新 DB_PASSWORD。 完成上述操作后,执行以下命令设置项目: composer install npm 安装 php artisan config:cache php artisan migrate php artisan db:seed 这样就能安装所有的 composer 和前端依赖项,更新配置,迁移数据库并为其播种。 我建议你安装 GitHub for desktop 或其他 Git 图形用户界面工具,这样你就能看到这些工具对你的代码做了什么。 什么是静态代码分析? 静态分析允许您在不运行代码的情况下检查代码是否存在问题。它基本上是读取代码、理解代码并将代码与特定规则进行比较,以验证代码的正确性。下面是一个例子: ...
magento2中opensearch或mysql作为catalog search engine的区别
在Magento 2中,你可以使用OpenSearch或MySQL作为Catalog Search Engine。这两种搜索引擎在功能上有一些显著的不同: 性能和规模:如果你需要处理大量的数据并且需要更好的性能和扩展性,那么OpenSearch很可能是更好的选择。OpenSearch是一种基于分布式架构的搜索引擎,可以通过增加节点来扩展性能和容量。MySQL作为关系型数据库,性能和容量的扩展受到硬件和软件的限制。 搜索质量:OpenSearch使用先进的全文搜索算法,可以更好地处理模糊查询、拼写错误和语言处理等问题。相比之下,MySQL的搜索算法可能更加基础,但它也可以通过使用全文索引等技术来提高搜索质量。 集成和配置:集成OpenSearch可能需要更多的配置和工作,因为它是一个独立的搜索引擎。相比之下,Magento 2已经默认集成了MySQL,因此使用MySQL作为Catalog Search Engine可能需要更少的配置和工作。 总的来说,如果你需要更好的性能和扩展性,以及更高质量的搜索结果,那么OpenSearch可能是更好的选择。如果你正在寻找一种简单易用的搜索引擎,并且你已经熟悉了MySQL,那么使用MySQL作为Catalog Search Engine可能是更好的选择。
PHP 8.2:动态属性被弃用
在PHP类中,有可能动态地设置和检索未被声明的类属性。这些属性不遵守特定的(类似于类型化的属性),它需要使用__get()和__set()魔法方法来有效地防止或控制动态属性的设置和检索方式。 class User { private int $uid; } $user = new User(); $user->name = 'Foo'; 在上面的片段中,User类没有声明一个名称为name的属性,但由于允许动态属性,PHP允许设置它。 虽然动态属性提供了创建类的灵活性,如没有严格的类声明的价值对象,但它为应用程序中潜在的错误和意外行为提供了可能性。例如,由于PHP默许所有的动态属性,设置属性的语句中的一个错别字可能会被忽略。 在 PHP 8.2 及以后的版本中,为未声明的类属性设置一个值是被废弃的,并且在应用程序执行过程中第一次设置该属性时,会发出废弃通知。 class User { private int $uid; } $user = new User(); $user->name = 'Foo'; Deprecated: Creation of dynamic property User::$name is deprecated in ... on line ... 从类中设置属性也会发出废弃通知: class User { public function __construct() { $this->name = 'test'; } } new User(); Deprecated: Creation of dynamic property User::$name is deprecated in ... on line ... 动态属性有合法的用例,比如从动态JSON响应中得到的值对象,或者允许任意值的配置对象。 理想情况下,类应该在类中声明动态属性以避免废弃通知。不需要用一个属性类型来声明该属性。 豁免的动态属性模式 这种废弃有三种例外情况。使用下面的方法之一可以避免废弃的通知。 Classes with #[AllowDynamicProperties] attribute. stdClass and its sub-classes Classes with __get and __set magic methods 参考: https://php.watch/versions/8.2/dynamic-properties-deprecated#exempt ...
GD库导致Magento2图片处理异常的问题处理
问题描述 部分产品图片无法正常加载,手动resize图片,报错。 bin/magento catalog:images:resize # warning show: # ... imagecreatefrompng(): gd-png: libpng warning: Interlace handling should be turned on when using png_read_image ... 查了一下这个问题,因该是 gd 库的bug 导致的报错,受系统环境制约,升级php版本及相关插件风险比较大,好再 Magento 提供了 GD2(默认) 和 ImageMagic 两种库的选择,可以绕过该问题。 安装配置 imageMagic yum install php-pear php-devel gcc yum install ImageMagick ImageMagick-devel ImageMagick-perl pecl install imagick echo extension=imagick.so >> /etc/php.ini systemctl restart php-fpm.service 修改默认Adapter # show default adapter bin/magento config:show dev/image/default_adapter GD2 # set imagick as default adapter bin/magento config:set dev/image/default_adapter IMAGEMAGICK 然后刷新缓存,重新resize,一切正常。 ...
brew切换php版本不生效的改进方案
mac环境随时随地方便的切换php版本,前提如下: Mac 环境, zsh为默认shell 安装了brew 通过brew 安装了多个版本的php 基本方式 举例,从php.7.4切换到php8.1 brew unlink php7.4 && brew link --overwrite --force php@8.1 到这一步,如果运行 php -v ,那么版本还是7.4 ,因为还需手动更新.zshrc文件中的PATH路径,以确保使用正确的PHP版本。 vim ~/.zshrc #注释掉下面两行 export PATH="/usr/local/opt/php@7.4/bin:$PATH" export PATH="/usr/local/opt/php@7.4/sbin:$PATH" #手动添加如下两行 export PATH="/usr/local/opt/php@8.1/bin:$PATH" export PATH="/usr/local/opt/php@8.1/sbin:$PATH" #保存后运行下面命令之使生效 source ~/.zshrc 改进方式 将上面提到的命令写成bash脚本,一次运行。 #!/bin/zsh if [ "$1" = "7.4" ]; then brew unlink php@8.1 && brew link --overwrite --force php@7.4 sed -i '' '/php@[0-9\.]*\//d' ~/.zshrc echo 'export PATH="/usr/local/opt/php@7.4/bin:$PATH"' >> ~/.zshrc echo 'export PATH="/usr/local/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc elif [ "$1" = "8.1" ]; then brew unlink php@7.4 && brew link --overwrite --force php@8.1 sed -i '' '/php@[0-9\.]*\//d' ~/.zshrc echo 'export PATH="/usr/local/opt/php@8.1/bin:$PATH"' >> ~/.zshrc echo 'export PATH="/usr/local/opt/php@8.1/sbin:$PATH"' >> ~/.zshrc else echo "Invalid argument. Please enter either '7.4' or '8.1'." exit 1 fi source ~/.zshrc 文件需要保存为.zsh后缀,首行声明 #!/bin/zsh , 否则会报错:Oh My Zsh can’t be loaded from: sh. You need to run zsh instead. 因为脚本在Bash中运行,而不是在zsh中运行。解决办法是将脚本转换为zsh脚本,将脚本的文件扩展名从.sh更改为.zsh,然后在脚本的开头添加以下行:#!/usr/bin/env zsh; 或者脚本的开头添加以下行:#!/bin/zsh ...
php7.4 与 php8差异
PHP 8.0 是 PHP 7.x 系列的下一个主要版本,与 PHP 7.4 相比有一些重大的变化和改进。以下是 PHP 8.0 相对于 PHP 7.4 的一些重要的变化和改进: JIT 编译器:PHP 8.0 引入了一个全新的 JIT 编译器,可以提高代码的执行速度,尤其是在大型应用程序中。 新的语言特性:PHP 8.0 引入了一些新的语言特性,例如命名参数、联合类型、match 表达式等,可以提高代码的可读性和可维护性。 函数和类的改进:PHP 8.0 对一些函数和类进行了改进,例如 str_contains()、str_starts_with()、str_ends_with() 函数,以及 DateTime 类等。 错误处理的改进:PHP 8.0 对错误处理进行了改进,例如引入了新的 Throwable 接口、Union Types 等,可以提高代码的健壮性和可靠性。 移除了一些废弃的特性:PHP 8.0 移除了一些废弃的特性,例如 magic_quotes_gpc、realpath_cache_size 等,可以提高代码的安全性和稳定性。 总的来说,PHP 8.0 相对于 PHP 7.4 有一些重大的变化和改进,尤其是 JIT 编译器和新的语言特性等,可以提高代码的执行速度和可读性。但是,这些变化和改进也可能导致一些不兼容性问题,因此在升级到 PHP 8.0 之前,需要仔细评估其对项目的影响,并进行充分测试。
Javascript Fetch Note
An Example about Fetch fetch('https://api.example.com/data', { method: 'POST', // 请求方法 headers: { 'Content-Type': 'application/json' // 请求头中的 Content-Type }, body: JSON.stringify({ // 请求体中的数据 name: 'John Doe', age: 30 }) }) .then(response => { if (response.ok) { // 判断响应是否成功 return response.json(); // 将响应转换为 JSON 格式 } else { throw new Error('Network response was not ok.'); // 抛出异常 } }) .then(data => { console.log(data); // 处理 JSON 格式的响应数据 }) .catch(error => { console.error('There was a problem with the fetch operation:', error); // 处理异常 }); fetch 默认是异步执行的。当你调用 fetch 函数时,它会立即返回一个 Promise 对象,然后在后台发起网络请求。一旦请求完成,Promise 对象就会被解析为一个 Response 对象,然后你可以使用 then() 方法来获取响应数据。 ...