如何编写一个健壮的 npm 包

无脑发布 npm

比如老王我,用npm init新建一个包,改把改把,然后来个npm publish,so easy ✌️!

Too young too naive, baby ?!

请容我讲述一些发布过程中踩过的坑。

首先,算了也可以之后有空再说,我们需要通读npm的配置文档。

package.json doc

通用性?

指定发布文件

利用package.jsonfiles字段精简发布体积。

{
  "files": ["dist", "lib", "module"]
}

若不指定files,每次发布会把所有不以.开头的文件都发布出去,导致发布体积过大(node_modules默认也不会被发布)。

README.md作为主文档,加不加都会发布,package.json也是。

指定源代码

{
  "source": "src/index.ts",
  "repository": {
    "type": "git",
    "url": "http://github.com/yourname/yourproject.git"
  }
}

通常来说我是不在npm发布中包括源代码的,因此都没有加过source字段,只是用repository来告知一下git仓库地址即可。

如果仓库是内部仓库或私人仓库并不对外,则source字段就有用了,将源代码发布后可让人帮忙debug找问题。

注意如果有source,则files也要加上souce对应的文件或文件夹。

发布sourcemap

一般来说我们发布的都是经过编译的代码,为了给使用者方便调试,只要不是源码,都要有对应的sourcemap文件,例如发布了一个dist/index.js则也需要一个dist/index.js.map文件与之配套。

指定安装源

如果你从来不用私有源,可跳过该项。

利用.npmrc指定安装源,用于当前项目与你的全局配置区分开。

否则当前项目很可能指定的内部npm源,导致外部用户无法利用lock文件安装。

例如

registry=http://registry.npmjs.org/

精确指定dependenciesdevDependenciespeerDependencies

dependencies要尽量少,只有在运行时确实用到才放进去。

依赖的版本号要清晰指明,如"react": "16.x || 17.x"

否则,如果指定了"react": "17.0.0",则在使用了react 16的项目中,会引入两份react,造成一些莫名其妙的问题。

这种情况,react应放到peerDependencies中。

指定发布目标

如果你从来不在私有源发布,可跳过该项。

package.json中指定发布地址,在当前包与全局配置不一致时非常必要。

{
  "publishConfig": {
    "registry": "http://registry.npmjs.org"
  }
}

sideEffects

对应配置:

{ "sideEffects": false }

作用:在打包时进行treeshake可根据是否使用而优化相关的代码。

如果sideEffectstrue,则一旦引入,不管是否调用都不能被treeshake掉。

专用性?

类型配套

无论针对哪个环境,目前自带类型已经是既成事实的标配。

记得生成类型的.d.ts文件,并在package.json中指定。

{
  "types": "type/index.d.ts",
  "typings": "type/index.d.ts"
}

我一般会用一个专用的tsconfig.declaration.json来专门生成类型:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "noEmit": false,
    "emitDeclarationOnly": true,
    "declaration": true,
    "outDir": "types"
  }
}

作为后端库

package.json中指定main字段。

编译结果需要在nodejs环境中运行,输出commonjs格式模块。

为了兼容最新与将来,同时也要输出esmodule格式模块。

相关配置:

{
  "main": "lib/index.js",
  "module": "module/index.js",
  "jsnext:main": "module/index.js"
}

modulejsnext:main都是指esmodule格式,只是为了兼容某些特殊环境的别名。可能还有其他别名单我暂时就见过这俩。

其中module中的文件推荐使用特定的后缀名,例如.esm.js.mjs,但在一些工程相关工具中是否会有未知为题,不好说。

未来已来,现在大部分前端工程工具都会优先使用module指定的文件,单如果没有指定module,也会为了兼容去加载main

作为前端库

前端库其实要求比后端库更高,为啥?

因为现代前端开发环境要求支持所有后端环境,并延伸出前端环境的额外支持。也就是说后端库要求一般是前端库要求的子集。

需要扩展的是纯前端环境的运行格式,老格式amd已经被淘汰可以不用考虑,现在基本都被umd格式统一。

{
  "main": "lib/index.js",
  "module": "module/index.js",
  "unpkg": "dist/index.js",
  "umd:main": "dist/index.js",
  "jsdelivr": "dist/index.umd.production.min.js"
}

