Python Selenium 实现网站自动签到教程

前情提要

小五收藏了一些论坛网站,经常需要自己登录签到,以此来获得积分金币等等。

步骤倒是并不复杂,只需要填写账号密码登录,然后点击签到即可。

但天天手动太容易忘了这件事啦。毕竟我们都会用python了,那就可以使用Selenium操作;浏览器实现自动签到啊!

现在开始上手工作👉

准备工作

首先我们需要先安装Selenium,从而实现后续自动化操控浏览器。我们可以利用它来模拟鼠标按键,跟按键精灵很类似。

pip install selenium

待其安装完成后,准备另一个必需工具。

selenium可以操控多款浏览器,包括谷歌,火狐等,这里小五使用的是谷歌浏览器。

这里需要知道浏览器的版本信息,只需打开“关于Chrome”,就可以看到了。

如上图所示,我的浏览器版本是89.0.4389.114。然后我们需要前往(http://chromedriver.storage.googleapis.com/index.html)找到与浏览器相匹配的版本,没有一模一样的选择最近的版本也可以。

点击进去选择对应的系统版本,下载后将chromedriver.exe解压出来,最后将其放到与python.exe文件相同的路径下。

如果你是用的anaconda就放在下面目录下

C:\Users\Administrator\anaconda3

具体位置如下图所示👇

下面我们就可以正式用python自动签到了。

selenium 教程-代码及讲解

首先打开我要登录的网站,具体域名就不分享给大家了。

先导入selenium库,这里只需使用selenium中的webdriver模块,运行

from selenium import webdriver

打开下载的浏览器驱动,设置隐式等待时

wd=webdriver.Chrome()
wd.implicitly_wait(1)

👆执行代码的时候会自行去寻找chromedriver.exe(在python目录下寻找)。如果我们前面没有把它放在固定的路径下,就需要在这里指定chromedriver.exe路径。

打开登录网页

wd.get('待登录网站URL')

如上图所示,模拟浏览器已经打开了网站的登录界面。这个时候我们需要定位到输入框、密码框以及登录按钮等。

这里不用担心,Selenium提供了很多种定位DOM元素的方法,各有各的特点和优势。今天就主要使用 by_xpath() 这个方法来定位元素,这个方法比较灵活方便,大部分属性都可以通过它来定位。

【检查】→【进入开发者模式】点击左上角的图标,再点击你要找的对象,即可得到该对象的信息。点位该对象后,右键copy它的XPath!

input = wd.find_element_by_xpath('//*[@id="email"]')
input.send_keys('kxpython@163.com')

同理,我们可以定位到密码框,再send_keys输入密码

password = wd.find_element_by_xpath('//*[@id="password"]')
password.send_keys('kxpython')

至于需要点击的对象,可以使用click()来实现模拟点击的功能。

点击登录

button_login = wd.find_element_by_xpath('//*[@id="app"]/section/div/div/div/div[2]/form/div/div[5]/button')
button_login.click()

点击跳过弹窗

一般登录后会有个小弹窗,关闭即可。

wd.find_element_by_xpath('//*[@id="popup-ann-modal"]/div/div/div[3]/button').click()

尝试签到

try:
    wd.find_element_by_xpath('//*[@id="checkin-div"]/a').click()
except:
    print("已签到")

最后要记得关闭浏览器窗口

wd.quit()

注:close()关闭当前窗口,wd.quit()则是关闭所有窗口。

点击运行上面的全部代码,即可实现python对网站的自动签到。我们还可以将该python脚本设置为定时任务,这样就不用每天手动去签到啦!

小结

作为演示的这个网站非常简单,如果大家也想用python来自动签到的话,要根据自己的网站情况来改写脚本。

其实 Selenium 更多的用法是自动化测试、爬虫等,具体Selenium的详细用法,可以参考文档。

地址:http://selenium-python.readthedocs.org/

我们学习python时,可以尝试用来解决自己的生活问题,这样学得也更扎实,学得也更有趣味!

来源:快学Python

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Pandas 实战 — 结构化数据非等值范围查找

本文通过两个案例,三个部分介绍了如何在 pandas 结构化数据中进行高效的范围查找。

1.简单案例讲解

Pandas案例需求

有两张表,A表记录了很多款产品的三个基础字段,分别是产品ID,地区代码和重量:

B表是运费明细表,这个表结构很“业务”。每行对应着单个地区,不同档位重量,所对应的运费:

比如121地区,0-0.5kg的产品,运费是5.38元;2.01(实际应该是大于1)-3kg,运费则是5.44元。
现在,我们想要结合A表和B表,统计出A表每个产品付多少运费,应该怎么实现?
可以先自己思考一分钟!

解题思路

人海战术

任何数据需求,在人海战术面前都是弟弟。

A表一共215行,我们只需要找215个人,每个人只需要记好自己要统计那款产品的地区代码和重量字段,然后在B表中根据地区代码,找到所在地区运费标准,然后一眼扫过去,就能得到最终运费了。

两个“只需要”,问题就这样easy的解决了。

问题变成了,我还差214个人。

解构战术

通过人海战术,我们其实已经明确了解题的朴素思路:根据地区代码和重量,和B表匹配,返回运费结果。

难点在于,B表是偏透视表结构的,运费是横向分布,用Pandas就算用地区代码匹配,还是不能找到合适的运费区间。

怎么办呢?

如果我们把B表解构,变成“源数据”格式,问题就全部解决了:

转换完成后,和A表根据地区代码做一个匹配筛选,答案就自己跑出来了。
下面是动手时刻。

具体实现

先导入数据,A表(product):

B表(cost):

要想把B表变成“源数据”的格式,关键在于理解stack()堆叠操作,结合示例图比较容易搞懂:

通过stack操作,把多列变为单列多行,原本的2列数据堆成了1列,从而方便了一些场景下的匹配。要变回来也很简单,unstack即可:

在我们的具体场景中,先指定好不变的索引列,然后直接上stack:

这样,就得到了我们目标的源数据。接着,A表和B表做匹配:

值得注意的是,因为我们根据每个地方的重量区间做了堆叠,这里的匹配结果,每个产品保留了对应地区,所有重量区间的价格,离最终结果还有一步之遥。
需要把重量区间做拆分,从而和产品重量对比,找到对应的重量区间:

接着,根据重量的最低、最高区间,判断每一行的重量是否符合区间:

最后,筛选出符合区间的产品,及对应的价格等字段:

大功告成!

2.复杂一点的情况

Pandas案例需求

需求如下:

该问题最核心的解题思路是按照地区代码先将两张表关联起来,然后按照重量是否在指定的区间筛选出符合条件的记录。不同的解法实际区别也是,如何进行表关联,如何进行关联后的过滤。

上文的简化写法

简化后:

import pandas as pd

product = pd.read_excel('sample.xlsx', sheet_name='A')
cost = pd.read_excel('sample.xlsx', sheet_name='B')

fi_cost = cost.set_index(['地区代码','地区缩写']).stack().reset_index()
result = pd.merge(product, fi_cost, on='地区代码', how='left')
result.columns = ['产品ID''地区代码''重量''地区缩写''重量区间''价格']
result[['最低区间''最高区间']] = result['重量区间'].str.split('~', expand=True).astype(float)
result.query("最低区间<=`重量`<=最高区间")

顺序查找匹配

考虑到直接merge会产生笛卡尔积,多消耗N倍的内存,所以下面采用筛选连接法,执行耗时比merge连接稍微长点,但减少了内存消耗。

首先读取数据:

import pandas as pd
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all'

product = pd.read_excel('sample.xlsx', sheet_name='A')
cost = pd.read_excel('sample.xlsx', sheet_name='B')

预览数据:

product.head()
cost.head()

下面我们将价格表由”宽格式”旋转为”长格式”方便匹配:

fi_cost = cost.melt(id_vars=["地区代码""地区缩写"], var_name="重量区间", value_name='价格')
fi_cost

观察价格区间0~0.5, 0.501~1, 1.01~2, 2.01~3, 3.01~4, 4.01~5, 5.01~7, 7.01~10, 10.01~15, 15.01~100000我们完全可以只取前面的数字或只取后面的数字,理解为一个前闭后开或前开后闭的区间,我取重量区间的最大值来表示区间:

fi_cost.重量区间 = fi_cost.重量区间.str.split("~").str[1].astype("float")
fi_cost.sort_values(["地区代码""重量区间"], inplace=True, ignore_index=True)
fi_cost.head(10)

测试对第一个产品,取出对应的地区价格表:

fi_cost_g = fi_cost.groupby("地区代码")
for product_id, area_id, weight in product.values:
    print(product_id, area_id, weight)
    cost_table = fi_cost_g.get_group(area_id)
    display(cost_table)
    break

下面我们继续测试根据重量筛选出对应的价格:

fi_cost_g = fi_cost.groupby("地区代码")[["地区缩写""重量区间""价格"]]
for product_id, area_id, weight in product.values:
    print(product_id, area_id, weight)
    cost_table = fi_cost_g.get_group(area_id)
    display(cost_table)
    for area, weight_cost, price in cost_table.values:
        if weight <= weight_cost:
            print(area, price)
            break
    break

可以看到已经顺利的匹配出对应的价格是20.05。

于是完善最终代码为:

result = []
fi_cost_g = fi_cost.groupby("地区代码")[["地区缩写""重量区间""价格"]]
for product_id, area_id, weight in product.values:
    cost_table = fi_cost_g.get_group(area_id)
    for area, weight_cost, price in cost_table.values:
        if weight <= weight_cost:
            break
    result.append((product_id, area_id, area, weight, price))
result = pd.DataFrame(result, columns=["产品ID""地区代码""地区缩写""重量(kg)""价格"])
result

成功匹配出每个产品对应的地区简写和价格。

顺序查找匹配的完整代码为:

import pandas as pd

product = pd.read_excel('sample.xlsx', sheet_name='A')
cost = pd.read_excel('sample.xlsx', sheet_name='B')

fi_cost = cost.melt(id_vars=["地区代码""地区缩写"], var_name="重量区间", value_name='价格')
fi_cost.重量区间 = fi_cost.重量区间.str.split("~").str[1].astype("float")
fi_cost.sort_values(["地区代码""重量区间"], inplace=True, ignore_index=True)
result = []
fi_cost_g = fi_cost.groupby("地区代码")[["地区缩写""重量区间""价格"]]
for product_id, area_id, weight in product.values:
    cost_table = fi_cost_g.get_group(area_id)
    for area, weight_cost, price in cost_table.values:
        if weight <= weight_cost:
            break
    result.append((product_id, area_id, area, weight, price))
result = pd.DataFrame(result, columns=["产品ID""地区代码""地区缩写""重量(kg)""价格"])
result

3.优化方案

前面两部分内容就已经解决了问题,考虑到上述区间查找其实是一个顺序查找的问题,所以我们可以使用二分查找进一步优化减少查找次数。

当然二分查找对于这种2位数级别的区间个数查找优化不明显,但是当区间增加到万级别,几十万的级别时,那个查找效率一下子就体现出来了,大概就是几万次查找和几次查找的区别。

字典查找+二分查找高效匹配

本次优化,主要通过字典查询大幅度加快了查询的效率,几乎实现了将非等值连接转换为等值连接。

首先读取数据:

import pandas as pd

product = pd.read_excel('sample.xlsx', sheet_name='A')
cost = pd.read_excel('sample.xlsx', sheet_name='B')
cost.head()

下面计划将价格表直接转换为能根据地区代码和索引快速查找价格的字典。

先取出区间范围列表,用于索引位置查找:

price_range = cost.columns[2:].str.split("~").str[1].astype("float").tolist()
price_range

结果:

[0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 10.0, 15.0, 100000.0]

下面将测试二分查找的效果:

import bisect
import numpy as np

for a in np.linspace(0.5510):
    idx = bisect.bisect_left(price_range, a)
    print(a, idx)

结果:

0.5 0
1.0 1
1.5 2
2.0 2
2.5 3
3.0 3
3.5 4
4.0 4
4.5 5
5.0 5

可以打印索引列表方便对比:

print(*enumerate(price_range))

结果:

(0, 0.5) (1, 1.0) (2, 2.0) (3, 3.0) (4, 4.0) (5, 5.0) (6, 7.0) (7, 10.0) (8, 15.0) (9, 100000.0)

经过对比可以看到,二分查找可以正确的找到一个指定的重量在重量区间的索引位置。

于是我们可以构建地区代码和索引位置作联合主键快速查找价格的字典:

cost_dict = {}
for area_id, area, *prices in cost.values:
for idx, price in enumerate(prices):
        cost_dict[(area_id, idx)] = area, price

然后就可以批量查找对应的运费了:

result = []
for product_id, area_id, weight in product.values:
    idx = bisect.bisect_left(price_range, weight)
    area, price = cost_dict[(area_id, idx)]
    result.append((product_id, area_id, area, weight, price))
result = pd.DataFrame(result, columns=["产品ID""地区代码""地区缩写""重量(kg)""价格"])
result

字典查找+二分查找高效匹配的完整代码:

import pandas as pd
import bisect

product = pd.read_excel('sample.xlsx', sheet_name='A')
cost = pd.read_excel('sample.xlsx', sheet_name='B')
price_range = cost.columns[2:].str.split("~").str[1].astype("float").tolist()
cost_dict = {}
for area_id, area, *prices in cost.values:
for idx, price in enumerate(prices):
        cost_dict[(area_id, idx)] = area, price
result = []
for product_id, area_id, weight in product.values:
    idx = bisect.bisect_left(price_range, weight)
    area, price = cost_dict[(area_id, idx)]
    result.append((product_id, area_id, area, weight, price))
result = pd.DataFrame(result, columns=["产品ID""地区代码""地区缩写""重量(kg)""价格"])
result

两种算法的性能对比

可以看到即使如此小的数据量下依然存在几十倍的性能差异,将来更大的数量量时,性能差异会更大。

将非等值连接转换为等值连接

基于以上测试,我们可以将非等值连接转换为等值连接直接连接出结果,完整代码如下:

import pandas as pd
import bisect

product = pd.read_excel('sample.xlsx', sheet_name='A')
cost = pd.read_excel('sample.xlsx', sheet_name='B')
price_range = cost.columns[2:].str.split("~").str[1].astype("float").tolist()
cost.columns = ["地区代码""地区缩写"]+list(range(cost.shape[1]-2))
cost = cost.melt(id_vars=["地区代码""地区缩写"],
                       var_name='idx', value_name='运费')
product["idx"] = product["重量(kg)"].apply(
lambda weight: bisect.bisect_left(price_range, weight))
result = pd.merge(product, cost, on=['地区代码''idx'], how='left')
result.drop(columns=["idx"], inplace=True)
result

该方法的平均耗时为6ms:

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 实战教程 | 轻松实现APP自动化记账

前情回顾

不知道大家有没有手动记账的习惯,我大概从大学开始就坚持记账,中途也换过几个账本APP。目前使用的是圈子账本 ,它的记账界面如下图所示:

再说说我现在的情况,毕业之后支出越来越多越琐碎,每月的账单多到再手动记账有些过于浪费时间了。

不过有几点让我注意到了,似乎可以实现自动化记账:

一是我目前支出首选信用卡(支付宝、微信也绑定信用卡),几乎全部支出都在这里;

二是圈子账本可以通过上传模板文件来直接上传账单,现在也支持支付宝账单了;

三是我的支出类别比较单一,主要就下面几种:

折中方案

根据上面的几点,我搞了个折中的方案,并一直用到现在。

就是电脑登录信用卡官网,手动复制或者下载账单。

然后使用python调整成账本官网支持的格式,导出成excel格式,直接上传至官网。

下面给大家对比一下操作前和操作后的格式:

信用卡里的账单:

官网规定格式:

操作实战

先手动复制账单到excel里,先命名为测试数据.xlsx

然后我们开始使用python处理,导入数据

df = pd.read_excel('测试数据.xlsx',header = None)
df.head(6)

👆每隔三行其实是一条数据,所以我们要跳行提取数据

df2 = pd.DataFrame(columns=['日期','时间','入账金额','交易说明'])

df2['日期'] = df.iloc[[ i+1 for i in range(0,len(df),3)],[0]].reset_index()[0]
df2['时间'] = df.iloc[[ i+2 for i in range(0,len(df),3)],[0]].reset_index(drop=True)
df2['入账金额'] = df.iloc[[ i+1 for i in range(0,len(df),3)],[1]].reset_index(drop=True)
df2['交易说明'] = df.iloc[[ i+2 for i in range(0,len(df),3)],[1]].reset_index(drop=True)

创建了一个df2,并从df中隔行提取数据,结果如下

调整格式

下一步调整格式,先参考目标格式要求:

df2['时间'] = df2['日期'].apply(lambda x : str(x).replace('00:00:00','')) + df2['时间'].apply(lambda x : str(x)[:-3])
df2['入账金额'] = df2['入账金额'].str.lstrip('入账金额:¥')
df2['交易说明'] = df2['交易说明'].str.lstrip('交易说明:财付通公司-')
df2 = df2.drop(columns = '日期')

这样我们就调整好了时间入账金额(金额)交易说明(备注),还剩下一个关键的值就是类别,其实我自己的消费类别没几个,可以简单的利用交易说明判断类别,无法分辨的类别归为其他。

def fenlei(comment):
    if '美团' in comment or '拉扎斯'in comment:
        data = "餐饮"
    elif '花小猪'in comment or '滴滴'in comment:
        data = "交通"
    elif '燃气'in comment or '电费'in comment:
        data = "水电燃气"
    elif '拼多多'in comment:
        data = "生活用品"
    else:
        data = "其他"
    return data

利用上面的函数,就可以统计出类别这一列的值。

其中拉扎斯指的是饿了么,大家查一下自己账单就知道了。至于其他的种类,大家根据自己实际情况改改就可。

另外再添加另外两个固定列,就齐了。

df2['分类'] = df2.apply(lambda x :fenlei(x['交易说明']), axis=1)
df2 = df2[df2['入账金额'].astype(float) > 0]
df2['类型'] = '支出'
df2['账户'] = '交通银行'
df2.head()

👆这里面我还筛选了只大于0的入账金额,这是为了排除还款记录。

注:还款记录在信用卡账单里是负值

最后结果如下图所示:

导出数据

由于这次导出数据要固定格式,所以使用了openpyxl来向官网模板中直接写入,这样导入比较规范。

workbook = load_workbook(filename="朱小五.xlsx")
sheet = workbook.active
df2 = df2.iloc[:,[4,0,3,1,5,2]]
# 先删除第4行之后的旧数据,预计1000行完全够用
sheet.delete_rows(idx=2, amount=1000)
# 然后在进行添加数据
for row in df2.values.tolist():
    sheet.append(row)
    print(row)
print("已经保存到文件中")
workbook.save(filename="朱小五.xlsx")
workbook.close()

打开朱小五.xlsx,查看结果

没什么问题,将Excel导入账本官网中

完美导入
再打开手机记账APP
发现账单已经安安静静地躺在账本里啦!

本文转自快学Python.

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 实战教程 — 爬取所有LOL英雄皮肤壁纸

今天是教使用大家selenium,一键爬取LOL英雄皮肤壁纸。

第一步,先要进行网页分析

一、网页分析

进入LOL官网后,鼠标悬停在游戏资料上,等出现窗口,选择资料库,点击进入。大家可以直接打开链接👉http://lol.qq.com/data/info-heros.shtml

进入了所有英雄的页面,随便选择一个英雄进行查看

检查可以发现一个一个名为hero_list.js的文件,里面保存了所有英雄的有关信息,可以将里面的内容复制下来保存到本地txt,然后再利用Python转为json。

import json

# 读取txt里数据
with open('hreo_list.txt'as f:
    con = f.read()
# 将str转换为json
rep = json.loads(con)
# 遍历  得到每个英雄的 ID
print(f"有多少个英雄:{len(rep['hero'])}")    # 有多少个英雄:152
# https://lol.qq.com/data/info-defail.shtml?id=876
count = 0
for item in rep['hero']:
    print(f"英雄ID:{item['heroId']}")

执行过程

依次点击英雄的详情页分析

id参数的值为.js文件中heroId对应的值
通过参数构造英雄详情页的URL

黑暗之女:https://lol.qq.com/data/info-defail.shtml?id=1
狂战士:https://lol.qq.com/data/info-defail.shtml?id=2
正义巨像:https://lol.qq.com/data/info-defail.shtml?id=3
含羞蓓蕾:https://lol.qq.com/data/info-defail.shtml?id=876

一些英雄的皮肤URL是规律的,比如安妮这样:

# big + id + 001.jpg  从001.jpg开始
https://game.gtimg.cn/images/lol/act/img/skin/big1001.jpg
https://game.gtimg.cn/images/lol/act/img/skin/big1002.jpg
https://game.gtimg.cn/images/lol/act/img/skin/big1003.jpg
https://game.gtimg.cn/images/lol/act/img/skin/big1004.jpg
https://game.gtimg.cn/images/lol/act/img/skin/big1005.jpg

但有些又像派克这样,皮肤URL不规律

https://game.gtimg.cn/images/lol/act/img/skin/big555001.jpg   # 第一张
https://game.gtimg.cn/images/lol/act/img/skin/big555009.jpg   # 第二张
https://game.gtimg.cn/images/lol/act/img/skin/big555016.jpg   # 第三张00000000000000

这样的情况,构造URL来请求下载图片不方便,我们直接上 selenium 大法👇

二、selenium爬虫

爬虫大法好,走起🚀

部分爬虫代码,完整代码下载见文末👇

def create_urls():
    # 读取txt里数据
    with open('hreo_list.txt'as f:
        con = f.read()
    # 将str转换为json
    rep = json.loads(con)
    # 遍历  得到每个英雄的 ID
    print(f"有多少个英雄:{len(rep['hero'])}")
    # https://lol.qq.com/data/info-defail.shtml?id=876
    id_ = []
    for item in rep['hero']:
        # print(f"英雄ID:{item['heroId']} -- 英雄名称:{item['name']}")
        id_.append((item['heroId'],item['name']))
    return id_

运行效果如下:

预览结果

死亡如风,常伴吾身。吾虽浪迹天涯,却未迷失本心。长路漫漫,唯剑作伴。

想当初,我的亚索也是很快乐的~

本文转自快学Python.

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

表白神器!使用 Python PIL 库绘制爱心墙!

 

一、爱心墙

通过爬虫搜集到粉丝的头像,然后利用 PIL 库拼接出爱心墙的形状

二、代码分析

1.头像爬取

在个人中心点击我的粉丝便可以看到自己的粉丝

通过抓包可知对应的接口为:

url = 'https://me.csdn.net/api/relation/index?pageno=1&pagesize=20&relation_type=fans' # 接口地址

那么,可以定义一个函数来获取粉丝的信息:

def get_fansInfo():
    '''
    获取粉丝相关信息
    '''

    url = 'https://me.csdn.net/api/relation/index?pageno=%d&pagesize=%d&relation_type=fans' # 接口地址
    cookies = {} # 用户登陆cookies
    headers = {  # 请求头
        'User-Agent''Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
        'Accept''application/json, text/plain, */*',
        'Accept-Language''zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
        'Referer''https://i.csdn.net/',
        'Origin''https://i.csdn.net',
        'Connection''keep-alive',
        'TE''Trailers',
    }
    # 获取粉丝总数
    res = requests.get(url%(1,10),headers=headers,cookies=cookies)
    res_json = res.json()
    N_fans = res_json['data']['data_all']
    print('一共有%d个粉丝'%N_fans)
    # 获取全部粉丝数据
    res = requests.get(url%(1,N_fans),headers=headers,cookies=cookies)
    res_json = res.json()
    return res_json

在返回的数据中,包括一个avatar字段,这个就是用户的头像地址

拿到头像地址之后便可以定义个函数来下载相应的头像:

def download_avatar(username,url):
    '''
    下载用户头像
    '''

    savePath = './avatars' # 头像存储目录
    res = requests.get(url)
    with open('%s/%s.jpg'%(savePath,username),'wb'as f:
        f.write(res.content)

定义主函数,运行代码:

if __name__ == '__main__':
    fans = get_fansInfo()
    for f in fans['data']['list']:
        username = f['fans'# 用户名
        url = f['avatar']    # 头像地址
        download_avatar(username,url)
        print('用户"%s"头像下载完成!'%username)

最后我成功将所有头像下载到本地文件夹中:

2.头像去重

聪明的你应该已经发现,在爬取到的头像中有两个头像重复出现(想必这应该是官方默认头像):

 

 

 

于是乎,为了更好地展示,我们得对头像进行去重

这里我们利用每个头像的 MD5 值来进行去重,然后定义函数来计算头像的 MD5 值

def get_md5(filename):
    '''
    获取文件的md5值cls
    '''

    m = hashlib.md5()
    with open(filename,'rb'as f:
        for line in f:
            m.update(line)
    md5 = m.hexdigest()
    return md5

说明:每个文件通过 MD5 计算出摘要,理论来说只有文件完全一致 MD5 值才会相同。因此,可以利用它来进行图像的去重

对头像进行去重,并把去重后的头像保存到另外的目录中:

# 照片去重
md5_already = [] # 用于存储已经记录过的图片,便于去重
for filename in os.listdir('./avatars'):
    md5 = get_md5('./avatars/'+filename)  
    if md5 not in md5_already:
        md5_already.append(md5)
        shutil.copyfile('./avatars/'+filename,'./avatars(dr)/'+filename)

3.绘制爱心墙

这一步,主要是利用 PIL 库来把头像按照设定的框架拼接成一个更大的图片

首先导入相关库:

import os
import random
import numpy as np
import PIL.Image as Image

定义绘制图形的框架(用二维数组表示):

FRAME = [[0,1,1,0,0,0,0,1,1,0],
         [1,1,1,1,0,0,1,1,1,1],
         [1,1,1,1,1,1,1,1,1,1],
         [1,1,1,1,1,1,1,1,1,1],
         [0,1,1,1,1,1,1,1,1,0],
         [0,0,1,1,1,1,1,1,0,0],
         [0,0,0,1,1,1,1,0,0,0],
         [0,0,0,0,1,1,0,0,0,0]]

这里大家完全可以发挥自己的想象,画你心中所想

其中,0 表示不进行填充,1 表示用头像进行填充。

定义相关参数,包括每张用于填充的头像的大小、每个点位填充的次数等

# 定义相关参数
SIZE = 50 # 每张图片的尺寸为50*50
N = 2     # 每个点位上放置2*2张图片

# 计算相关参数
width = np.shape(FRAME)[1]*N*SIZE  # 照片墙宽度
height = np.shape(FRAME)[0]*N*SIZE # 照片墙高度
n_img = np.sum(FRAME)*(N**2)       # 照片墙需要的照片数
filenames = random.sample(os.listdir('./avatars(dr)'),n_img) # 随机选取n_img张照片
filenames = ['./avatars(dr)/'+f for f in filenames]

遍历 FRAME,用头像对背景图片进行填充:

# 绘制爱心墙
img_bg = Image.new('RGB',(width,height)) # 设置照片墙背景
i = 0
for y in range(np.shape(FRAME)[0]):
    for x in range(np.shape(FRAME)[1]):
         if FRAME[y][x] == 1# 如果需要填充
             pos_x = x*N*SIZE # 填充起始X坐标位置
             pos_y = y*N*SIZE # 填充起始Y坐标位置
             for yy in range(N):
                 for xx in range(N):
                     img = Image.open(filenames[i])
                     img = img.resize((SIZE,SIZE),Image.ANTIALIAS)
                     img_bg.paste(img,(pos_x+xx*SIZE,pos_y+yy*SIZE))
                     i += 1
                
# 保存图片
img_bg.save('love.jpg')

写在最后

天气逐渐微寒,愿这次小小的表白可以给你们带来些许暖意;愿风雨兼程,不忘归途;愿身能似月亭亭,千里伴君行!

转自AirPython.

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

漂亮的GitHub个人总览 ,原来这么容易实现

前段时间,GitHub悄悄地发布了一个新功能:Profile README.

翻译成中文即简历型README,好听一点就是个人自述型简历,简单点就是个人GitHub总览

下面给大家讲讲怎么通过 GitHub API 创建一个能够自更新的总览。

1.首先,创建一个GitHub仓库:

创建一个与你的GitHub帐户同名的存储库(在我的情况下为github.com/Ckend/Ckend

向其添加一个README.md,我写入了以下内容:

“To be continued…”

如图所示:

然后GitHub将在你的个人资料页面顶部呈现该README内容,对我来说就是github.com/Ckend

如图所示,你用户名的这个仓库的 README.md 将成为你的个人资料首页的展示内容。

2.美化你的展示内容

首先,我们可以加一个GitHub的基本统计信息

这是官方给出的统计组件API,使用起来很方便,你只需要往你的README.md里添加下述代码即可:

<img align="left" src="https://github-readme-stats.vercel.app/api?username=你的账号用户名&include_all_commits=true&count_private-true&custom_title=你的账号用户名'%20GitHub%20Stats&line_height=30&show_icons=true&hide_border=true&bg_color=192133&title_color=efb752&icon_color=efb752&text_color=70bed9">

此外GitHub官方还提供了一个展示自己最常用语言的接口。

你可以在README.md里添加下述内容展示这个图表:

<img align="right" src="https://github-readme-stats.vercel.app/api/top-langs/?username=ckend">

你还可以带一个 &layout=compact 参数展示横版图表:

<img align="right" src="https://github-readme-stats.vercel.app/api/top-langs/?username=ckend&layout=compact">

另外,​我们还可以加上技术栈图标:

利用 https://img.shields.io 提供的图标,可以轻松实现这点,在README键入以下内容即可:

### 技术栈

![Python](https://img.shields.io/badge/-Python-192133?style=flat-square&logo=python&logoColor=white)
![Django](https://img.shields.io/badge/-Django-192133?style=flat-square&logo=figma&logoColor=white)
![PHP](https://img.shields.io/badge/-PHP-192133?style=flat-square&logo=figma&logoColor=white)
![MySQL](https://img.shields.io/badge/-MySQL-192133?style=flat-square&logo=mysql&logoColor=white)
![Redis](https://img.shields.io/badge/-Redis-192133?style=flat-square&logo=redis&logoColor=white)
![Elasticsearch](https://img.shields.io/badge/-Elasticsearch-192133?style=flat-square&logo=elasticsearch&logoColor=white)
![Kafka](https://img.shields.io/badge/-Kafka-192133?style=flat-square&logo=apache-kafka&logoColor=white)

当然,你要根据自己的情况做修改。

此外,shields网站还能自定义图标,可以用于展示自己的项目:

### 项目
[![pythondict-quant](https://img.shields.io/badge/pythondict-quant-192133?style=flat-square)](https://github.com/Ckend/pythondict-quant)
[![scihub-cn](https://img.shields.io/badge/scihub-cn-192133?style=flat-square)](https://github.com/Ckend/scihub-cn)

你可以按照自己的情况选择以上任意一种组件来美化总览。

完成一个漂亮的总览,能让你更有动力去维护GitHub仓库,所以一定要动手试试。

下面给大家提供一份我的总览完整版:

<img align="left" src="https://github-readme-stats.vercel.app/api?username=Ckend&include_all_commits=true&count_private-true&custom_title=Ckend'%20GitHub%20Stats&line_height=30&show_icons=true&hide_border=true&bg_color=192133&title_color=efb752&icon_color=efb752&text_color=70bed9">

### 技术栈
​
![Python](https://img.shields.io/badge/-Python-192133?style=flat-square&logo=python&logoColor=white)
![Django](https://img.shields.io/badge/-Django-192133?style=flat-square&logo=figma&logoColor=white)
![PHP](https://img.shields.io/badge/-PHP-192133?style=flat-square&logo=figma&logoColor=white)
![MySQL](https://img.shields.io/badge/-MySQL-192133?style=flat-square&logo=mysql&logoColor=white)
![Redis](https://img.shields.io/badge/-Redis-192133?style=flat-square&logo=redis&logoColor=white)
![Elasticsearch](https://img.shields.io/badge/-Elasticsearch-192133?style=flat-square&logo=elasticsearch&logoColor=white)
![Kafka](https://img.shields.io/badge/-Kafka-192133?style=flat-square&logo=apache-kafka&logoColor=white)

### 项目
[![pythondict-quant](https://img.shields.io/badge/pythondict-quant-192133?style=flat-square)](https://github.com/Ckend/pythondict-quant)
[![scihub-cn](https://img.shields.io/badge/scihub-cn-192133?style=flat-square)](https://github.com/Ckend/scihub-cn)

大家可以参考这个方案进行修改,绘制一个属于自己的漂亮总览。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Django 展示可视化图表的几种方式对比

1. 前言

使用 Django 进行 Web 开发时,经常有需要展示图表的需求,以此来丰富网页的数据展示,常见方案包含:Highcharts、Matplotlib、Echarts、Pyecharts,其中后 2 种方案使用频率更高

本篇文章将聊聊 Django 结合 Echarts、Pyecharts 实现图表可视化的具体流程

2. Echarts

Echarts 是百度开源的一个非常优秀的可视化框架,它可以展示非常复杂的图表类型

以展示简单的柱状图为例,讲讲 Django 集成 Echarts 的流程

首先,在某个 App 的 views.py 编写视图函数

当请求方法为 POST 时,定义柱状图中的数据值,然后使用 JsonResponse 返回数据

from django.http import JsonResponse
from django.shortcuts import render


def index_view(request):
    if request.method == "POST":

        # 柱状图的数据
        datas = [52036101020]

        # 返回数据
        return JsonResponse({'bar_datas': datas})
    else:
        return render(request, 'index.html', )

在模板文件中,导入 Echarts 的依赖

PS:可以使用本地 JS 文件或 CDN 加速服务

{#导入js和echarts依赖#}
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.0.2/echarts.common.js"></script>

然后,重写 window.onload 函数,发送一个 Ajax 请求给后端,利用 Echarts 将返回结果展示到图表中去

<script>
    // 柱状图
    function show_bar(data{

        //控件
        var bar_widget = echarts.init(document.getElementById('bar_div'));

        //设置option
        option = {
            title: {
                text'简单的柱状图'
            },
            tooltip: {},
            legend: {
                data: ['销量']
            },
            xAxis: {
                type'category',
                data: ["衬衫""羊毛衫""雪纺衫""裤子""高跟鞋""袜子"]
            },
            yAxis: {
                type'value'
            },
            series: [{
                data: data,
                type'bar'
            }]
        };

        bar_widget.setOption(option)
    }

    //显示即加载调用
    window.onload = function () {
        //发送post请求,地址为index(Jquery)
        $.ajax({
            url"/",
            type"POST",
            data: {},
            successfunction (data{
                // 柱状图
                show_bar(data['bar_datas']);

                //后端返回的结果
                console.log(data)
            }
        })
    }
</script>

最后,编写路由 URL,运行项目

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('',include('index.urls')),
    path('admin/', admin.site.urls),
]

发现,首页展示了一个简单的柱状图

更多复杂的图表展示可以参考官方

https://echarts.apache.org/examples/zh/index.html

3. Pyecharts

Pyecharts 是一款使用 Python 对 Echarts 进行再次封装后的开源框架

相比 Echarts,Django 集成 Pyecharts 更快捷、方便

Django 集成 Pyecharts 只需要 4 步

3-1  安装依赖

# 安装依赖
pip(3) install pyecharts

3-2  拷贝 pyecharts 的模板文件到项目下

将虚拟环境中 pyecharts 的模板文件拷贝到项目的模板文件夹下

比如本机路径如下:

/Users/xingag/Envs/xh_log/lib/python3.7/site-packages/pyecharts/render/templates/

3-3  编写视图函数,渲染图表

在视图文件中,使用 pyecharts 库内置的类 Bar 创建一个柱状图

# Create your views here.
from django.http import HttpResponse
from jinja2 import Environment, FileSystemLoader
from pyecharts.globals import CurrentConfig

CurrentConfig.GLOBAL_ENV = Environment(loader=FileSystemLoader("./index/templates"))

from pyecharts import options as opts
from pyecharts.charts import Bar


# http://127.0.0.1:8000/demo/
def index(request):
    c = (
        Bar()
            .add_xaxis(["衬衫""羊毛衫""雪纺衫""裤子""高跟鞋""袜子"])
            .add_yaxis("商家A", [52036107590])
            .add_yaxis("商家B", [15251655488])
            .set_global_opts(title_opts=opts.TitleOpts(title="Bar-基本示例", subtitle="我是副标题"))
    )
    return HttpResponse(c.render_embed())

3-4  运行项目

运行项目,生成的柱状图如下:

这只是最简单的使用实例,更多复杂的图表及前后端分离、更新的例子

可以参考官网:

https://pyecharts.org/#/zh-cn/web_django?id=django-%e5%89%8d%e5%90%8e%e7%ab%af%e5%88%86%e7%a6%bb

4. 最后

文中介绍了 Django 快速集成 Echarts 和 Pyecharts 的基本步骤

实际项目中,一些复杂的图表、前后端分离数据更新可以参考官网去拓展

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Jrnl — Python编写的超方便命令行笔记程序

Jrnl 是用Python编写的命令行笔记应用程序,用起来非常简单方便,特别适合需要快速记录文本信息的同学。

您可以使用它轻松创建,搜索和查看所有的笔记。笔记以人类可读的纯文本存储,当然也可以使用 AES加密进行加密

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install jrnl

2.快速上手

要创建一个新的笔记,你只需要在终端这样输入:

jrnl now: 第一次使用. 我擦,这玩意儿真的好用吗?                                              

jrnl 是笔记开始的标志。now: 的标记会记录一个当前时间的时间戳,后接的第一句话到句号(.)为止是笔记的标题。句号后续的所有内容都是该笔记的内容。

第一次使用的时候,会让你指定笔记记录的位置和是否需要加密:

Path to your journal file (leave blank for C:\Users\83493\.local\share\jrnl\journal.txt):
Do you want to encrypt your journal? You can always change this later [y/N] n

一般默认即可,除非你需要做特殊的处理。

如果要查看刚刚编写的记录,可以这样查看到今日为止的所有笔记:

jrnl -to today

结果如下:

或者:

jrnl -n 1

-n 后接的是数字,能够查看最近n条笔记,比如最近一条笔记:

不错,要记点简单的东西的时候甚至不需要开文档编辑器,直接终端用jrnl记录即可。

下面是更多功能的说明。

3.基本使用

如果你在输入 jrnl 命令时后面不接时间,jrnl 会默认使用当前时间插入到笔记中。

不过有时候我们想记的笔记或者日记是多日之前甚至是几个月之前的,这时候jrnl也提供了许多强大的时间格式:

3.1 笔记的时间

jrnl 支持的时间格式如下:

  • at 6am
  • yesterday
  • last monday
  • sunday at noon
  • 2 march 2012
  • 7 apr
  • 5/20/1998 at 23:42
  • 2020-05-22T15:55-04:00

比如:

jrnl 2021-02-01: 2月初. 2月的第一天,祝大家2月万事如意,快快乐乐。

然后查看到今日为止的所有笔记如下:

PS G:\push> jrnl -to today
2021-02-01 09:00 Called in sick.
| Used the time to clean and spent 4h on writing my book.

2021-02-01 09:00 2月初. 
| 2月的第一天,祝大家2月万事如意,快快乐乐。

2021-02-02 00:21 第一次使用.
| 我擦,这玩意儿真的好用吗?

当然,不使用冒号也是可以记笔记的:

PS G:\push> jrnl 不用冒号也能记笔记吗?
[Entry added to default journal]

3.2 标签功能

jrnl 支持标签功能。默认标记符号为@(不用#号是因为它是保留字符)。

要使用标签,请在所需标记的文字前面加上@符号:

jrnl Had a wonderful day at the @beach with @Tom and @Anna.

尽管可以在标记条目时使用大写字母,但按标记搜索时不区分大小写。

条目中可以使用多个标签没有限制。

3.3 重点笔记

要将笔记标记为重点项,只需使用星号(*)对它进行“星标” :

jrnl last sunday *: Best day of my life.

如果你不想添加日期,则以下选项是等效的(确保*号后面没有空格):

jrnl *: Best day of my life.
jrnl *Best day of my life.
jrnl Best day of my life.*

3.4 查看和搜索

要查看到今天为止的所有条目,请输入:

jrnl -to today

jrnl提供了几个过滤命令,以单破折号(-)开头,可让您更方便地进行查找。例如 -n:

jrnl -n 10

列出最近的十个条目。更简洁的写法是 jrnl -10,这两者效果一致。

如果要查看从去年年初到今年三月底之前编写的所有条目,请输入

jrnl -from "last year" -to march

使用多个单词的过滤条件需要使用引号("")括起来。

要查看特定日期的条目,请使用-on

jrnl -on yesterday

-contains 命令显示包含该关键词的所有笔记,–edit 允许你编辑这些笔记。

jrnl -contains "dogs" --edit

不过编辑笔记之前,jrnl会提示你配置一个默认的编辑器(因为编辑功能需要打开编辑器):

按标签过滤

您可以按标签过滤笔记。例如:

jrnl @pinkie @WorldDomination

显示@pinkie@WorldDomination 的所有笔记。标签过滤器可以与其他过滤器结合使用:

jrnl -n 5 @pinkie -and @WorldDomination

显示包含  @pinkie 和 @worldDomination 的最近五个笔记。

要查看笔记中所有的标签,请输入:

jrnl --tags

查看所有重点笔记:

jrnl -starred

3.5 删除笔记

删除笔记非常简单,相当于搜索后加 –delete 参数进行删除。

PS G:\push> jrnl -contains "2月" --delete
Delete entry '2021-02-01 09:00 2月初.2月的第一天,祝大家2月万事如意,快快乐乐。'? [y/N] y

基本的使用就是这些,jrnl 还有一些高级用法,大家可以在官网参考使用:
https://jrnl.sh/en/stable/advanced/

综上所述,如果你有快速记录文本信息的需求,这个工具是你的不二之选。​

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

​ Python 教程 — 优化机制之常量折叠

每种编程语言为了表现出色,并且实现卓越的性能,都需要大量编译器级的优化

一种著名的优化技术是 “常量折叠”(Constant Folding),即:在编译期间,编译器会设法识别出常量表达式,对其进行求值,然后用求值的结果来替换表达式,从而使得运行时更精简

我们深入探讨了什么是常量折叠,了解了它在 Python 世界中的适用范围,最后解读了 Python 的源代码(即:CPython),并分析出 Python 是如何优雅地实现它

常量折叠

所谓常量折叠,指的是在编译时就查找并计算常量表达式,而不是在运行时再对其进行计算,从而会使运行时更加精简和快速

>>> day_sec = 24 * 60 * 60

当编译器遇到一个常量表达式时,如上所述,它将对表达式求值,并作替换

通常而言,表达式会被 “抽象语法树”( Abstract Syntax Tree,简写为 AST )中的计算值所替换,但是这完全取决于语言的实现

因此,上述表达式可以等效地被执行为:

>>> day_sec = 86400

Python 中的常量折叠

在 Python 中,我们可以使用反汇编模块(Disassembler)获取 CPython 字节码,从而更好地了解代码执行的过程

当使用dis模块反汇编上述常量表达式时,我们会得到以下字节码:

>>> import dis
>>> dis.dis("day_sec = 24 * 60 * 60")

        0 LOAD_CONST               0 (86400)
        2 STORE_NAME               0 (day_sec)
        4 LOAD_CONST               1 (None)
        6 RETURN_VALUE

从字节码中可以看出,它只有一个LOAD_CONST ,以及一个已经计算好的值86400

这表明 CPython 解释器在解析和构建抽象语法树期间,会折叠常量表达式 24 * 60 * 60,并将其替换为计算值 86400

常量折叠的适应范围

Python 会尝试折叠每一个常量表达式,但在某些情况下,即使该表达式是常量,但是 Python 并不会对其进行折叠

例如,Python 不会折叠x = 4 ** 64,但会折叠 x = 2 ** 64

除了算术表达式,Python 还会折叠涉及字符串和元组的表达式,其中,长度不超过 4096 的字符串常量表达式会被折叠

>>> a = "-" * 4096   # folded
>>> a = "-" * 4097   # not folded
>>> a = "--" * 4096  # not folded

常量折叠的内部细节

现在,我们将重点转移到内部的实现细节,即关注 CPython 在哪里以及如何实现常量折叠。

所有的 AST 优化(包括常量折叠)都可以在 ast_opt.c 文件中找到

基本的开始函数是 astfold_expr,它会折叠 Python 源码中包含的所有表达式

这个函数以递归方式遍历 AST,并试着折叠每个常量表达式,如下面的代码片段所示:

astfold_expr 在折叠某个表达式之前,会尝试折叠其子表达式(操作对象),然后将折叠操作代理给特定的表达式折叠函数

特定操作的折叠函数对表达式求值,并返回计算后的常数,然后将其放入 AST 中

例如,每当 astfold_expr 遇到二值运算时,它便调用 fold_binop,递归地计算两个子操作对象(表达式) 

fold_binop 函数返回计算后的常量值,如下面的代码片段所示:

fold_binop 函数通过检查当前运算符的种类,然后调用其相应的处理函数来折叠二值运算

例如,如果当前的操作是加法运算,为了计算最终值,它会对其左侧和右侧操作数调用 PyNumber_Add

怎样优雅?

为了有效地折叠某些模式或类型的常量表达式,CPython 不会写特殊的逻辑,而是调用相同的通用代码

例如,在折叠时,它会调用通用的 PyNumber_Add 函数,跟执行常规的加法操作一样

因此,CPython 通过确保其通用代码/计算过程可以处理常量表达式的求值,从而消除了编写特殊函数来处理常量折叠的需要。

转自AirPython.

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Easyocr — 3行代码识别图片中的任意语言文字

今天给大家介绍一个超级简单且强大的OCR文本识别工具:easyocr.

这个模块支持70多种语言的即用型OCR,包括中文,日文,韩文和泰文等。

下面是使用这个模块的实战教程。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install easyocr

它会安装除了模型文件之外的所有依赖,模型文件则会在运行代码的时候下载。

对于Windows,如果在安装Torch或Torchvision时报错了,请先按照https://pytorch.org的官方说明安装Torch和Torchvision 。

在pytorch网站上,请确保选择正确的CUDA版本。如果仅打算在CPU模式下运行,请选择CUDA = None。

2.实战教程

这个模块用起来真的非常简单,三行代码完事了:

import easyocr
reader = easyocr.Reader(['ch_sim','en'])
result = reader.readtext('test.png')

运行的过程中会安装所需要的模型文件,像下面这样:

不过它的下载速度非常慢,而且经常会失败,因此这里给出第二个解决方案:先下载好模型文件,再将其放置到所需要的位置:

如果下载速度太慢,请在Python实用宝典公众号后台回复:easyocr, 下载我上传到微云网盘的文字检测模型(CRAFT)和中文简体模型文件包。

下载完模型后,将文件放到下面这个位置。

Windows:C:\Users\用户名.EasyOCR\model
Linux:~/ .EasyOCR / model

重新执行脚本不会再提醒下载模型了:

import easyocr
reader = easyocr.Reader(['ch_sim'])
result = reader.readtext('test.png')
print(result)

我随便截了一个直播弹幕的图片保存在脚本所在的文件夹下,命名为test.png:

结果如下:

基本上所有应该识别的文字都识别出来了,效果非常不错。

另外也可以看到,输出采用列表格式,每个item分别表示对应文字的边界框,识别文本结果和置信度。

这个模块还能识别多语种的情况:

我将这张图片命名为test2.jpg,修改代码中对应的图片名称:

import easyocr
reader = easyocr.Reader(['ch_sim','en'])
result = reader.readtext('test2.jpg')
print(result)

效果如下:

这张图片很复杂,而且是中英文混杂在一起的情况,但是可以看到模型除了左上角的水印,图片中的文字基本都是识别出来了,尽管有部分文字识别错误,但还在可以接受的范围之内。

不过需要注意的是,虽然可以一次性识别许多种语言,但并非所有语言都可以一起用,通常是公共语言和一个特殊语种可以一起识别,相互兼容,比如英语和日语。

如果你的电脑没有GPU或者显存不足,可以加一个gpu=false的参数仅使用CPU运行:

reader = easyocr.Reader(['ch_sim','en'], gpu = False)

另外,这个模块还支持直接使用命令行运行,相当方便,大家可以试一试:

easyocr -l ch_sim en -f test.png --detail=1 --gpu=True

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

有趣好用的Python教程

退出移动版
微信支付
请使用 微信 扫码支付