当前位置: 首页  - 技术分享  - 数据爬虫  - 列表 - 第12页 学而时习之,不亦说乎
站长工具大全,网站收录推送,伪原创

数据爬虫

数据爬虫昨晚,我用python帮隔壁小姐姐P证件照 自拍,然后发现。。。

昨晚,我用python帮隔壁小姐姐P证件照 自拍,然后发现。。。

大家好,我是Lex 喜欢欺负超人那个Lex 建议大家收藏哦,以后帮小姐姐P自拍、证件照、调尺寸、背景、抠图,直接10行代码搞定,瞬间高大上。 事情是这样的 晚上,正在聚精会神写代码 突然,收到隔壁小姐姐给我发来的消息 还有一张证件自拍照 而且是可以放在结婚证上的那种哦   就是 之前帮过她几次忙 难道要以身相许 去一起办证

数据爬虫第十四届全国大学生信息安全竞赛部分wp

第十四届全国大学生信息安全竞赛部分wp

第十四届全国大学生信息安全竞赛部分wp 前言MISC-Robot补充用PIL写法misc running_pixelMisc tiny traffic隔空传话密码学RSAweb1Re1web2总结 前言 第一次参加国赛,更让我清楚意识到自己是fw,做出几道题记录一下,期待自己的进步成长 MISC-Robot 下载得到 结合题目是机器,要

数据爬虫进大厂全靠它了!10个Python实战项目+5张Python图谱打包给你!

进大厂全靠它了!10个Python实战项目+5张Python图谱打包给你!

​前言:如果有人问:“Python还火吗?”“当然,很火。”“哪能火多久呢?”“不知道。” 技术发展到现在衍生出许多种编程语言,但没有任何一门语言能处于垄断地位(我们现在生身处于Java的时代),Python是当前流行的语言,其最主要原因是简单易学,没有复杂的逻辑关系,吸引了一大批准程序员/程序员的关注与学习,但很多人在学完基础部分后,开

数据爬虫『Python爬虫菜鸟教程』快速入门实战:统计分析CSDN与博客园博客阅读数据

『Python爬虫菜鸟教程』快速入门实战:统计分析CSDN与博客园博客阅读数据

文章目录 0x01:引子 首先介绍一下网络爬虫是什么,可以用来做什么? 这里简单探讨一下网络爬虫的合法性 正式进入爬虫实战前,需要我们了解下网页结构 HTML CSS JScript 写一个简单的 HTML 0x02:实操 安装依赖 爬虫的基本原理 统计分析CSDN博客阅读数据 使用 GET 方式抓取数据 使用 Beautiful So

数据爬虫你想象的黑客是什么样的?Python是黑客攻击语言的不二之选吗?

你想象的黑客是什么样的?Python是黑客攻击语言的不二之选吗?

一、黑客的初衷与故事 Hacker(黑客),往往被人们理解为只会用非法手段来破坏网络安全的计算机高手。但是,黑客其实不是这样的,真正的“网络破坏者”是与黑客名称读音都相似的骇客。 骇客,是用黑客手段进行非法操作并为己取得利益的人。黑客,是用黑客手段为单位做事的人。 黑客与骇客的故事 骇客其实他的前身就是黑客,黑客是很善良的, 原本,只有

数据爬虫Python生成字符视频

Python生成字符视频

Python生成字符视频 一、前言 在之前也写过生成字符视频的文章,但是使用的是命令行窗口输出,效果不是很好,而且存在卡顿的情况。于是我打算直接生成一个mp4的字符视频。大致思路和之前一样:Python20行代码实现视频字符化。 下面来看一个效果图: 二、OpenCV的操作图像 我们先来看一些基本操作。首先我们需要安装OpenCV,执行

数据爬虫

作为一个“精灵鬼”,这么有价值的数据,我必须帮老爸解开呀

寻找思路

解密压缩包的思路是什么?
答:通过各种密码去尝试解压文件。

用什么解压文件?
答:zip 使用 zipfilerar 使用 rarfile,已经有 Python 大佬给我们写好啦,只需要调用它们的方法即可。

密码从哪里找?
答:程序自行运算或者找密码本。

思路整理清楚之后,就可以开始了。

zipfile 与 rarfile

解压文件使用二者生成对象的 extractall 方法即可。

以下内容以 zipfile 库进行举例,举一反三即可。

先默默通过 zipfile 解压一个没有密码的文件,试试手感。

测试文件自己进行打包压缩即可,先尝试英文或者数字文件命名,在尝试中文命名。

import zipfile  try:     # 创建 ZipFile 对象     with zipfile.ZipFile('测试文件.zip" title="我爸电脑上有个加密压缩包,我给用 Python 给解开了" alt="我爸电脑上有个加密压缩包,我给用 Python 给解开了"/>

我爸电脑上有个加密压缩包,我给用 Python 给解开了

老爸说他有个照片文件夹打不开了,让我过去看看,一瞅,好家伙,加密压缩包尘封老照片呀。 既然加密,没准还有意外收货。 作为一个“精灵鬼”,这么有价值的数据,我必须帮老爸解开呀。 寻找思路 解密压缩包的思路是什么? 答:通过各种密码去尝试解压文件。 用什么解压文件? 答:zip 使用 zipfile,rar 使用 rarfile,已经

数据爬虫

他们的图怎么就这么多?结果一问,每个人手机里都专门存了几十张表情包,有的人甚至存了上百张…原来这就是他们“嚣张”斗图的原因?!

我想了想,斗图不就是比谁的表情包多吗?那谁能比我们程序员表情包多?爬虫一爬就是成千上万张!

今天就教大家一招用Python爬虫一键爬取海量表情包,分分钟碾压那些斗图狂魔!并附上源码。

二、思路解析

1.创建请求头,也被称为伪装浏览器

可能有些同学会问了,什么是请求头啊。请求头其实就是一个用户代理,在请求头中是包含了当前用户的操作系统版本信息以及当前用户访问网站所使用的浏览器版本信息。

那么为什么要创建请求头呢,因为在网站访问的过程中,有大部分网站会对当前请求做验证,来判断当前的请求是否合法(不是使用浏览器来获取网站数据的话会被认为非法请求)。如果不添加请求头的话,可能会出现当前网站没有访问权限。

创建方法:

1.打开浏览器
2.按住f12
3.选中NetWork选项卡
4.点击筛选出来的链接(链接选择随意)
5.找到user-agent选项并复制

	'user-agent': 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36' 

2.使用requests 网络请求库完成网站数据请求

当我们创建完成请求头之后就需要访问网站拿到网站的页面数据了,那么如何获取网站数据呢,这时候就需要使用requests来帮助我们获取了。

在使用requests之前,需要先下载安装。
下载安装命令:pip install requests -i https://pypi.douban.com/simple

安装完成之后我们就可以使用requests了
使用方法:requests.get(‘https://fabiaoqing.com/biaoqing/lists/page/1.html’, headers=headers).text

在获取网页数据的时候,需要调用http协议中的get方法来获取页面数据,一般情况下会返回html页面源代码
需要传入的参数:网站的域名以及请求头

如果想获取文本数据,那么久调用requests中内置的text方法返回文本数据,如果想要获取二进制数据则使用内置的content方法。

3.获取数据后使用bs4对页面数据进行提取

因为一个页面包含的数据太多了,例如:搜索框、页面广告、ICP备案号等等。但是我们只是想要获取页面中的表情包图片,那该怎么办呢?这时候我们就需要用到一个非常好用的第三方包:bs4

使用方法:

1.在浏览器中按住f12调出开发者工具,点击Elements,之后点击元素选择器(左边的小箭头),之后选中页面上的图片,左键点击。浏览器就会帮助我们定位图片所在html代码的位置

2.看到被选中的标签后,查看当前图片的元素标签,当前标签是img,观察当前标签中的属性,有一个class属性,复制该属性的值

3.调用方法:find_all(‘img’, class_=‘ui image lazy’),调用之后会返回图片标签的列表

4.对列表进行循环,将img标签中的data-original属性的值提取出来

		for i in img_list: 			image_url = i['data-original'] 

5.提取完成之后将会获得当前页面所有的图片标签,我们对当前获取的链接进行二次请求并使用python内置的with open方法将图片数据下载到本地

		with open('./' + '图片名称' + '文件后缀名', 'wb') as f: 			image_data = requests.get(image_url, headers=headers).content 			f.write(image_data) 

至此,一个简单的微信表情包爬虫就制作完成。

三、源码

import os import requests from bs4 import BeautifulSoup  if not os.path.exists('./images/'):     os.mkdir('./images/')  headers = { 	'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36' }  url = 'https://fabiaoqing.com/biaoqing/lists/page/1.html' response = requests.get(url, headers=headers).text  ''' lxml: html解析库,因为python和html两者没有关系 python没有办法直接控制html代码 我们就需要使用lxml这个库将html代码转成python对象     需要大家去下载 pip install lxml ''' soup = BeautifulSoup(response, 'lxml') img_list = soup.find_all('img" title="Python爬虫一键爬取海量表情包,分分钟碾压斗图狂魔!【附源码】" alt="Python爬虫一键爬取海量表情包,分分钟碾压斗图狂魔!【附源码】"/>

Python爬虫一键爬取海量表情包,分分钟碾压斗图狂魔!【附源码】

一、前言 有时候我不是很理解聊天斗图的现象,年轻人也就罢了,但我这种四十多岁的圈子里,居然还盛行聊天斗图这种风气…一把年纪了还当斗图狂魔… 他们的图怎么就这么多?结果一问,每个人手机里都专门存了几十张表情包,有的人甚至存了上百张…原来这就是他们“嚣张”斗图的原因?! 我想了想,斗图不就是比谁的表情包多吗?那谁能比我们程序员表情包多?爬虫一

数据爬虫
我们利用json()方法,直接将json字符串,转换为了dict格式的数据。扫描一下数据,我的妈!一大堆,我该怎么解析?

pprint模块的妙用

那么,有没有一种好的办法,能够快速帮助我们理清字典嵌套之间的关系呢?pprint模块是一个很好的选择。

这是一个第三方库,在使用之前,我们需要pip安装。

pip install pprint 

安装后,直接导入即可。

from pprint import pprint 

接着,对于上述案例,我们使用pprint()函数,打印一下,看看会有什么好的效果呢?

from pprint import pprint  pprint(data) 

结果如下:

从图中可以看出,这个嵌套关系,一目了然,清清楚楚,明明白白,这样应该很好解析了吧。

下面在用一个简单的案例,带大家感受一下。

dic = { 'main" title="超级牛逼的Python库,漂亮的打印,爬虫爱好者最喜欢!" alt="超级牛逼的Python库,漂亮的打印,爬虫爱好者最喜欢!"/>

超级牛逼的Python库,漂亮的打印,爬虫爱好者最喜欢!

遇到的问题 在学习爬虫的时候,大家肯定碰到过返回的结果是json字符串格式的数据。 对于这种数据我们通常使用的是json模块,将json字符串,转化为字典格式的数据,然后采用 “键值对” 方式,获取我们想要的数据。 但是存在一个问题: 往往网页获取到的json数据转化为字典后,嵌套太多,一层接着一层,看起来一团糟的感觉,往往不知道哪个节点

数据爬虫Python爬虫实践--爬取网易云音乐

Python爬虫实践--爬取网易云音乐

Python爬虫实践 前言Python + 爬虫下载歌词坑点与进阶坑解决python模拟浏览器缺点总结全部代码 前言 最近,网易的音乐很多听不到了,刚好也看到很多教程,跟进学习了一下,也集大全了吧,本来想优化一下的,但是发现问题还是有点复杂,最后另辟捷径,提供了简单的方法啊! Python + 爬虫 首先,说一下准备工作: Python

数据爬虫

1. 冒泡排序

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  lis = [56,12,1,8,354,10,100,34,56,7,23,456,234,-58]  def sortport():     for i in range(len(lis)-1):         for j in range(len(lis)-1-i):             if lis[j] > lis[j+1]:                 lis[j],lis[j+1] = lis[j+1],lis[j]     print(lis)     return lis  sortport() 

2. 计算 x 的 n 次方的方法

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  def power(x,n):     s = 1     while n > 0:         n = n-1         #n -= 1         s = s * x          print(s)     return s  power(5,3) 

3. 计算 a * a + b * b + c * c + ……

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  def calc(*numbers):     sum = 0     for n in numbers:         sum = sum + n * n     print(sum)     return sum  calc(2,34,4,5,221,45,0,7) 

4. 计算阶乘 n!

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  def fac():     num = int(input('请输入一个数字:'))     factorial = 1  #查看数字是负数,0 或者 正数     if num < 0:         print(('抱歉,负数没有阶乘'))     elif num == 0:         print('0的阶乘为 1')     else:         for i in range(1,num + 1):             factorial *= i             factorial = factorial*i         print('%d 的阶乘为 %d' %(num, factorial))  fac()  def factorial(n):     result = n     for i in range(1,n):         result *= i     return result  def fact(n):     if n == 1:         return 1     return n * fact(n-1)  

5. 列出当前目录下的所有文件和目录名

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  import os  list = [d for d in os.listdir('31个应用项目(代码复用)')] print(list)  print('--------------------') for d in os.listdir('31个应用项目(代码复用)'):     print(d) 
  1. 把一个 list 中所有的字符串变成小写
# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  L = ['Hello','World','IBM','apple']  # n = [s.lower for s in L] # print(n)  for n in L:     print(n.lower()) 

7. 输出某个路径下的所有文件和文件夹的路径

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  import os  def print_dir():     filepath = input('请输入一个路径:')      if filepath == '':         print('请输入正确的路径')     else:         for i in os.listdir(filepath):             print(os.path.join(filepath,i))  print(print_dir()) 

8. 输出某个路径及其子目录下的所有文件路径

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  import os  def show_dir(filename):     for i in os.listdir(filename):         path = (os.path.join(filename,i))         print(path)         if os.path.isdir(path):   #isdir 判断是否是目录             show_dir(path)        #如果是目录,使用递归方法  filename = input('请输入路径:')  show_dir(filename) 

9. 输出某个路径及其子目录下所有以.html 为后缀的文件

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  import os  def print_dir(filepath):     for i in os.listdir(filepath):         path = os.path.join(filepath,i)          if os.path.isdir(path):             print_dir(path)          if path.endswith('.html'):             print(path)  filepath = input('请输入路径:') print_dir(filepath) 

10. 把原字典的键值对颠倒并生产新的字典

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  dict1 = {'a':'1','b':'2','c':'3'} dict2 = {y:x for x,y in dict1.items()}  print(dict2) 

11. 打印九九乘法表

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  for i in range(1,10):     for j in range(1,i+1):         print('{}x{}={}'.format(j,i,i*j),end = ' ')     print() 

通过指定 end 参数的值,可以取消在末尾输出回车符,实现不换行。

12. 替换列表中所有的 3 为 3a

# 个人公众号:yk 坤帝 # 后台回复‘代码复用’获得全部源码 # 大二 # 2021年5月10日  num = ['haaden" title="31个全网最常用python实现(体系学习,学完显著提高代码复用能力)" alt="31个全网最常用python实现(体系学习,学完显著提高代码复用能力)"/>

31个全网最常用python实现(体系学习,学完显著提高代码复用能力)

1. 冒泡排序 2. 计算 x 的 n 次方的方法 3. 计算 aa + bb + c*c + …… 4. 计算阶乘 n! 5. 列出当前目录下的所有文件和目录名 6. 把一个 list 中所有的字符串变成小写 7. 输出某个路径下的所有文件和文件夹的路径 8. 输出某个路径及其子目录下的所有文件路径 9. 输出某个路径及其子目录下所有以

数据爬虫“升级版后浪”刷屏:B站别再搬砖砸自己脚了!

“升级版后浪”刷屏:B站别再搬砖砸自己脚了!

这几天,B站又被骂了。距上次北邮校招中公然PUA惹怒全国年轻人还不到一个月... 青年节,B站发布了“升级版后浪”——《我不想做这样的人》。小部看了这个视频后,只觉得五味杂陈,百感交集。 这个宣传片在青年节放出来,明显是为了讨年轻用户欢心。 看似尊重年轻群体,实则B站还是改不了“好为人师”的毛病。B站“为人师”的结果,却又往往不尽如人意

数据爬虫如何将Python写的代码打包成.exe可执行文件

如何将Python写的代码打包成.exe可执行文件

有时候我们需要将自己写的代码打包成exe文件,给别人使用需要怎么办呢?以下将讲解Python代码如何打包成.exe文件。 1. 下载pyinstaller 因为Python中有很多三方包,我们想要这些三方包也包含在里面就需要一个工具,就是pyinstaller,很简单,直接在命令行输入pip install pyinstaller 或者使

数据爬虫

敏感的小哥哥心生疑窦,难道会有原谅帽

然后python撸了一段代码 分析照片

分析下来 emmm

拍摄地址居然在 XXX酒店

小哥哥崩溃之余 大呼上当

 

python分析照片

小哥哥将发给自己的照片原图下载下来

并使用python写了一个脚本

读取到了照片拍摄的详细的地址

详细到了具体的街道和酒店名称

 

引入exifread模块

首先安装python的exifread模块,用于照片分析

pip install exifread 安装exfriead模块

PS C:\WINDOWS\system32> pip install exifread Collecting exifread   Downloading ExifRead-2.3.2-py3-none-any.whl (38 kB) Installing collected packages: exifread Successfully installed exifread-2.3.2 PS C:\WINDOWS\system32> pip install json

 

GPS经纬度信息

其实我们平时拍摄的照片里,隐藏了大量的私密信息

包括 拍摄时间、极其精确 具体的GPS信息。

下面是通过exifread模块,来读取照片内的经纬度信息。

#读取照片的GPS经纬度信息 def find_GPS_image(pic_path):     GPS = {}     date = ''     with open(pic_path, 'rb') as f:         tags = exifread.process_file(f)         for tag, value in tags.items():             #纬度             if re.match('GPS GPSLatitudeRef" title="女友半夜加班发自拍 python男友用30行代码发现惊天秘密" alt="女友半夜加班发自拍 python男友用30行代码发现惊天秘密"/>

女友半夜加班发自拍 python男友用30行代码发现惊天秘密

事情是这样的 正准备下班的python开发小哥哥 接到女朋友今晚要加班的电话 并给他发来一张背景模糊的自拍照 如下 ↓ ↓ ↓ 敏感的小哥哥心生疑窦,难道会有原谅帽 然后python撸了一段代码 分析照片 分析下来 emmm 拍摄地址居然在 XXX酒店 小哥哥崩溃之余 大呼上当   python分析照片 小哥哥将发给自己的照片原

数据爬虫

一、实验简介

本实验将使用 Python3 去识别图片是否为色情图片,我们会使用到 PIL 这个图像处理库,会编写算法来划分图像的皮肤区域

1.1. 知识点

Python 3 的模块的安装
Python 3 基础知识
肤色像素检测与皮肤区域划分算法
Pillow 模块的使用
argparse 模块的使用
1.2. 效果展示

二、实验步骤

2.1. 安装包

PIL 2009年之后就没有更新了,也不支持 Python3 ,于是有了 Alex Clark 领导的公益项目 Pillow,Pillow 是一个对 PIL 友好的分支,支持 Python3,所以我们这里安装的是 Pillow,其官方文档

安装前更新源

$ sudo apt-get update

首先我们需要处理一个问题:当前实验楼的环境中 python3 命令使用的 python 版本为 3.5,但源中却没有 python3.5-dev,这会导致安装 Pillow 出错。所以我们必须将 python3 命令使用的 python 版本切换为 3.4,然后再安装 python3-dev 和 python3-setuptools。

$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.4 70 --slave /usr/bin/python3m python3m /usr/bin/python3.4m
$ sudo apt-get install python3-dev python3-setuptools

然后安装 Pillow 依赖包

$ sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev \ libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-devpython-tk

安装 pip3,pip 是 Python2 的软件包管理系统,使用它来安装 Python2 的模块非常简便,而 pip3 则是对应于 Python3 的版本

$ sudo apt-get install python3-pip

最后安装 Pillow:

$ sudo pip3 install Pillow

2.2. 程序原理

本程序根据颜色(肤色)找出图片中皮肤的区域,然后通过一些条件判断是否为色情图片

程序的关键步骤如下:

遍历每个像素,检测像素颜色是否为肤色
将相邻的肤色像素归为一个皮肤区域,得到若干个皮肤区域
剔除像素数量极少的皮肤区域
我们定义非色情图片的判定规则如下(满足任意一个判定为真):

皮肤区域的个数小于 3 个
皮肤区域的像素与图像所有像素的比值小于 15%
最大皮肤区域小于总皮肤面积的 45%
皮肤区域数量超过60个
这些规则你可以尝试更改,直到程序效果让你满意为止

关于像素肤色判定这方面,公式可以在网上找到很多,但世界上不可能有正确率 100% 的公式

你可以用自己找到的公式,在程序完成后慢慢调试

RGB 颜色模式

第一种:r > 95 and g > 40 and g < 100 and b > 20 and max([r, g, b]) - min([r, g, b]) > 15 and abs(r - g) > 15 and r > g and r > b

第二种:nr = r / (r + g + b), ng = g / (r + g + b), nb = b / (r +g + b),nr / ng > 1.185 and r * b / (r + g + b) ** 2 > 0.107 and r * g / (r + g + b) ** 2 > 0.112

HSV 颜色模式

h > 0 and h < 35 and s > 0.23 and s < 0.68

YCbCr 颜色模式

97.5 <= cb <= 142.5 and 134 <= cr <= 176

一幅图像有零个到多个的皮肤区域,程序按发现顺序给它们编号,第一个发现的区域编号为 0,第 n 个发现的区域编号为 n-1

我们用一种类型来表示像素,我们给这个类型取名为 Skin,包含了像素的一些信息:唯一的 编号(id),是/否肤色(skin),皮肤区域号(region),横坐标(x),纵坐标(y)

遍历所有像素时,我们为每个像素创建一个与之对应的 Skin 对象,并设置对象的所有属性

其中 region 属性即为像素所在的皮肤区域编号,创建对象时初始化为无意义的 None

关于每个像素的 id 值,左上角为原点,像素的 id 值按像素坐标排布,那么看起来如下图

其实 id 的顺序也即遍历的顺序

遍历所有像素时,创建 Skin 对象后,如果当前像素为肤色,且相邻的像素有肤色的,那么我们把这些肤色像素归到一个皮肤区域

相邻像素的定义:通常都能想到是当前像素周围的 8 个像素,然而实际上只需要定义 4 个就可以了,位置分别在当前像素的左方,左上方,正上方,右上方;因为另外四个像素都在当前像素后面,我们还未给这4个像素创建对应的 Skin 对象

接下来实现细节部分

2.3. 实现脚本

导入所需要的模块

import sys import os import _io from collections import namedtuple from PIL import Image 

我们将设计一个 Nude 类:

class Nude(object):

这个类里面我们首先使用 collections.namedtuple() 定义一个 Skin 类型

Skin = namedtuple(“Skin”, “id skin region x y”)

collections.namedtuple() 函数实际上是一个返回Python中标准元组类型子类的一个工厂方法。 你需要传递一个类型名和你需要的字段给它,然后它就会返回一个类,你可以初始化这个类,为你定义的字段传递值等。 详情参见官方文档。

然后定义 Nude 类的初始化方法

def __init__(self, path_or_image):  # 若 path_or_image 为 Image.Image 类型的实例,直接赋值  if isinstance(path_or_image, Image.Image):   self.image = path_or_image  # 若 path_or_image 为 str 类型的实例,打开图片  elif isinstance(path_or_image, str):   self.image = Image.open(path_or_image)    # 获得图片所有颜色通道  bands = self.image.getbands()  # 判断是否为单通道图片(也即灰度图),是则将灰度图转换为 RGB 图  if len(bands) == 1:   # 新建相同大小的 RGB 图像   new_img = Image.new("RGB", self.image.size)   # 拷贝灰度图 self.image 到 RGB图 new_img.paste (PIL 自动进行颜色通道转换)   new_img.paste(self.image)   f = self.image.filename   # 替换 self.image   self.image = new_img   self.image.filename = f    # 存储对应图像所有像素的全部 Skin 对象  self.skin_map = []  # 检测到的皮肤区域,元素的索引即为皮肤区域号,元素都是包含一些 Skin 对象的列表  self.detected_regions = []  # 元素都是包含一些 int 对象(区域号)的列表  # 这些元素中的区域号代表的区域都是待合并的区域  self.merge_regions = []  # 整合后的皮肤区域,元素的索引即为皮肤区域号,元素都是包含一些 Skin 对象的列表  self.skin_regions = []  # 最近合并的两个皮肤区域的区域号,初始化为 -1  self.last_from, self.last_to = -1, -1  # 色情图像判断结果  self.result = None  # 处理得到的信息  self.message = None  # 图像宽高  self.width, self.height = self.image.size  # 图像总像素  self.total_pixels = self.width * self.height 

本实验代码中使用到的模块中的函数均可以在其模块的文档中找到,一定要培养查阅文档的习惯

isinstane(object, classinfo) 如果参数 object 是参数 classinfo 的实例,返回真,否则假;参数 classinfo可以是一个包含若干 type 对象的元祖,如果参数 object 是其中任意一个类型的实例,返回真,否则假
涉及到效率问题,越大的图片所需要消耗的资源与时间越大,因此有时候可能需要对图片进行缩小

所以需要有图片缩小方法

def resize(self, maxwidth=1000, maxheight=1000):  """  基于最大宽高按比例重设图片大小,  注意:这可能影响检测算法的结果    如果没有变化返回 0  原宽度大于 maxwidth 返回 1  原高度大于 maxheight 返回 2  原宽高大于 maxwidth, maxheight 返回 3    maxwidth - 图片最大宽度  maxheight - 图片最大高度  传递参数时都可以设置为 False 来忽略  """  # 存储返回值  ret = 0  if maxwidth:   if self.width > maxwidth:    wpercent = (maxwidth / self.width)    hsize = int((self.height * wpercent))    fname = self.image.filename    # Image.LANCZOS 是重采样滤波器,用于抗锯齿    self.image = self.image.resize((maxwidth, hsize), Image.LANCZOS)    self.image.filename = fname    self.width, self.height = self.image.size    self.total_pixels = self.width * self.height    ret += 1  if maxheight:   if self.height > maxheight:    hpercent = (maxheight / float(self.height))    wsize = int((float(self.width) * float(hpercent)))    fname = self.image.filename    self.image = self.image.resize((wsize, maxheight), Image.LANCZOS)    self.image.filename = fname    self.width, self.height = self.image.size    self.total_pixels = self.width * self.height    ret += 2  return ret Image.resize(size, resample=0) 

size – 包含宽高像素数的元祖 (width, height) resample – 可选的重采样滤波器

返回 Image 对象
然后便是最关键之一的解析方法了

def parse(self):  # 如果已有结果,返回本对象  if self.result is not None:   return self  # 获得图片所有像素数据  pixels = self.image.load() 

接着,遍历每个像素,为每个像素创建对应的 Skin 对象,代码见下

其中 self._classify_skin() 这个方法是检测像素颜色是否为肤色

for y in range(self.height):  for x in range(self.width):   # 得到像素的 RGB 三个通道的值   # [x, y] 是 [(x,y)] 的简便写法   r = pixels[x, y][0] # red   g = pixels[x, y][1] # green   b = pixels[x, y][2] # blue   # 判断当前像素是否为肤色像素   isSkin = True if self._classify_skin(r, g, b) else False   # 给每个像素分配唯一 id 值(1, 2, 3...height*width)   # 注意 x, y 的值从零开始   _id = x + y * self.width + 1   # 为每个像素创建一个对应的 Skin 对象,并添加到 self.skin_map 中   self.skin_map.append(self.Skin(_id, isSkin, None, x, y)) 

若当前像素并不是肤色,那么跳过本次循环,继续遍历

# 若当前像素不为肤色像素,跳过此次循环 if not isSkin:  continue 

若当前像素是肤色像素,那么就需要处理了,先遍历其相邻像素

一定要注意相邻像素的索引值,因为像素的 id 值是从 1 开始编起的,而索引是从 0 编起的。变量 _id 是存有当前像素的id 值, 所以当前像素在 self.skin_map 中的索引值为 _id - 1,以此类推,那么其左方的相邻像素在 self.skin_map 中的索引值为 _id - 1 - 1 ,左上方为 _id - 1 - self.width - 1,上方为 _id - 1 - self.width ,右上方为 _id - 1 - self.width + 1

# 设左上角为原点,相邻像素为符号 *,当前像素为符号 ^,那么相互位置关系通常如下图 # *** # *^   # 存有相邻像素索引的列表,存放顺序为由大到小,顺序改变有影响 # 注意 _id 是从 1 开始的,对应的索引则是 _id-1 check_indexes = [_id - 2, # 当前像素左方的像素      _id - self.width - 2, # 当前像素左上方的像素      _id - self.width - 1, # 当前像素的上方的像素      _id - self.width] # 当前像素右上方的像素 

说起来复杂,其实看上面代码并不复杂,说这么多是怕同学搞混,你要是觉得有点绕的话,你也可以把 id 值从 0 编起

# 用来记录相邻像素中肤色像素所在的区域号,初始化为 -1 region = -1 # 遍历每一个相邻像素的索引 for index in check_indexes:  # 尝试索引相邻像素的 Skin 对象,没有则跳出循环  try:   self.skin_map[index]  except IndexError:   break  # 相邻像素若为肤色像素:  if self.skin_map[index].skin:   # 若相邻像素与当前像素的 region 均为有效值,且二者不同,且尚未添加相同的合并任务   if (self.skin_map[index].region != None and     region != None and region != -1 and     self.skin_map[index].region != region and     self.last_from != region and     self.last_to != self.skin_map[index].region) :    # 那么这添加这两个区域的合并任务    self._add_merge(region, self.skin_map[index].region)   # 记录此相邻像素所在的区域号   region = self.skin_map[index].region 

self._add_merge() 这个方法接收两个区域号,它将会把两个区域号添加到 self.merge_regions 中的元素中,self.merge_regions 的每一个元素都是一个列表,这些列表中存放了 1 到多个的区域号,区域号代表的区域是连通的,需要合并

检测的图像里,有些前几行的像素的相邻像素并没有 4 个,所以需要用 try “试错”

然后相邻像素的若是肤色像素,如果两个像素的皮肤区域号都为有效值且不同,因为两个区域中的像素相邻,那么其实这两个区域是连通的,说明需要合并这两个区域。记录下此相邻肤色像素的区域号,之后便可以将当前像素归到这个皮肤区域里了。

遍历完所有相邻像素后,分两种情况处理

所有相邻像素都不是肤色像素:发现了新的皮肤区域
存在区域号为有效值的相邻肤色像素:region 的中存储的值有用了,把当前像素归到这个相邻像素所在的区域

# 遍历完所有相邻像素后,若 region 仍等于 -1,说明所有相邻像素都不是肤色像素 if region == -1:  # 更改属性为新的区域号,注意元祖是不可变类型,不能直接更改属性  _skin = self.skin_map[_id - 1]._replace(region=len(self.detected_regions))  self.skin_map[_id - 1] = _skin  # 将此肤色像素所在区域创建为新区域  self.detected_regions.append([self.skin_map[_id - 1]]) # region 不等于 -1 的同时不等于 None,说明有区域号为有效值的相邻肤色像素 elif region != None:  # 将此像素的区域号更改为与相邻像素相同  _skin = self.skin_map[_id - 1]._replace(region=region)  self.skin_map[_id - 1] = _skin  # 向这个区域的像素列表中添加此像素  self.detected_regions[region].append(self.skin_map[_id - 1]) 

somenamedtuple._replace(kwargs) 返回一个替换指定字段的值为参数的 namedtuple 实例
遍历完所有像素之后,图片的皮肤区域划分初步完成了,只是在变量 self.merge_regions 中还有一些连通的皮肤区域号,它们需要合并,合并之后就可以进行色情图片判定了

# 完成所有区域合并任务,合并整理后的区域存储到 self.skin_regions self._merge(self.detected_regions, self.merge_regions) # 分析皮肤区域,得到判定结果 self._analyse_regions() return self 

方法 self._merge() 便是用来合并这些连通的皮肤区域的

方法 self._analyse_regions(),运用之前在程序原理一节定义的非色情图像判定规则,从而得到判定结果

现在编写我们还没写过的调用过的 Nude 类的方法

首先是 self._classify_skin() 方法,这个方法是检测像素颜色是否为肤色,之前在程序原理一节已经把肤色判定该公式列举了出来,现在是用的时候了

# 基于像素的肤色检测技术 def _classify_skin(self, r, g, b):  # 根据RGB值判定  rgb_classifier = r > 95 and \   g > 40 and g < 100 and \   b > 20 and \   max([r, g, b]) - min([r, g, b]) > 15 and \   abs(r - g) > 15 and \   r > g and \   r > b  # 根据处理后的 RGB 值判定  nr, ng, nb = self._to_normalized(r, g, b)  norm_rgb_classifier = nr / ng > 1.185 and \   float(r * b) / ((r + g + b) ** 2) > 0.107 and \   float(r * g) / ((r + g + b) ** 2) > 0.112    # HSV 颜色模式下的判定  h, s, v = self._to_hsv(r, g, b)  hsv_classifier = h > 0 and \   h < 35 and \   s > 0.23 and \   s < 0.68    # YCbCr 颜色模式下的判定  y, cb, cr = self._to_ycbcr(r, g, b)  ycbcr_classifier = 97.5 <= cb <= 142.5 and 134 <= cr <= 176    # 效果不是很好,还需改公式  # return rgb_classifier or norm_rgb_classifier or hsv_classifier or ycbcr_classifier  return ycbcr_classifier 

颜色模式的转换并不是本实验的重点,转换公式可以在网上找到,这里我们直接拿来用就行

def _to_normalized(self, r, g, b):  if r == 0:   r = 0.0001  if g == 0:   g = 0.0001  if b == 0:   b = 0.0001  _sum = float(r + g + b)  return [r / _sum, g / _sum, b / _sum]   def _to_ycbcr(self, r, g, b):  # 公式来源:  # http://stackoverflow.com/questions/19459831/rgb-to-ycbcr-conversion-problems  y = .299*r + .587*g + .114*b  cb = 128 - 0.168736*r - 0.331364*g + 0.5*b  cr = 128 + 0.5*r - 0.418688*g - 0.081312*b  return y, cb, cr   def _to_hsv(self, r, g, b):  h = 0  _sum = float(r + g + b)  _max = float(max([r, g, b]))  _min = float(min([r, g, b]))  diff = float(_max - _min)  if _sum == 0:   _sum = 0.0001    if _max == r:   if diff == 0:    h = sys.maxsize   else:    h = (g - b) / diff  elif _max == g:   h = 2 + ((g - r) / diff)  else:   h = 4 + ((r - g) / diff)    h *= 60  if h < 0:   h += 360    return [h, 1.0 - (3.0 * (_min / _sum)), (1.0 / 3.0) * _max] 

self._add_merge() 方法主要是对 self.merge_regions 操作,而self.merge_regions 的元素都是包含一些 int 对象(区域号)的列表,列表中的区域号代表的区域都是待合并的区域

self._add_merge() 方法接收两个区域号,将之添加到 self.merge_regions 中

这两个区域号以怎样的形式添加,要分3种情况处理,

传入的两个区域号都存在于 self.merge_regions 中
传入的两个区域号有一个区域号存在于 self.merge_regions 中
传入的两个区域号都不存在于 self.merge_regions 中
具体的处理方法,见代码

def _add_merge(self, _from, _to):  # 两个区域号赋值给类属性  self.last_from = _from  self.last_to = _to    # 记录 self.merge_regions 的某个索引值,初始化为 -1  from_index = -1  # 记录 self.merge_regions 的某个索引值,初始化为 -1  to_index = -1      # 遍历每个 self.merge_regions 的元素  for index, region in enumerate(self.merge_regions):   # 遍历元素中的每个区域号   for r_index in region:    if r_index == _from:     from_index = index    if r_index == _to:     to_index = index    # 若两个区域号都存在于 self.merge_regions 中  if from_index != -1 and to_index != -1:   # 如果这两个区域号分别存在于两个列表中   # 那么合并这两个列表   if from_index != to_index:    self.merge_regions[from_index].extend(self.merge_regions[to_index])    del(self.merge_regions[to_index])   return    # 若两个区域号都不存在于 self.merge_regions 中  if from_index == -1 and to_index == -1:   # 创建新的区域号列表   self.merge_regions.append([_from, _to])   return  # 若两个区域号中有一个存在于 self.merge_regions 中  if from_index != -1 and to_index == -1:   # 将不存在于 self.merge_regions 中的那个区域号   # 添加到另一个区域号所在的列表   self.merge_regions[from_index].append(_to)   return  # 若两个待合并的区域号中有一个存在于 self.merge_regions 中  if from_index == -1 and to_index != -1:   # 将不存在于 self.merge_regions 中的那个区域号   # 添加到另一个区域号所在的列表   self.merge_regions[to_index].append(_from)   return 

在序列中循环时,索引位置和对应值可以使用 enumerate() 函数同时得到,在上面的代码中,索引位置即为 index ,对应值即为region

self._merge() 方法则是将 self.merge_regions 中的元素中的区域号所代表的区域合并,得到新的皮肤区域列表

def _merge(self, detected_regions, merge_regions):  # 新建列表 new_detected_regions   # 其元素将是包含一些代表像素的 Skin 对象的列表  # new_detected_regions 的元素即代表皮肤区域,元素索引为区域号  new_detected_regions = []    # 将 merge_regions 中的元素中的区域号代表的所有区域合并  for index, region in enumerate(merge_regions):   try:    new_detected_regions[index]   except IndexError:    new_detected_regions.append([])   for r_index in region:    new_detected_regions[index].extend(detected_regions[r_index])    detected_regions[r_index] = []    # 添加剩下的其余皮肤区域到 new_detected_regions  for region in detected_regions:   if len(region) > 0:    new_detected_regions.append(region)    # 清理 new_detected_regions  self._clear_regions(new_detected_regions)     # 添加剩下的其余皮肤区域到 new_detected_regions   for region in detected_regions:    if len(region) > 0:     new_detected_regions.append(region)     # 清理 new_detected_regions   self._clear_regions(new_detected_regions) 

self._clear_regions() 方法只将像素数大于指定数量的皮肤区域保留到 self.skin_regions

# 皮肤区域清理函数 # 只保存像素数大于指定数量的皮肤区域 def _clear_regions(self, detected_regions):  for region in detected_regions:   if len(region) > 30:    self.skin_regions.append(region) 

self._analyse_regions() 是很简单的,它的工作只是进行一系列判断,得出图片是否色情的结论

# 分析区域 def _analyse_regions(self):  # 如果皮肤区域小于 3 个,不是色情  if len(self.skin_regions) < 3:   self.message = "Less than 3 skin regions ({_skin_regions_size})".format(    _skin_regions_size=len(self.skin_regions))   self.result = False   return self.result    # 为皮肤区域排序  self.skin_regions = sorted(self.skin_regions, key=lambda s: len(s),         reverse=True)    # 计算皮肤总像素数  total_skin = float(sum([len(skin_region) for skin_region in self.skin_regions]))    # 如果皮肤区域与整个图像的比值小于 15%,那么不是色情图片  if total_skin / self.total_pixels * 100 < 15:   self.message = "Total skin percentage lower than 15 ({:.2f})".format(total_skin / self.total_pixels * 100)   self.result = False   return self.result    # 如果最大皮肤区域小于总皮肤面积的 45%,不是色情图片  if len(self.skin_regions[0]) / total_skin * 100 < 45:   self.message = "The biggest region contains less than 45 ({:.2f})".format(len(self.skin_regions[0]) / total_skin * 100)   self.result = False   return self.result    # 皮肤区域数量超过 60个,不是色情图片  if len(self.skin_regions) > 60:   self.message = "More than 60 skin regions ({})".format(len(self.skin_regions))   self.result = False   return self.result    # 其它情况为色情图片  self.message = "Nude!!"  self.result = True  return self.result 

然后可以组织下分析得出的信息

def inspect(self):  _image = '{} {} {}×{}'.format(self.image.filename, self.image.format, self.width, self.height)  return "{_image}: result={_result} message='{_message}'".format(_image=_image, _result=self.result, _message=self.message) 

Nude 类如果就这样完成了,最后运行脚本时只能得到一些真或假的结果,我们需要更直观的感受程序的分析效果,我们可以生成一张原图的副本,不过这个副本图片中只有黑白色,白色代表皮肤区域,那么这样我们能直观感受到程序分析的效果了

前面的代码中我们有获得图像的像素的 RGB 值的操作,设置像素的 RGB 值也就是其逆操作,还是很简单的,不过注意设置像素的 RGB 值时不能在原图上操作

# 将在源文件目录生成图片文件,将皮肤区域可视化 def showSkinRegions(self):  # 未得出结果时方法返回  if self.result is None:   return  # 皮肤像素的 ID 的集合  skinIdSet = set()  # 将原图做一份拷贝  simage = self.image  # 加载数据  simageData = simage.load()    # 将皮肤像素的 id 存入 skinIdSet  for sr in self.skin_regions:   for pixel in sr:    skinIdSet.add(pixel.id)  # 将图像中的皮肤像素设为白色,其余设为黑色  for pixel in self.skin_map:   if pixel.id not in skinIdSet:    simageData[pixel.x, pixel.y] = 0, 0, 0   else:    simageData[pixel.x, pixel.y] = 255, 255, 255  # 源文件绝对路径  filePath = os.path.abspath(self.image.filename)  # 源文件所在目录  fileDirectory = os.path.dirname(filePath) + '/'  # 源文件的完整文件名  fileFullName = os.path.basename(filePath)  # 分离源文件的完整文件名得到文件名和扩展名  fileName, fileExtName = os.path.splitext(fileFullName)  # 保存图片  simage.save('{}{}_{}{}'.format(fileDirectory, fileName,'Nude' if self.result else 'Normal', fileExtName)) 

变量 skinIdSet 使用集合而不是列表是有性能上的考量的,Python 中的集合是哈希表实现的,查询效率很高

最后支持一下命令行参数就大功告成啦!我们使用 argparse 这个模块来实现命令行的支持。argparse 模块使得编写用户友好的命令行接口非常容易。程序只需定义好它要求的参数,然后 argparse 将负责如何从 sys.argv 中解析出这些参数。argparse 模块还会自动生成帮助和使用信息并且当用户赋给程序非法的参数时产生错误信息

具体使用方法请查看argparse的 官方文档,这里就不多说了

if __name__ == "__main__":  import argparse    parser = argparse.ArgumentParser(description='Detect nudity in images." title="发现个python好玩的实战项目—色情图片识别" alt="发现个python好玩的实战项目—色情图片识别"/>

发现个python好玩的实战项目—色情图片识别

一、实验简介 本实验将使用 Python3 去识别图片是否为色情图片,我们会使用到 PIL 这个图像处理库,会编写算法来划分图像的皮肤区域 1.1. 知识点 Python 3 的模块的安装 Python 3 基础知识 肤色像素检测与皮肤区域划分算法 Pillow 模块的使用 argparse 模块的使用1.2. 效果展示 二、实验步骤

数据爬虫

引言

目前智慧城市的发展,人们生活处处有科技,比如人脸识别,智慧交通,无人驾驶等前沿的科技产品也都融入了人们生活中;
智慧交通的发展也越来越成熟,车辆识别,车辆跟踪,车辆分析,行人跟踪检测与行为分析,这些都越来越成熟,但是都是建立在斑马线的基础上来实现的。

智慧斑马线,严格地说,是用于(单条或区域多条)人行横道(斑马线)上,人、车、路、环境协同的一整套软硬件产品与服务,主要通过提高斑马线标线的清晰度和醒目度,以及智能网联控制,实现智能的斑马线通行的警示、调度、控制、多点联动。

智慧斑马线首先是斑马线。斑马线是一条线,对行人来说是保护道路通行安全的生命线;对城市交通管理来说,是对人、车、路进行协同工作的一条协同线,只有人和车、路都是按规则有秩序地协同,才能达到交通文明有序。智慧斑马线就是以技术为出发点,帮助行人和城市交管做到斑马线生命线和协同线的一种智能产品和服务。

神经网络的结构

神经网络模型包含三个部分:input layer(输入层)hidden layer(中间层或隐藏层)output layer(输出层)。其中,hidden layer的层数不固定,在某些简单问题中,hidden layer的层数可能为0,仅有input layer和output layer;在复杂问题中,hidden layer的层数也可能成百上千。

模型中每一层的节点称为“神经元”。位于input layer的神经元对应着训练数据的特征。hidden layer和output layer中的神经元由activation function(激活函数)表达,我们用字母 g ​ g​ g​表示。Activation function有很多种类型,最常用是sigmoid函数,它的表达式如下:

sigmoid函数图像如下图所示。当 x > > 0 ​ x>>0​ x>>0​时, f ( x ) ​ f(x)​ f(x)​无限逼近于1;当 x < < 0 ​ x<<0​ x<<0​时, f ( x ) ​ f(x)​ f(x)​无限逼近于0;当 x = 0 ​ x=0​ x=0​时, f ( x ) = 0.5 ​ f(x)=0.5​ f(x)=0.5​。

搭建模型

一、引入基本库

环境配置:

  • Windows10系统
  • Python–3.7.3
  • tensorflow–2.3
  • OpenCV–4.5.1
import tensorflow as tf import matplotlib.pyplot as plt import cv2 as cv import pandas as pd import numpy as np import os import shutil from keras.models import Sequential, load_model from keras import optimizers from keras.preprocessing.image import ImageDataGenerator from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense 

Conv2D :卷积
MaxPooling2D: 最大池化
Flatten: 从卷积层到全连接层的过渡(卷积),扁平数据
Dense: 全连接

二、数据集准备


数据集来源:斑马线数据集
在这里我们使用Keras自带的图像生成器ImageDataGenerator,在这里下载下来的数据集并不需要我们去处理,我们只需要下载,解压就行;

ImageDataGenerator图像生成器他会根据train和test的子文件信息来给予标签;

#简单的二分类 train_dir = 'G:\\深度学习\\Zebra\\Zebra\\train" title="Python-基于卷积神经网络斑马线识别分类,准确率高达99%" alt="Python-基于卷积神经网络斑马线识别分类,准确率高达99%"/>

Python-基于卷积神经网络斑马线识别分类,准确率高达99%

引言 目前智慧城市的发展,人们生活处处有科技,比如人脸识别,智慧交通,无人驾驶等前沿的科技产品也都融入了人们生活中; 智慧交通的发展也越来越成熟,车辆识别,车辆跟踪,车辆分析,行人跟踪检测与行为分析,这些都越来越成熟,但是都是建立在斑马线的基础上来实现的。 智慧斑马线,严格地说,是用于(单条或区域多条)人行横道(斑马线)上,人、车、路、

数据爬虫为什么黑帽子从不用鼠标,一直在敲键盘?看完长见识了

为什么黑帽子从不用鼠标,一直在敲键盘?看完长见识了

由于平台限制,很多黑ke技术文章发布不了,感兴趣的同学可以关注我新创建的同名公众号:程序员启航 在各种好莱坞大片里头,但凡需要“技术小子”表现一下如何用几分钟时间黑掉一个庞大IT系统的时候,里面的电脑都是这样的:   1.文字处理软件从来不显示光标。 2.所有的屏幕都显示1英尺高的字符。 3 高技术的计算机都有简单易用的图形界面。 4.

数据爬虫Python超简单容易上手的画图工具库

Python超简单容易上手的画图工具库

今天,在网上发现一款很棒的python画图工具库。很简单的api调用就能生成漂亮的图表。并且可以进行一些互动。 pyecharts 是一个用于生成 Echarts 图表的类库。Echarts 是百度开源的一个数据可视化 JS 库。用 Echarts 生成的图可视化效果非常棒。废话不多说下来直接看效果(对于我这种没审美感的人来是我觉得挺漂亮

数据爬虫大事件,Java被超越了,2021年5月TIOBE编程语言排行榜出炉

大事件,Java被超越了,2021年5月TIOBE编程语言排行榜出炉

TIOBE 头条 TIOBE 5月编程语言排行榜新鲜出炉。前十榜单中,C、Python、Java三大鳌头仍占据前三榜单。去年11月,Python短时间的挤掉Java跃居至榜单第二名;今年5月,Python再次挤掉Java,再度夺下榜二。 TIOBE排行榜是世界上权威编程语言排行榜,注意,它只是反映某个编程语言的热门程度,并不能说明一门编程

首页 8 9 10 11 12 13 14 15 16 17 末页
点击下拉

SEO优化/竞价信息流托管/百度360搜狗推广开户/网站定制开发/建设推广流程

SEO优化/竞价信息流托管/百度360搜狗推广开户/网站定制开发/建设推广流程