其中unpkgumd:mainjsdelivr都是为了更广泛兼容的指向浏览器环境运行的同一个目标别名。

通常来说commonjsesmoduleumd都不会将其依赖的其他包包括进去,只是在运行时才加载。

还有一种情况,可能只有我自己用到过,就是发布包中有些东西与外部环境有冲突,因此除了这些通用模式之外我又加了一个independent(取名叫standalong也比较合适)格式,将这个包的所有依赖都封装进去,可以不依赖外部环境独立使用。

例如mobx-value的独立运行文件。

mobx-value independent

注意浏览器环境输出的都是优化后的.production.min格式,也必须同时输出.development后缀的开发模式,为了方便使用者调试方便。

因为最大的使用者,往往就是我们自己,不要连自己都糊弄了事~

作为命令行工具

多配置兼容

命令行工具一般需要很多参数,例如tsc,当参数过多时没人愿意每次都输入长长的参数,因此需要配置文件的支持。

那么选哪种配置格式呢?

此时cosmiconfig隆重登场!以一句名言形容,小孩子才做选择,成年人全都要!

兼容各种配置,各种位置,详情参见其api

还有一点,如果需要读取一些周边的json配置,不要用原生的JSON.parse,很多json是带注释的或者编写不规范,用json5读取兼容好。

还有一个精简版:lilconfig,功能差不多,我下次打算试试。

配置文件类型校验

刚入门typescript时,我尝试用typescript作为配置文件,然后在运行时利用类型机制达到校验配置的目的。

但这样会丢失很多灵活性,限制死了配置文件的来源与格式,并由于库的typescript环境与应用所在的typescript环境不一致,也导致了很多工程问题(对我说的就是ts-gear)。

后来发现通过注释文档的方式,js文件中也同样可以校验类型,而且js文件对运行时更友好。

例如webpack.config.js这样配置

/**
 * @type {import('webpack').Configuration}
 * */
const config = {...}
export default config

配置文件运行时校验

我们的程序要读配置,但配置是使用者提供的,谁知道用户会写些什么,即使有上面那步提到的类型校验把关,也会有很多边界问题类型根本管不了。

因此,运行时配置数据校验就是必备环节。

不光是校验不通过时终止运行,还必须给出一个合理且精准的错误提示。

推荐一个协议、两个校验工具与一个漂亮的格式化提示工具。

协议是json schema,校验工具为joiajv,提示输出工具为chalk

指定可运行文件

package.json中指定bin

{
  "bin": "bin/run.js"
}

对于大部分js脚本,都要在运行文件头部指定运行环境。

#! /usr/bin/env node

然后别忘了在发布前添加可执行属性,务必整合在自动化发布脚本中。

chmod +x bin/run.js

可调用api

例如babel,我们不光能使用@babel/cli在命令行使用,也可以在自己的程序里import babel from 'babel'来调用其api

一个命令行工具通常也是一个第三方库,方便集成到调用者自身的脚本与环境中。

其他特定环境

例如针对react-native,这个我就见过,没实际用过。

{
  "react-native": "dist/index.esm.js"
}

最后不论什么格式,都记得输出配套sourcemap.map文件。

健壮性?

指定运行环境:engine与os

尤其对于命令行工具,这俩点很重要,不然很容易就换个人换个电脑就莫名报错。

{
  "engine": "node>=14",
  "os": ["linux", "darwin"]
}

有否配套测试用例

  • 有可运行的配套测试用例。
  • README.md上有可见的测试覆盖率统计,让人可以放心使用。

测试用例放在哪?

最初我习惯按照jest推荐的模式,将所有测试用例放在__tests__文件夹内。

最近两年看了好多别的语言的单测用例,我现在更倾向于将测试文件与源文件放在一起。因为测试用例,就是源代码的一部分!

比如以下这种目录结构

src/setter.ts
src/setter.test.ts

测试运行时机

npm prepublishOnly的钩子一定要加上运行测试用例。

有余力的情况,可以再配置个额外的流水线,github上有好多免费的配套流水线,自己折腾折腾。

代码校验配套

项目必须有一个较好的文档规则校验流程,大多数情况我使用eslint,然后配上airbnbprettier的校验规则。

校验有两个重要作用,一个是真的能解决很多隐性bug,另一个是代码漂亮,之后看你项目源码的人也会觉得舒服,关键是面试时也能拿的出手。

如果有面试者给我看自己的开源作品,如果代码风格都不行,立即就判定不行,也不用再看什么逻辑能力了,招进来也是挖坑。

好的代码风格必须依赖校验工具,最好把校验流程也集成到发布的钩子上。

推广性?

文档

使用.markdownlint配置规范自己的markdown文档,否则很容易写飞了。

要不人家一看文档,项目质量很容易就露馅了不是?

配套展示用例

  • 一个方法是在项目中自带一个可运行的样例,让人clone之后运行指定命令即可查看样例。
  • 更好一些,部署一个可以在线查看的例子,并在主文档上附上直达链接。
  • 更进一步,项目增大之后,需要说明的地方越来越多,一个README已经太长。使用docusaurus等类似的工具部署一个独立的文档站点。

有否自动化版本管理

Why?因为版本号与兼容性是强相关的,具体参考semver规范。

  • 使用husky/yorkie等规范提交日志。
  • 使用standard-version等自动生成CHANGELOG并根据规则自动提升版本号。

最后留个作业

  • 你有什么npm发布时的关键经验这里没提到的,帮我补充下?
  • 当我们再一次运行npm publish,脑编译一下,想想这期间都发生了些什么,还少些什么?

作者:京东零售 王凡

内容来源:京东云开发者社区

本文转载于网络 如有侵权请联系删除

相关文章

  • Python 微信机器人:属于自己的微信机器人制作,简单易懂。图灵机器人接口api调用。

    首先你需要安装itchat库。 进入cmd,先直接pipinstallitchat就好了。我调的是图灵机器人的接口,可以了解一下: 图灵机器人的注册,图灵机器人api获取方式微信机器人实现过程开启的时候会弹出一个二维码,微信扫描后就会登陆了。 原理是网页版微信,那个二维码就是你网页版微信登陆的二维码。详细的过程见代码里的注释。#-*-coding:UTF8-*- importitchat importrequests #调用图灵的api获得一个回复,这个参数的msg就是接收到的消息内容 defget_response(msg): apiUrl='http://www.tuling123.com/openapi/api' data={ 'key':'bd0a1aafaafd418bbdb6aa0a40f73859', 'info':msg, 'userid':'小爱', } try: r=requests.post(apiUrl,dat

  • vue+element实现一个excel表格下载的功能

    最近在使用vue-element-admin这个后台管理框架开源模板在做一个管理后台,使用起来其实还挺方便的,大部分的组件源码里面都已经写好了,用的时候只需要把源码拿出来修改修改,也就成了。这里记录一下开发过程中遇到的一些功能。资料相关vue-element-admin推荐指数:star:55k Github地址:https://github.com/PanJiaChen/vue-element-admin Demo体验:https://panjiachen.github.io/vue-element-admin/#/dashboard一个基于vue2.0和Eelement的控制面板UI框架,这是使用vue技术栈开发的前端程序员的首选管理系统模板,模板以及非常的成熟了,并且有相关的社区和维护人员,开发时候遇到问题也不要慌。今天记录一个表格下载的功能在demo给到的源码里面,可以看到也是有表格下载的功能的,在这个基础上进行一些修改,大概是这个样子,点击下载按钮,将页面上显示的表格下载出来即可。即调用后端给到的接口,直接从后端服务器上下载表格。后端会返回一个二进制文件给到我这边。参考代码:

  • 『1W7字中高级前端面试必知必会』终极版

    作者:陈大鱼头github:KRISACHANChrome浏览器进程在资源不足的设备上,将服务合并到浏览器进程中浏览器主进程负责浏览器界面显示各个页面的管理,创建以及销毁将渲染进程的结果绘制到用户界面上网络资源管理GPU进程用于3D渲染绘制网络进程发起网络请求插件进程第三方插件处理,运行在沙箱中渲染进程页面渲染脚本执行事件处理网络传输流程生成HTTP请求消息输入网址浏览浏览器解析URL生成HTTP请求信息 收到响应 状态码含义1xx告知请求的处理进度和情况2xx成功3xx表示需要进一步操作4xx客户端错误5xx服务端错误向DNS服务器查询Web服务器的IP地址Socket库提供查询IP地址的功能通过解析器向DNS服务器发出查询全世界DNS服务器的大接力寻找相应的DNS服务器并获取IP地址通过缓存加快DNS服务器的响应委托协议栈发送消息协议栈通过TCP协议收发数据的操作。创建套接字浏览器,邮件等一般的应用程序收发数据时用TCPDNS查询等收发较短的控制数据时用UDP连接服务器浏览器调用Socket.connect在TCP模块处创建表示连接控制信息的头部通过TCP头部中的发送方和接收方端口

  • Python3装饰器的使用

    装饰器简易装饰器模板defwrapper(func): definner(*args,**kwargs): print('主代码前添加的功能') ret=func(*args,**kwargs) print('主代码后添加的功能') returnret returninner @wrapper deffunc(): print('主代码')复制利用装饰器完成的登录认证defwrapper(func): definner(*args,**kwargs): username=input('请输入用户名:') password=input('请输入密码:') ret=func(username,password) ifret=='1': print('登录成功') else: print('登录失败') returnret returninner @wrapper deffun

  • 这6个命令助你玩转matlab自定义函数

    函数对于matlab的重要性这里就不在赘述了(你了解matlab局部函数吗?)。matlab自带的函数虽包罗万象、但并不可能揽括一切,在实际编程过程中往往还需要编程者根据实际问题编写适合解决当下问题的函数,这也就是所谓的自定义函数。对于函数来说,几个参数指标是不可忽视的,包括函数的输入接口、输出接口、输入参数及其个数和输出参数及其个数,我们希望通过输入某些参数经过自定义函数的处理来获取我们想要的数据结果。为了方便大家更深刻地理解函数的概念,这里做一个形象的比喻,把面包房看作是函数,那输入参数就有面粉、酵母、鸡蛋、水等,而输出参数就是香喷喷的面包,只要输入面粉、酵母、鸡蛋、水等,经过面包房加工处理,就能得到香喷喷的面包。这相当于多个输入一个输出,函数还可以是一个输入多个输出、多个输入多个输出、零个输入零个输出、零个输入一个或多个输出,说白了就是函数既可有输入也可无输入,既可有输出也可无输出。 那么问题来了?既然函数的参数这般多变,要怎么定义才能尽可能做到万花丛中一枝独秀呢?即函数本身具备自适应输入输出参数个数的功能。接下来就一起来揭开6个小矮人的神秘面纱吧!为了能让更加自由地自定义函数,

  • Ubuntu18重启docker服务失败问题备忘

    环境信息操作系统:Ubuntu18.04.2Docker:18.06.1-ce现象执行命令servicerestartdocker,提示启动失败:root@hedy:~#systemctlrestartdocker Failedtorestartdocker.service:Unitdocker.servicenotfound.复制原因依稀记得这台机器上的Docker是用snap安装的,执行snap命令查看服务,果然看到了docker:root@hedy:~#snapservices ServiceStartupCurrentNotes docker.dockerdenabledactive-复制执行命令docker.help可以看到更多snap的信息:root@hedy:~#docker.help Dockersnap:DockerLinuxcontainerruntime. Duetotheconfinementissuesonsnappy,itrequiressomemanualsetuptomakedocker-snapworksonyourmachine. We'

  • 突破Java面试(48)-设计可动态扩容缩的分库分表

    0Github1面试题设计可动态扩容的分库分表2考点分析选一个数据库中间件,然后深入之设计分库分表的方案,要分成多少个库,每个库分成多少个表基于已选的数据库中间件,以及在测试环境建立好的分库分表,?能否正常执行分库分表的读写完成单库单表到分库分表的迁移(使用上一文提到的双写方案)线上系统,开始基于分库分表对外服务突然!扩容了,扩容成6个库,每个库需要12个表,你怎么来增加更多库和表呢?这个你必须面对的事,就是当你已经弄好分库分表方案,测试也通过了,数据能均匀分布到各个库和表里去,而且接着你还通过双写方案上了系统,已经直接基于分库分表方案在搞了。需求来了~现在这些库和表又支撑不住了,要继续扩容,咋办?这个可能就是每个库的容量又快满了,或者表数据量又太大了,也可能每个库的写并发太高了,得继续扩容!3停机扩容(不推荐)这就跟停机迁移一样,步骤几乎一致,唯一不同是导数的工具,是把现有库表的数据抽出来慢慢导入到新的库和表里去。但是最好别这样,有点不太靠谱,既然分库分表,就说明数据量实在太大了,你这么玩,可能会出问题!从单库单表迁移到分库分表时,数据量并不是很大,单表最大也就两三千万写个工具,多弄

  • 13个不容错过的Java项目

    今天我们将整理一大波干货满满的Java示例代码与能力展示素材。GitHub可谓一座程序开发的大宝库,有些素材值得fork,有些则能帮助我们改进自有代码或者学习编程技能。无论如何,开发工作当中我们几乎不可能绕得开GitHub。下面,我们将一同分享各有趣且颇为实用的Java库,大家请任取所需、不用客气~1.极致精简的JavaBootique是一项用于构建无容器可运行Java应用的极简技术。该项目允许大家创建REST服务、Web应用、任务、数据库迁移等等,且一切都立足于模块实现。另外,大家也可以将其作为简单的命令进行使用。该项目的目标在于将应用从Java容器中解放出来,允许开发者重新回归main()方法。另外其中还包含部分内置命令,因此就算各位需要处理的代码量不多或者并未向应用中导入任何模块,仍然能够利用Bootique对其加以执行。2.优雅的问题处理方式99-problems,光看名字就能对其功能了解一二。很明显,它的作用是帮助大家磨练逻辑编程中的具体技能。大家可以选择利用Java8、Scala或者Haskell进行问题解决,并最终找到最精致的解决办法。如果大家喜爱解题,其中还提供多种不同

  • 6262:流感传染

    6262:流感传染查看提交统计提问总时间限制: 1000ms内存限制: 65536kB描述有一批易感人群住在网格状的宿舍区内,宿舍区为n*n的矩阵,每个格点为一个房间,房间里可能住人,也可能空着。在第一天,有些房间里的人得了流感,以后每天,得流感的人会使其邻居传染上流感,(已经得病的不变),空房间不会传染。请输出第m天得流感的人数。 输入第一行一个数字n,n不超过100,表示有n*n的宿舍房间。 接下来的n行,每行n个字符,’.’表示第一天该房间住着健康的人,’#’表示该房间空着,’@’表示第一天该房间住着得流感的人。 接下来的一行是一个整数m,m不超过100.输出输出第m天,得流感的人数样例输入5 ....# .#.@. .#@.. #.... ..... 4复制 样例输出16复制1#include<cstring> 2#include<iostream> 3usingnamespacestd; 4intn,t,ans; 5inta[110][110]; 6boolb[110][110]; 7chard[110][110]; 8intmain(){ 9cin&

  • 【DeepMind最新Nature论文】探索人类行为中的强化学习机制

    【新智元导读】DeepMind与来自普林斯顿、NYU、达特茅斯学院、UCL和哈佛大学的研究人员合作,探索了人类行为中的强化学习,为开发智能体强化学习提供了新的策略。研究人员具体探讨了一种存在于无模型和基于模型的学习算法之间的方法,基于后继表示(successorrepresentation,SR),将长期状态预测存入缓存中。作者预计,这些发现将为计算科学、电生理学和神经影像学研究开辟新的途径去研究评估机制的神经基础。相关论文《Thesuccessorrepresentationinhumanreinforcementlearning》日前在Nature子刊《自然-人类行为》上发表。人类和其他动物在不断变化的环境中适时适机进行决策,这底层的算法是什么?发现其中的机制对于完成序列决策(比如国际象棋和迷宫导航)尤其重要。过去20年,大部分致力于解决多步骤问题的研究,都关注强化学习(RL)的两类算法,即无模型(MF)和基于模型的(MB)算法。MF和BM都将决策形式化为长期奖励预期与不同的候选行动之间的关系,但在表示(representation)和计算方面却不尽相同。突1:无模型、基于模型和基

  • 【总结思考】如何提高项目的稳定性和开发效率

    前言除了保证项目如期上线,如何保证项目上线后的运行速度,如何提高容灾能力,减少bug同样是我们需要考虑的问题。我们从以下几个方面来探究思考,抛砖引玉,看看大家是否有其他维度来提高项目,欢迎在评论区留言。1.语言选择方面开发效率和运行效率的平衡点我入行时做的安卓开发,使用Java语言,觉得入门门槛比较高:异常处理,IO,集合,JDBC等等,除了基础概念不好理解之外,代码量也比较大。使用Java开发了2年安卓之后,开始使用PHP做接口开发,觉得PHP开发真的比Java开发代码量少太多了,而且PHP的数组实在是太简单了。那时候满脑子想的就是“PHP是最好的语言”去年接触了Go,发现Go对并发处理实在是太友好了,而且代码量像PHP一样少,甚至更少。而且Go打包编译时自动格式化代码,比PHP更规范。Go性能比肩Java,对开发者的友好程序甚至略好于PHP(我个人的体会)所以,对开发语言的选择对项目至关重要,我们要结合自己的业务场景,选择合适的语言进行开发。我们目前采用的是PHP+Go,内部服务采用RPC的方式来通讯。2.框架选择方面(开发速度、项目性能)我们来探究一下相较于其他框架,为什么swo

  • 边工作边刷题:70天一遍leetcode: day 48

    ReconstructItinerary 要点:注意这题不是让找cycle,只需要从”JFK"开始cover所有站就可以。所以基本方法就是按图做dfs遍历直到找到一条valid的路径 dfs找路径的要点有二:1是返回boolean来表示是否找到,从而可以直接返回,2是在每一个点分支要不断push=>pop来backtrack 因为同一站可能在同一路径上经过多次,所以每层处理完了一个destination就要从当前分支中remove,下层返回后又要加入分支backtrack。这里就需要loop的同时remove/add,所以不能用foreachloop,而是要按初始结点个数。 这里的一个难点是因为要保持分支遍历的顺序,所以要用queue(FIFO)来remove/add分支:python中是deque(注意list模拟queue的效率不好) 结束条件是res.size()==n。这里假设了ticket都会用光的。 错误点: 因为用的是defaultdict,所以要检查下一个结点是否在graph里。注意,某一站可能不在任何ticket的出发点 因为图邻接点有限,所以用TreeS

  • HTTP协议图--概述

    1.计算机网络体系结构分层 2.TCP/IP通信传输流 利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信。发送端从应用层往下走,接收端则从链路层往上走。如下: 3.TCP/IP通信传输流 首先作为发送端的客户端在应用层(HTTP协议)发出一个想看某个Web页面的HTTP请求。 接着,为了传输方便,在传输层(TCP协议)把从应用层处收到的数据(HTTP请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。 在网络层(IP协议),增加作为通信目的地的MAC地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了。 接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的HTTP请求。 如图所示: 4.HTTP请求 HTTP协议(HyperTextTransferProtocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文

  • centos7安装phpstudy

    操作系统:CentOS7x86_64 SSH登录工具:FinalSHell2.9.7 一、安装phpstudy 1、下载完整版: wget-chttp://lamp.phpstudy.net/phpstudy-all.bin复制 2、权限设置 chmod+xphpstudy-all.bin复制 3、运行安装 ./phpstudy-all.bin复制 执行命令1、2、3,在这个过程中选择好php的版本安装。安装过程需要10来分钟。 服务进程管理:phpstudy(start|stop|restart|uninstall)站点主机管理:phpstudy(add|del|list)ftpd用户管理:phpstudyftp(add|del|list) phpsstudy是安装在根目录下。目录结构为:  

  • python识别图片中的信息

    好好学习的第一步 一心一意的干好一件事儿,问自己 我做什么 我怎么做 做的结果是啥 例子1 问题 回答 我做什么: 识别图片上的信息 我怎么做: 百度+谷歌 结果是啥: 完成识别 1安装PIL pip3installpillow 2安装pytesser3 pip3installpytesser3 3installpytesseract 4installautopy3 5installsoftwareTesseract-OCR tesseract-v Ref importpytesseract fromPILimportImage path_of_pic=r'图片.png' im=Image.open(path_of_pic) text=pytesseract.image_to_string(im) print(text) 复制

  • eccharts-gl 3D立体柱状图

    echarts-gl继承于echarts echarts-gl官方实例https://echarts.baidu.com/examples/index.html#chart-type-globe 代码: <divid="main"style="width:500px;height:400px;margin:0auto;"></div>复制 js functiongetData(){ varpieChart=echarts.init(document.getElementById('main')); varhours=['90-100','80-89','70-79','60-69','<60']; vardays=['1','2','3','4','5']; varbest=$("#best").val()==undefined?0.0:$("#best").val(); vargood=$("#good").val()==undefined?0.0:$("#good").val(); varmidd=$("#medium").val()==und

  • P3810 【模板】三维偏序(陌上花开)

    题目背景 这是一道模板题 可以使用bitset,CDQ分治,K-DTree等方式解决。 题目描述 有 nn 个元素,第 ii 个元素有 a_iai​、b_ibi​、c_ici​ 三个属性,设 f(i)f(i) 表示满足 a_j\leqa_iaj​≤ai​ 且 b_j\leqb_ibj​≤bi​ 且 c_j\leqc_icj​≤ci​ 的 jj 的数量。 对于 d\in[0,n)d∈[0,n),求 f(i)=df(i)=d 的数量 输入输出格式 输入格式:   第一行两个整数 nn、kk,分别表示元素数量和最大属性值。 之后 nn 行,每行三个整数 a_iai​、b_ibi​、c_ici​,分别表示三个属性值。   输出格式:   输出 nn 行,第 d+1d+1 行表示 f(i)

  • 第06组 Beta冲刺(3/5)

    队名:拾光组 组长博客链接 作业博客链接 团队项目情况 燃尽图(组内共享) 组长:宋奕 过去两天完成了哪些任务 继续维护后端代码 学习深入python 研究匿名拨打电话问题、套牌多结果处理问题 GitHub签入记录 接下来的计划 维护后端代码,跟进组员完成进度,学习后端架构,学习深入python,解决匿名拨打电话问题,实现套牌多结果处理,准备beta版本的答辩 还剩下哪些任务 维护后端代码,跟进组员完成进度,学习后端架构,学习深入python,解决匿名拨打电话问题,实现套牌多结果处理,准备beta版本的答辩 燃尽图组内共享 遇到了哪些困难 天好冷,风好大,软工好难 有哪些收获和疑问 凭借对软工的热情战胜寒冷,克服困难 如何打代码的时候不冻手? 组员1:杨晋南 过去两天完成了哪些任务 学习Android应用开发进阶 拍照功能完善 github签入记录 接下来的计划 学习Android应用开发进阶,准备beta版本的答辩 还剩下哪些任务 学习Android应用开发进阶,准备beta版本的答辩 燃尽图组内共享

  • scratch编程神秘的吉普赛读心术

    你知道吉普赛读心术吗?就是在一张纸上有很多个数字,每一个数字下面都有对应的图形,你只需要想着其中一个10以上的数字,用个位加上十位上的数去减原数,如10-(1+0),29-(2+9),现在试试看吧!   是不是很惊讶呢? 有兴趣的话请关注微信公众号:  

  • 爬虫 | cnblog文章收藏排行榜(“热门文摘”)

    目录需要用的module单页测试批量抓取数据保存 背景说明 因为加入cnblog不久,发现上面有很多优秀的文章。 无意中发现cnblog有整理文章的收藏排行榜,也就是热门文摘. 不过有点坑的是,这个页面不支持搜索,所以就写一个简单的脚本把这些热门文章理出来。 整个爬虫的思路: 确定页面的接口,一般常见的格式是html或者json格式; 确定页面迭代变量,找到page_index 对单页进行测试,包括header信息的配置,以及所需字段的提取; 对第3步中的代码进行封装,放到循环内执行; 页面说明 收藏文章排行的url示例 https://wz.cnblogs.com/hot/All/2 最后一个是页数(pageindex),这个是后面要放入for循环里的迭代变量. 从页面上的显示来看,最多可以抓100页 需要用的module importrequests,re importpandasaspd importlxml.html importtime,sys 复制 单页测试 先测试下单个页面,需要解析出页面下的: 文章url 文章title 收藏数 url='https://wz.

  • ubuntu下vim使用方法

    按下's'可对文本进行编辑 按下'ESC'再输入':',之后输入wq是保存再退出,输入q是直接退出。如果是只读readonly模式则需要输入'wq!'保存退出。 兴趣是最好的导师

相关推荐

推荐阅读