python 字符编码

python 字符编码

1.Python Unicode字符串
字符串还有一个编码问题。
由于计算机只能处理数字,若是要处理文本,就必须先把文本转换为数字才能处理。*先的计算机在设计时采用8个比特(bit)做为一个字节(byte),因此,一个字节能表示的*大的整数就是255(二进制11111111=十进制255),0 – 255被用来表示大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,好比大写字母 A 的编码是65,小写字母 z 的编码是122。
若是要表示中文,显然一个字节是不够的,至少须要两个字节,并且还不能和ASCII编码冲突,因此,中国制定了GB2312编码,用来把中文编进去。
相似的,日文和韩文等其余语言也有这个问题。为了统一全部文字的编码,Unicode应运而生。Unicode把全部语言都统一到一套编码里,这样就不会再有乱码问题了。
Unicode一般用两个字节表示一个字符,原有的英文编码从单字节变成双字节,只须要把高字节所有填为0就能够。
由于Python的诞生比Unicode标准发布的时间还要早,因此*先的Python只支持ASCII编码,普通的字符串’ABC’在Python内部都是ASCII编码的。
Python在后来添加了对Unicode的支持,以Unicode表示的字符串用u’…’表示,好比:
print u’中文’
中文
注意: 不加 u ,中文就不能正常显示。
Unicode字符串除了多了一个 u 以外,与普通字符串没啥区别,转义字符和多行表示法仍然有效:
转义:
u’中文\n日文\n韩文’
多行:
u”’*行
第二行”’
raw+多行:
ur”’Python的Unicode字符串支持”中文”,
“日文”,
“韩文”等多种语言”’
若是中文字符串在Python环境下遇到 UnicodeDecodeError,这是由于.py文件保存的格式有问题。能够在*行添加注释
# -*- coding: utf-8 -*-
目的是告诉Python解释器,用UTF-8编码读取源代码。而后用Notepad++ 另存为… 并选择UTF-8格式保存。

2.解析unicode编码的字符串
使用python抓取页面或者web端的json时候很容易抓到一些unicode编码的字符串流。在python里边对Unicode编码的处理成了一件头疼的事。

对于string里边不含”引号的处理比较简单,使用eval注明引入str是unicode编码:

str1 = eval(“u”+”\””+str + “\””)

str1.decode(‘utf8’)
对于包含引号的明文,须要先把引号转化为 \”,而后能够进行eval函数处理。 web

str=str.replace(“\\\””,”\\\\\””) #先转化字符串中的\”
str=str.replace(“\””,”\\\””) #再转化 ”

print eval(“u”+”\””+str+”\””)
对于json格式unicode的有个很奇怪的处理:

python 的json 库在使用 json.loads()函数时候会默认把输入中unicode编码解析好,而不是保留原输入。 函数

代码: 编码

str1=”{\”html\”:\”\u003c\u003e\”}”
s=json.loads(str1)
print s[“html”]
输出:<>
输出<>而不是 \u003c 这也引出了一个问题:python的json库解析json不彻底保留原格式,使用时候要注意。

若是想要json解析保持unicode编码比较麻烦,需要将unicode码的\改成\\,转译代码以下:

str=”{\”html\”:\”\u003c\”}”
s=str.replace(“\\u”,”\\\\u”)
s2=json.loads(s)
print s2[“html”]
输出: \u003c
3.str字符串和unicode字符串
字符编码
咱们在编辑器中输入的文字,对用户来讲是可读的。可是机器只能读懂01串,那怎么把咱们方便阅读的符号转换成机器能读懂的01串呢?程序员

这就需要给出符号-二进制之间的映射关系,并且必须是一一映射:即给定一个符号,机器有并且有惟一的二进制对应。根据字符获得二进制表示是编码过程(encode);根据二进制表示获得字符是解码过程(decode)。web

ASCII字符集与字符编码
刚开始的时候,给出了ASCII标准,用一个8bits字节来表示字符。并且这个字节实际上只用了7位,*高位是不用的,这样总共能表示128个字符。意味着ASCII字符集只有128个。数据库

随着计算机的普及,愈来愈多的国家开始使用计算机。128个字符难以知足各个国家的语言需求,这促使包含更多字符的字符集诞生,而且须要采用新的编码方案。网络

Latin-1
充分利用8bits字节的高位,扩展到256个字符。编辑器

Unicode字符集与字符编码
Unicode字符集包含了全部种语言的全部字符。一般用U+后接4位的16进制数字表示一个Unicode字符,好比U+FFFF。svg

UTF-8编码
UTF-8是针对Unicode字符集的一种编码方案。编码

用变长字节来表示字符:有的字符用一个字节表示(好比ASCII中规定的字符),有的字符用2个字节表示。*大长度为4字节。spa

%title插图%num

上面这张图是从Wikipedia中截取的。Number of Bytes列表示字节数;Bits for code point列表示多少个bit位是真正有用的;First code point列表示该字节数能表示的*个Unicode字符;Last code point列表示对应字节数能表示的*后一个Unicode字符;Byte i(i=1,2,3,4)列表示第i字节上的bit值。
以第二行为例,这一行的编码需要两个字节,其中真正有用的bit位只有11个,另5位是占位符,能表示从U+0080~U+07FF的Unicode字符。code

至于具体的编码方式,咱们以欧元符号€为例。€在Unicode字符集中对应U+20AC:

U+20AC位于U+0800~U+FFFF之间,因此须要三个字节来表示;
十六进制20AC能够写成二进制:0010 0000 1010 1100;
前4个bit放在*字节的低4位:11100010;
中间6个bit放在第二字节的低6位:10000010;
后6个bit放在第三字节的低6位:10101100;
因而€的UTF-8编码为:11100010 10000010 10101100。
Unicode字符集还有其余的编码方式,这里就介绍到这里。

要记住:全部的编码方式都是向后兼容ASCII的。ASCII字符对应什么二进制,那么在其余编码方式中也对应一样的二进制。

3.Python的字符串类型
Python包含两种字符串类型:str(其实就是二进制)和unicode。当只会用到ASCII字符集时,一切相安无事。一旦出现其余字符集,问题也就接踵而来。因此下面咱们着重介绍非ASCII字符串。

str类型
咱们平时写的用引号括起来的字符串都是str类型的。
<span style=”color:#000000″>>>> x = <span style=”color:#219161″><span style=”color:#219161″>’哈哈'</span></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>’\xb9\xfe\xb9\xfe'</span></span></span>
根据上面的打印结果,能够知道str类型的x存的实际上是二进制序列,而非字符串。为何会出现这种状况呢?咱们赋给x的明明是字符串。

其实很简单,x通过了一次隐形的编码过程encode()。应该采用的是系统默认编码方案。
– unicode类型
若是在引号的前面加上字符u,那么咱们就获得一个unicode字符串:

<span style=”color:#000000″>>>> x = <span style=”color:#219161″><span style=”color:#219161″>u’哈哈'</span></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>u’\u54c8\u54c8′</span></span></span>
unicode对象保存的是字符串自己,而非二进制序列。好比程序中的unicode字符串中包含两个U+54c8字符。

unicode编码为str
可是有的时候,咱们须要二进制序列,好比将数据写入文件、发送到网络或者写入数据库中时。若是不进行任何处理,会出现错误:

<span style=”color:#000000″>>>> x = <span style=”color:#219161″><span style=”color:#219161″>u’哈哈'</span></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>u’\u54c8\u54c8′</span></span>
>>> f = open(<span style=”color:#219161″><span style=”color:#219161″>’test.txt'</span></span>, <span style=”color:#219161″><span style=”color:#219161″>’w'</span></span>);
>>> f.write(x)
Traceback (most recent call last):
File <span style=”color:#219161″><span style=”color:#219161″>”<stdin>”</span></span>, line <span style=”color:#40a070″><span style=”color:#40a070″>1</span></span>, <span style=”color:#954121″><span style=”color:#954121″>in</span></span> <module>
UnicodeEncodeError: <span style=”color:#219161″><span style=”color:#219161″>’ascii'</span></span> codec can<span style=”color:#219161″><span style=”color:#219161″>’t encode characters in position 0-1: ordinal not in range(128)</span></span></span>
这是由于在把字符串写入文件时,会首先检查字符串的类型,若是是str类型的字符串,那么一切OK;若是是unicode类型的字符串,那么会隐式地对其编码,即x.encode()。而系统默认的编码方案是ASCII(能够经过sys.getdefaultencoding()查看),对非ASCII字符进行编码的时候,确定会出现错误。

为了不错误,在写入文件以前,应该用utf-8或者gbk编码方案对unicode字符串编码:

<span style=”color:#000000″>>>> x = <span style=”color:#219161″><span style=”color:#219161″>u’哈哈'</span></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>u’\u54c8\u54c8′</span></span>
>>> f = open(<span style=”color:#219161″><span style=”color:#219161″>’test.txt'</span></span>, <span style=”color:#219161″><span style=”color:#219161″>’w'</span></span>);
>>> x = x.encode(<span style=”color:#219161″><span style=”color:#219161″>’utf-8′</span></span>) <span style=”color:#408080″><em><span style=”color:#408080″><em>#unicode -> str</em></span></em></span>
>>>x
<span style=”color:#219161″><span style=”color:#219161″>’\xe5\x93\x88\xe5\x93\x88′</span></span>
>>> f.write(x)</span>
str解码为unicode
当从文本中读取数据时,读到的是str字符串,并且咱们已经知道,它保存的是二进制序列。若是其中包含非ASCII文本,咱们应该怎么恢复呢?这时候就要用到解码decode()。

<span style=”color:#000000″>>>> f = open(<span style=”color:#219161″><span style=”color:#219161″>’test.txt'</span></span>, <span style=”color:#219161″><span style=”color:#219161″>’w'</span></span>);
>>> x = f.read()
>>> x
<span style=”color:#219161″><span style=”color:#219161″>’\xe5\x93\x88\xe5\x93\x88′</span></span>
>>> x = x.decode(<span style=”color:#219161″><span style=”color:#219161″>’utf-8′</span></span>) <span style=”color:#408080″><em><span style=”color:#408080″><em>#str -> unicode</em></span></em></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>u’\u54c8\u54c8′</span></span></span>
必定要记得,用什么方式编码的就必须用什么方式解码。否则的话,从二进制到字符的对应过程会出现UnicodeDecodeError。

print语句
print语句的参数须要是str类型,并且在执行的时候会用系统的编码方式对str进行隐式解码。

两个遗留问题
#-*-coding:utf-8 -*-
如今暂且认为若是脚本中包含中文,那么必须加上这个声明。

setdefaultencoding() 这个方法貌似如今不能够用了。我以为这个设置与encode()、decode()在不指明参数的状况下的默认参数有关。

python删除相似度高的图片

python删除相似度高的图片

1.参考博客:
python—–删除同一文件夹下相似的图片
Python-列表删除重复元素/图像相似度判断及删除相似图像
python 图像相似 phash和compare_ssim比较
利用Python轻松实现图片相似度对比(一)
利用Python轻松实现图片相似度对比(二)
因为输入是视频,切完帧之后都是连续图片,所以主要参考*篇博客的*种方法。我的目录结构如下:

%title插图%num

其中frame_output是视频切帧后的保存路径,1和2文件夹分别对应两个是视频切帧后的图片。

2.切帧的代码如下:
#encoding:utf-8
import os
import sys
import cv2

video_path = ‘/home/pythonfile/video/’ # *对路径,video下有两段视频
out_frame_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), ‘frame_output’) #frame_output是视频切帧后的保存路径
if not os.path.exists(out_frame_path):
os.makedirs(out_frame_path)
print(‘out_frame_path’, out_frame_path)
files = []
list1 = os.listdir(video_path)
print(‘list’, list1)
for i in range(len(list1)):
item = os.path.join(video_path, list1[i])
files.append(item)
print(‘files’,files)
for k,file in enumerate(files):
frame_dir = os.path.join(out_frame_path, ‘%d’%(k+1))
if not os.path.exists(frame_dir):
os.makedirs(frame_dir)
cap = cv2.VideoCapture(file)
j = 0
print(‘start prossing NO.%d video’ % (k + 1))
while True:
ret, frame = cap.read()
j += 1
if ret:
#每三帧保存一张
if j % 3 == 0:
cv2.imwrite(os.path.join(frame_dir, ‘%d.jpg’%j), frame)
else:
cap.release()
break
print(‘prossed NO.%d video’%(k+1))

3.删除相似度高的图片
根据我的文件结构参考*篇博客的*种方法修改后的代码如下:

# coding: utf-8
import os
import cv2
# from skimage.measure import compare_ssim
# from skimage.metrics import _structural_similarity
from skimage.metrics import structural_similarity as ssim

def delete(filename1):
os.remove(filename1)

def list_all_files(root):
files = []
list = os.listdir(root)
# os.listdir()方法:返回指定文件夹包含的文件或子文件夹名字的列表。该列表顺序以字母排序
for i in range(len(list)):
element = os.path.join(root, list[i])
# 需要先使用python路径拼接os.path.join()函数,将os.listdir()返回的名称拼接成文件或目录的*对路径再传入os.path.isdir()和os.path.isfile().
if os.path.isdir(element): # os.path.isdir()用于判断某一对象(需提供*对路径)是否为目录
# temp_dir = os.path.split(element)[-1]
# os.path.split分割文件名与路径,分割为data_dir和此路径下的文件名,[-1]表示只取data_dir下的文件名
files.append(list_all_files(element))

elif os.path.isfile(element):
files.append(element)
# print(‘2’,files)
return files

def ssim_compare(img_files):
count = 0
for currIndex, filename in enumerate(img_files):
if not os.path.exists(img_files[currIndex]):
print(‘not exist’, img_files[currIndex])
break
img = cv2.imread(img_files[currIndex])
img1 = cv2.imread(img_files[currIndex + 1])
#进行结构性相似度判断
# ssim_value = _structural_similarity.structural_similarity(img,img1,multichannel=True)
ssim_value = ssim(img,img1,multichannel=True)
if ssim_value > 0.9:
#基数
count += 1
imgs_n.append(img_files[currIndex + 1])
print(‘big_ssim:’,img_files[currIndex], img_files[currIndex + 1], ssim_value)
# 避免数组越界
if currIndex+1 >= len(img_files)-1:
break
return count

if __name__ == ‘__main__’:
path = ‘/home/dj/pythonfile/frame_output/’

img_path = path
imgs_n = []

all_files = list_all_files(path) #返回包含完整路径的所有图片名的列表
print(‘1’,len(all_files))

for files in all_files:
# 根据文件名排序,x.rfind(‘/’)是从右边寻找*个‘/’出现的位置,也就是*后出现的位置
# 注意sort和sorted的区别,sort作用于原列表,sorted生成新的列表,且sorted可以作用于所有可迭代对象
files.sort(key = lambda x: int(x[x.rfind(‘/’)+1:-4]))#路径中包含“/”
# print(files)
img_files = []
for img in files:
if img.endswith(‘.jpg’):
# 将所有图片名都放入列表中
img_files.append(img)
count = ssim_compare(img_files)
print(img[:img.rfind(‘/’)],”路径下删除的图片数量为:”,count)
for image in imgs_n:
delete(image)

4.关于导入skimage.measure import compare_ssim出错的解决方法:
from skimage.measure import compare_ssim as sk_cpt_ssim error,从skimage导入compare_ssim出错。

from skimage.measure import compare_ssim
1
改为

from skimage.metrics import _structural_similarity
1
参考官网:https://scikit-image.org/docs/stable/auto_examples/transform/plot_ssim.html#sphx-glr-auto-examples-transform-plot-ssim-py

SSIM(structural similarity)算法原理

5.查看python安装路径及依赖包路径
ubuntu查看python及安装包的位置

6.*后贴上_structural_similarity.py的源码,以后学习
from warnings import warn
import numpy as np
from scipy.ndimage import uniform_filter, gaussian_filter

from ..util.dtype import dtype_range
from ..util.arraycrop import crop
from .._shared.utils import warn, check_shape_equality

__all__ = [‘structural_similarity’]

def structural_similarity(im1, im2,
*,
win_size=None, gradient=False, data_range=None,
multichannel=False, gaussian_weights=False,
full=False, **kwargs):
“””
Compute the mean structural similarity index between two images.

Parameters
———-
im1, im2 : ndarray
Images. Any dimensionality with same shape.
win_size : int or None, optional
The side-length of the sliding window used in comparison. Must be an
odd value. If `gaussian_weights` is True, this is ignored and the
window size will depend on `sigma`.
gradient : bool, optional
If True, also return the gradient with respect to im2.
data_range : float, optional
The data range of the input image (distance between minimum and
maximum possible values). By default, this is estimated from the image
data-type.
multichannel : bool, optional
If True, treat the last dimension of the array as channels. Similarity
calculations are done independently for each channel then averaged.
gaussian_weights : bool, optional
If True, each patch has its mean and variance spatially weighted by a
normalized Gaussian kernel of width sigma=1.5.
full : bool, optional
If True, also return the full structural similarity image.

Other Parameters
—————-
use_sample_covariance : bool
If True, normalize covariances by N-1 rather than, N where N is the
number of pixels within the sliding window.
K1 : float
Algorithm parameter, K1 (small constant, see [1]_).
K2 : float
Algorithm parameter, K2 (small constant, see [1]_).
sigma : float
Standard deviation for the Gaussian when `gaussian_weights` is True.

Returns
——-
mssim : float
The mean structural similarity index over the image.
grad : ndarray
The gradient of the structural similarity between im1 and im2 [2]_.
This is only returned if `gradient` is set to True.
S : ndarray
The full SSIM image. This is only returned if `full` is set to True.

Notes
—–
To match the implementation of Wang et. al. [1]_, set `gaussian_weights`
to True, `sigma` to 1.5, and `use_sample_covariance` to False.

.. versionchanged:: 0.16
This function was renamed from “skimage.measure.compare_ssim“ to
“skimage.metrics.structural_similarity“.

References
———-
.. [1] Wang, Z., Bovik, A. C., Sheikh, H. R., & Simoncelli, E. P.
(2004). Image quality assessment: From error visibility to
structural similarity. IEEE Transactions on Image Processing,
13, 600-612.
https://ece.uwaterloo.ca/~z70wang/publications/ssim.pdf,
:DOI:`10.1109/TIP.2003.819861`

.. [2] Avanaki, A. N. (2009). Exact global histogram specification
optimized for structural similarity. Optical Review, 16, 613-621.
:arxiv:`0901.0065`
:DOI:`10.1007/s10043-009-0119-z`

“””
check_shape_equality(im1, im2)

if multichannel:
# loop over channels
args = dict(win_size=win_size,
gradient=gradient,
data_range=data_range,
multichannel=False,
gaussian_weights=gaussian_weights,
full=full)
args.update(kwargs)
nch = im1.shape[-1]
mssim = np.empty(nch)
if gradient:
G = np.empty(im1.shape)
if full:
S = np.empty(im1.shape)
for ch in range(nch):
ch_result = structural_similarity(im1[…, ch],
im2[…, ch], **args)
if gradient and full:
mssim[…, ch], G[…, ch], S[…, ch] = ch_result
elif gradient:
mssim[…, ch], G[…, ch] = ch_result
elif full:
mssim[…, ch], S[…, ch] = ch_result
else:
mssim[…, ch] = ch_result
mssim = mssim.mean()
if gradient and full:
return mssim, G, S
elif gradient:
return mssim, G
elif full:
return mssim, S
else:
return mssim

K1 = kwargs.pop(‘K1’, 0.01)
K2 = kwargs.pop(‘K2’, 0.03)
sigma = kwargs.pop(‘sigma’, 1.5)
if K1 < 0:
raise ValueError(“K1 must be positive”)
if K2 < 0:
raise ValueError(“K2 must be positive”)
if sigma < 0:
raise ValueError(“sigma must be positive”)
use_sample_covariance = kwargs.pop(‘use_sample_covariance’, True)

if gaussian_weights:
# Set to give an 11-tap filter with the default sigma of 1.5 to match
# Wang et. al. 2004.
truncate = 3.5

if win_size is None:
if gaussian_weights:
# set win_size used by crop to match the filter size
r = int(truncate * sigma + 0.5) # radius as in ndimage
win_size = 2 * r + 1
else:
win_size = 7 # backwards compatibility

if np.any((np.asarray(im1.shape) – win_size) < 0):
raise ValueError(
“win_size exceeds image extent. If the input is a multichannel ”
“(color) image, set multichannel=True.”)

if not (win_size % 2 == 1):
raise ValueError(‘Window size must be odd.’)

if data_range is None:
if im1.dtype != im2.dtype:
warn(“Inputs have mismatched dtype. Setting data_range based on ”
“im1.dtype.”, stacklevel=2)
dmin, dmax = dtype_range[im1.dtype.type]
data_range = dmax – dmin

ndim = im1.ndim

if gaussian_weights:
filter_func = gaussian_filter
filter_args = {‘sigma’: sigma, ‘truncate’: truncate}
else:
filter_func = uniform_filter
filter_args = {‘size’: win_size}

# ndimage filters need floating point data
im1 = im1.astype(np.float64)
im2 = im2.astype(np.float64)

NP = win_size ** ndim

# filter has already normalized by NP
if use_sample_covariance:
cov_norm = NP / (NP – 1) # sample covariance
else:
cov_norm = 1.0 # population covariance to match Wang et. al. 2004

# compute (weighted) means
ux = filter_func(im1, **filter_args)
uy = filter_func(im2, **filter_args)

# compute (weighted) variances and covariances
uxx = filter_func(im1 * im1, **filter_args)
uyy = filter_func(im2 * im2, **filter_args)
uxy = filter_func(im1 * im2, **filter_args)
vx = cov_norm * (uxx – ux * ux)
vy = cov_norm * (uyy – uy * uy)
vxy = cov_norm * (uxy – ux * uy)

R = data_range
C1 = (K1 * R) ** 2
C2 = (K2 * R) ** 2

A1, A2, B1, B2 = ((2 * ux * uy + C1,
2 * vxy + C2,
ux ** 2 + uy ** 2 + C1,
vx + vy + C2))
D = B1 * B2
S = (A1 * A2) / D

# to avoid edge effects will ignore filter radius strip around edges
pad = (win_size – 1) // 2

# compute (weighted) mean of ssim
mssim = crop(S, pad).mean()

if gradient:
# The following is Eqs. 7-8 of Avanaki 2009.
grad = filter_func(A1 / D, **filter_args) * im1
grad += filter_func(-S / B2, **filter_args) * im2
grad += filter_func((ux * (A2 – A1) – uy * (B2 – B1) * S) / D,
**filter_args)
grad *= (2 / im1.size)

if full:
return mssim, grad, S
else:
return mssim, grad
else:
if full:
return mssim, S
else:
return mssim

moviepy的神奇操作竟然让我完成了对B站的爬取

moviepy的神奇操作竟然让我完成了对B站的爬取

 

文章目录
前言
目标分析
遇到问题
发现神器
下载安装
查文档
使用
结语
前言
*个人主张自学,但是也不能忘记了讨论的重要性,但是由于平时不z怎么看CSDN,所以呢我这边搞了一个小圈子,欢迎大家来哦~可以畅所欲言呀——java小圈子

貌似在Python爬虫这边打Java群广告不太好,不过管他呢,哦哈哈哈
*

目标分析
爬取B站某一视频

遇到问题
在爬取B站的时候我们发现:
B站的视频和音频是分开储存的
那么我们需要将音频视频分别爬取
(具体怎么爬,我也不介绍了,无非就是抓包分析)
然后将视频音频分别储存
而后利用Python将视频音频合在一起
但是怎么利用Python才能将视频音频合在一起?(不会怎么办,没事,搜索引擎会用吧)

发现神器
经过我的不(利)懈(用)努(百)力(度),我找到了一个强劲的第三方库:

moviepy

他可以对视频做出许许多多的操作如:
剪切、拼接、插入标题、视频合成(即非线性编辑)、视频处理和创建高级特效(我的天?pr?)

具体更多操作可以参考官方中文文档——moviepy官方中文文档

下载安装
因为是Python的第三方库嘛,因此就需要请出我们的pip选手将其拿下
打开我们的终端(cmd)输入:
pip install moviepy -i https://pypi.douban.com/simple
然后如果没啥大问题的话,应该都是会成功的

查文档
然后就是找到我们需要的功能(将视频和音频合并),然后去阅读官方文档查看用法

仔细阅读了一遍后,发现还是挺有趣的

具体用法太多,我就不一一列举了,强烈推荐去看看文档然后学习一下,很有用

使用
# 导包
from moviepy.editor import *

# 读取视频文件
videoclip = VideoFileClip(“视频文件名”)
# 读取音频文件
Audioclip = AudioFileClip(“音频文件名”)

# 给 视频 添加 音频
video_data = videoclip.set_audio(Audioclip)

# 保存为另一个视频
video_data.write_videofile(“视频文件名”)

将视频音频合二为一就成功了!

这样我们的爬取B站视频就成功了

完结撒花~

结语
学习本就是一个从无到有的过程,我们要学会如何使用别人的轮子达到我们的效果。

如果我们连用轮子都不会,何谈造轮子。

今天就到这里了,再见

Python之Pandas学习

Python之Pandas学习

一、Pandas
pandas是python+data+analysis的组合缩写,2008年WesMcKinney开发出的库,专门用于数据挖掘的开源Python库,是python中基于numpy和matplotlib的第三方数据分析库,与后两者共同构成了python数据分析的基础工具包,享有数分三剑客之名。
pandas是在numpy基础上实现,其核心数据结构与numpy的ndarray十分相似,但pandas与numpy的关系不是替代,而是互为补充。

二者之间主要区别是:

1.数据结构上:
numpy的核心数据结构是ndarray,支持任意维数的数组,但要求单个数组内所有数据是同质的,即类型必须相同;而pandas的核心数据结构是series和dataframe,仅支持一维和二维数据,但数据内部可以是异构数据,仅要求同列数据类型一致即可
numpy的数据结构仅支持数字索引,而pandas数据结构则同时支持数字索引和标签索引

2.功能定位上:
numpy虽然也支持字符串等其他数据类型,但仍然主要是用于数值计算,尤其是内部集成了大量矩阵计算模块,例如基本的矩阵运算、线性代数、fft、生成随机数等,支持灵活的广播机制
pandas主要用于数据处理与分析,支持包括数据读写、数值计算、数据处理、数据分析和数据可视化全套流程操作

pandas主要面向数据处理与分析,主要具有以下功能特色:

按索引匹配的广播机制,这里的广播机制与numpy广播机制还有很大不同
便捷的数据读写操作,相比于numpy仅支持数字索引,pandas的两种数据结构均支持标签索引,包括bool索引也是支持的
类比SQL的join和groupby功能,pandas可以很容易实现SQL这两个核心功能,实际上,SQL的*大部分DQL和DML操作在pandas中都可以实现
类比Excel的数据透视表功能,Excel中*为强大的数据分析工具之一是数据透视表,这在pandas中也可轻松实现
自带正则表达式的字符串向量化操作,对pandas中的一列字符串进行通函数操作,而且自带正则表达式的大部分接口
丰富的时间序列向量化处理接口
常用的数据分析与统计功能,包括基本统计量、分组统计分析等
集成matplotlib的常用可视化接口,无论是series还是dataframe,均支持面向对象的绘图接口
核心数据结构
1、DataFrame

既有行索引,又有列索引的二维数组
行索引,表明不同行,横向索引,叫index
列索引,表明不同列,纵向索引,叫columns
常用属性

shape
index 行索引列表
columns 列索引列表
values 直接获取其中array的值
T 行列转置
常用方法

head() 开头几行
tail() *后几行
import numpy as np
import pandas as pd
# 创建一个符合正态分布的10个股票5天的涨跌幅数据
stock_change = np.random.normal(0, 1, (10, 5))
pd.DataFrame(stock_change)
# 添加行索引
stock = [“股票{}”.format(i) for i in range(10)]
pd.DataFrame(stock_change, index=stock)
# 添加列索引
date = pd.date_range(start=”20200101″, periods=5, freq=”B”)
data = pd.DataFrame(stock_change, index=stock, columns=date)

# 属性
print(data.shape)
print(data.index)
print(data.columns)
print(data.values)
data.T # 行列转置

# 方法
data.head(3) # 开头3行
data.tail(2) # *后2行

索引设置

# 修改行列索引值
# data.index[2] = “股票88” 不能单独修改索引
stock_ = [“股票_{}”.format(i) for i in range(10)]
data.index = stock_

# 重设索引
data.reset_index(drop=False) # drop=True把之前的索引删除

# 设置新索引
df = pd.DataFrame({‘month’: [1, 4, 7, 10],
‘year’: [2012, 2014, 2013, 2014],
‘sale’:[55, 40, 84, 31]})
# 以月份设置新的索引
df.set_index(“month”, drop=True)
# 设置多个索引,以年和月份
new_df = df.set_index([“year”, “month”])

2、MultiIndex与Panel

2.1、MultiIndex
多级或分层索引对象

index属性
names: levels的名称
levels: 每个level的元组值
print(new_df.index)
print(new_df.index.names)
print(new_df.index.levels)

2.2、Panel

pandas.Panel(data=None,items=None,major_axis=None,minor_axis=None,copy=False,dtype=None)存储3维数组的Panel结构

items – axis 0,每个项目对应于内部包含的数据帧(DataFrame)。
major_axis – axis 1,它是每个数据帧(DataFrame)的索引(行)。
minor_axis – axis 2,它是每个数据帧(DataFrame)的列。
p = pd.Panel(np.arange(24).reshape(4,3,2),
items=list(‘ABCD’),
major_axis=pd.date_range(‘20130101’, periods=3),
minor_axis=[‘first’, ‘second’])
p[“A”]
p.major_xs(“2013-01-01”)
p.minor_xs(“first”)

注:Pandas从版本0.20.0开始弃用,推荐的用于表示3D数据的方法是DataFrame上的MultiIndex方法

3、Series
带索引的一维数组

属性

index
values
# 创建
pd.Series(np.arange(3, 9, 2), index=[“a”, “b”, “c”])
# 或
pd.Series({‘red’:100, ‘blue’:200, ‘green’: 500, ‘yellow’:1000})

sr = data.iloc[1, :]
sr.index # 索引
sr.values # 值

总结:DataFrame是Series的容器,Panel是DataFrame的容器

二、基本数据操作
1、索引操作
data = pd.read_csv(“./stock_day/stock_day.csv”)
data = data.drop([“ma5″,”ma10″,”ma20″,”v_ma5″,”v_ma10″,”v_ma20”], axis=1) # 去掉一些不要的列
data[“open”][“2018-02-26”] # 直接索引,先列后行

data.loc[“2018-02-26”][“open”] # 按名字索引
data.loc[“2018-02-26”, “open”]
data.iloc[1, 0] # 数字索引

# 组合索引
# 获取行第1天到第4天,[‘open’, ‘close’, ‘high’, ‘low’]这个四个指标的结果
data.iloc[:4, [‘open’, ‘close’, ‘high’, ‘low’]] # 不能用了
data.loc[data.index[0:4], [‘open’, ‘close’, ‘high’, ‘low’]]
data.iloc[0:4, data.columns.get_indexer([‘open’, ‘close’, ‘high’, ‘low’])]

2、赋值操作
data.open = 100
data.iloc[1, 0] = 222
1
2
3、排序操作
排序有两种形式,一种对内容进行排序,一种对索引进行排序

内容排序:
使用df.sort_values(key=,ascending=)对内容进行排序,单个键或者多个键进行排序,默认升序,ascending=False:降序 True:升序
索引排序:
使用df.sort_index对索引进行排序
data.sort_values(by=”high”, ascending=False) # DataFrame内容排序

data.sort_values(by=[“high”, “p_change”], ascending=False).head() # 多个列内容排序

data.sort_index().head()

sr = data[“price_change”]

sr.sort_values(ascending=False).head()

sr.sort_index().head()

三、DataFrame运算
1、算术运算
data[“open”].add(3).head() # open统一加3 data[“open”] + 3
data.sub(100).head() # 所有统一减100 data – 100
data[“close”].sub(data[“open”]).head() # close减open

2、逻辑运算
query(expr) expr:查询字符串
isin(values) 判断是否为values

data[data[“p_change”] > 2].head() # p_change > 2
data[(data[“p_change”] > 2) & (data[“low”] > 15)].head()

data.query(“p_change > 2 & low > 15”).head()

# 判断’turnover’是否为4.19, 2.39
data[data[“turnover”].isin([4.19, 2.39])]

3、统计运算
describe()

综合分析:能够直接得出很多统计结果,count,mean,std,min,max等

data.describe()
data.max(axis=0)
data.idxmax(axis=0) #*大值位置

4、累计统计函数
cumsum 计算前1/2/3/…/n个数的和
cummax 计算前1/2/3/…/n个数的*大值
cummin 计算前1/2/3/…/n个数的*小值
cumprod 计算前1/2/3/…/n个数的积

data[“p_change”].sort_index().cumsum().plot()
1
5、自定义运算
apply(func, axis=0)
func: 自定义函数
axis=0: 默认按列运算,axis=1按行运算

data.apply(lambda x: x.max() – x.min())
1

四、Pandas画图
pandas.DataFrame.plot
DataFrame.plot(x=None, y=None, kind=‘line’)

x: label or position, default None
y: label, position or list of label, positions, default None
Allows plotting of one column versus another
kind: str
‘line’: line plot(default)
-’’bar”: vertical bar plot
-“barh”: horizontal bar plot
-“hist”: histogram
-“pie”: pie plot
-“scatter”: scatter plot
data.plot(x=”volume”, y=”turnover”, kind=”scatter”)
data.plot(x=”high”, y=”low”, kind=”scatter”)
1
2
pandas.Series.plot

sr.plot(kind=”line”)
1

五、文件读取与存储(常用3种文件类型)
1、CSV
pd.read_csv(“./stock_day/stock_day.csv”, usecols=[“high”, “low”, “open”, “close”]).head() # 读哪些列

data = pd.read_csv(“stock_day2.csv”, names=[“open”, “high”, “close”, “low”, “volume”, “price_change”, “p_change”, “ma5”, “ma10”, “ma20”, “v_ma5”, “v_ma10”, “v_ma20”, “turnover”]) # 如果列没有列名,用names传入

data[:10].to_csv(“test.csv”, columns=[“open”]) # 保存open列数据

data[:10].to_csv(“test.csv”, columns=[“open”], index=False, mode=”a”, header=False) # 保存opend列数据,index=False不要行索引,mode=”a”追加模式|mode=”w”重写,header=False不要列索引

2、HDF5
read_hdf()与to_hdf()
HDF5文件的读取和存储需要指定一个键,值为要存储的DataFrame
pandas.read_hdf(path_or_buf, key=None, **kwargs)

从h5文件当中读取数据

path_or_buffer: 文件路径
key: 读取的键
mode: 打开文件的模式
reurn: The Selected object
DataFrame.to_hdf(path_or_buf, key, **kwargs)

day_close = pd.read_hdf(“./stock_data/day/day_close.h5”)
day_close.to_hdf(“test.h5″, key=”close”)

3、JSON
read_json()

pandas.read_json(path_or_buf=None,orient=None,typ=“frame”,lines=False)

将JSON格式转换成默认的Pandas DataFrame格式
orient: string,Indication of expected JSON string format.
‘split’: dict like {index -> [index], columns -> [columns], data -> [values]}
‘records’: list like [{column -> value}, …, {column -> value}]
‘index’: dict like {index -> {column -> value}}
‘columns’: dict like {column -> {index -> value}}, 默认该格式
‘values’: just the values array
lines: boolean, default False
按照每行读取json对象
typ: default ‘frame’,指定转换成的对象类型series或者dataframe
sa = pd.read_json(“Sarcasm_Headlines_Dataset.json”, orient=”records”, lines=True)

sa.to_json(“test.json”, orient=”records”, lines=True)

六、缺失值处理
如何进行缺失值处理?

删除含有缺失值的样本
替换/插补数据
1、如何处理NaN?
1.1、判断是否有NaN

pd.isnull(df)
pd.notnull(df)
1.2、删除含有缺失值的样本
df.dropna(inplace=True) 默认按行删除 inplace:True修改原数据,False返回新数据,默认False
1.3、替换/插补数据
df.fillna(value,inplace=True) value替换的值 inplace:True修改原数据,False返回新数据,默认False

import pandas as pd
import numpy as np
movie = pd.read_csv(“./IMDB/IMDB-Movie-Data.csv”)
# 1)判断是否存在NaN类型的缺失值
np.any(pd.isnull(movie)) # 返回True,说明数据中存在缺失值
np.all(pd.notnull(movie)) # 返回False,说明数据中存在缺失值
pd.isnull(movie).any()
pd.notnull(movie).all()

# 2)缺失值处理
# 方法1:删除含有缺失值的样本
data1 = movie.dropna()
pd.notnull(data1).all()

# 方法2:替换
# 含有缺失值的字段
# Revenue (Millions)
# Metascore
movie[“Revenue (Millions)”].fillna(movie[“Revenue (Millions)”].mean(), inplace=True)
movie[“Metascore”].fillna(movie[“Metascore”].mean(), inplace=True)

2、不是缺失值NaN
不是缺失值NaN,有默认标记的

# 读取数据
path = “https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data”
name = [“Sample code number”, “Clump Thickness”, “Uniformity of Cell Size”, “Uniformity of Cell Shape”, “Marginal Adhesion”, “Single Epithelial Cell Size”, “Bare Nuclei”, “Bland Chromatin”, “Normal Nucleoli”, “Mitoses”, “Class”]

data = pd.read_csv(path, names=name)

# 1)替换
data_new = data.replace(to_replace=”?”, value=np.nan)

# 2)删除缺失值
data_new.dropna(inplace=True)

七、数据离散化
连续属性的离散化就是将连续属性的值域上,将值域划分为若干个离散的区间,*后用不同的符号或整数 值代表落在每个子区间的属性值。

为什么要离散化:
连续属性离散化的目的是为了简化数据结构,数据离散化技术可以用来减少给定连续属性值的个数。离散化方法经常作为数据挖掘的工具。

如何实现数据的离散化
1、分组

自动分组 sr = pd.qcut(data, bins)
自定义分组 sr = pd.cut(data, [])
2、将分组好的结果转换成one-hot编码(哑变量)

pd.get_dummies(sr, prefix=)
# 1)准备数据
data = pd.Series([165,174,160,180,159,163,192,184], index=[‘No1:165’, ‘No2:174′,’No3:160’, ‘No4:180’, ‘No5:159’, ‘No6:163’, ‘No7:192’, ‘No8:184’])
# 2)分组
# 自动分组
sr = pd.qcut(data, 3)
sr.value_counts() # 看每一组有几个数据
# 3)转换成one-hot编码
pd.get_dummies(sr, prefix=”height”)

# 自定义分组
bins = [150, 165, 180, 195]
sr = pd.cut(data, bins)
# get_dummies
pd.get_dummies(sr, prefix=”身高”)

八、合并
1、按方向
pd.concat([data1, data2], axis=1) axis:0为列索引;1为行索引

2、按索引
pd.merge(left, right, how=“inner”, on=[]) on:索引

left = pd.DataFrame({‘key1’: [‘K0’, ‘K0’, ‘K1’, ‘K2’],
‘key2’: [‘K0’, ‘K1’, ‘K0’, ‘K1’],
‘A’: [‘A0’, ‘A1’, ‘A2’, ‘A3’],
‘B’: [‘B0’, ‘B1’, ‘B2’, ‘B3’]})

right = pd.DataFrame({‘key1’: [‘K0’, ‘K1’, ‘K1’, ‘K2’],
‘key2’: [‘K0’, ‘K0’, ‘K0’, ‘K0’],
‘C’: [‘C0’, ‘C1’, ‘C2’, ‘C3’],
‘D’: [‘D0’, ‘D1’, ‘D2’, ‘D3’]})

pd.merge(left, right, how=”inner”, on=[“key1”, “key2″])

pd.merge(left, right, how=”left”, on=[“key1”, “key2″])

pd.merge(left, right, how=”outer”, on=[“key1”, “key2”])

九、交叉表与透视表
找到、探索两个变量之间的关系

1、交叉表
交叉表用于计算一列数据对于另外一列数据的分组个数(寻找两个列之间的关系)

pd.crosstab(value1, value2)

data = pd.crosstab(stock[“week”], stock[“pona”])
data.div(data.sum(axis=1), axis=0).plot(kind=”bar”, stacked=True)

2、透视表
DataFrame.pivot_table([], index=[])

# 透视表操作
stock.pivot_table([“pona”], index=[“week”])

十、分组与聚合
分组与聚合通常是分析数据的一种方式,通常与一些统计函数一起使用,查看数据的分组情况。
DataFrame.groupby(key, as_index=False) key:分组的列数据,可以多个

col =pd.DataFrame({‘color’: [‘white’,’red’,’green’,’red’,’green’], ‘object’: [‘pen’,’pencil’,’pencil’,’ashtray’,’pen’],’price1′:[5.56,4.20,1.30,0.56,2.75],’price2′:[4.75,4.12,1.60,0.75,3.15]})

# 进行分组,对颜色分组,price1进行聚合
# 用dataframe的方法进行分组
col.groupby(by=”color”)[“price1”].max()

# 或者用Series的方法进行分组聚合
col[“price1”].groupby(col[“color”]).max()

Python爬虫Scrapy轮子工具

Python爬虫Scrapy轮子工具

Scrapy
万字长文,建议使用目录点击查阅,有助于高效开发。建议点赞收藏

文章目录
Scrapy
概念
模块作用
开发步骤
爬虫文件 spiders.py
代码流程
提取数据
scrapy.Request发送post请求
发送post请求
response响应
Cookie
参数解释
meta参数的使用
管道 piplines.py
pipeline中常用的方法:
开启管道
多个管道的开启作用
MongoDB 持久化
Json 持久化
MySql 持久化
Csv持久化
中间件 middleware.py
中间件的分类
Scrapy中间的作用(预处理Request和Response对象)
Downloader Middlewares默认的方法:
fake_useragent
ip_proxy
方法一【免费代理】:
方法二【收费代理】:
Scrapy-redis
Scrapy-bloomfilter布隆过滤器
设置 settings.py
常用变量
启动运行
方法一【运行单个爬虫文件】:
方法二【 串行 运行完*个才会运行下一个】:
方法三【在进程里面跑多个爬虫】:
概念
scrapy框架的运行流程以及数据传递过程:

爬虫中起始的url构造成request对象–>爬虫中间件–>引擎–>调度器
调度器把request–>引擎–>下载中间件—>下载器
下载器发送请求,获取response响应—->下载中间件—->引擎—>爬虫中间件—>爬虫
爬虫提取url地址,组装成request对象—->爬虫中间件—>引擎—>调度器,重复步骤2
爬虫提取数据—>引擎—>管道处理和保存数据
模块作用
引擎(engine):负责数据和信号在不腰痛模块间的传递
调度器(scheduler):实现一个队列,存放引擎发过来的request请求对象
下载器(downloader):发送引擎发过来的request请求,获取响应,并将响应交给引擎
爬虫(spider):处理引擎发过来的response,提取数据,提取url,并交给引擎
管道(pipeline):处理引擎传递过来的数据,比如存储
下载中间件(downloader middleware):可以自定义的下载扩展,比如设置代理ip
爬虫中间件(spider middleware):可以自定义request请求和进行response过滤,与下载中间件作用重复

开发步骤
创建项目:

scrapy startproject mySpider
scrapy startproject <项目名字>

生成一个爬虫【在项目目录下执行】:

scrapy genspider lianjia lianjia.com
scrapy genspider <爬虫名字> <允许爬取的域名>

爬虫名字: 作为爬虫运行时的参数

允许爬取的域名: 为对于爬虫设置的爬取范围,设置之后用于过滤要爬取的url,如果爬取的url与允许的域不通则被过滤掉。

提取数据:

修改start_urls
检查修改allowed_domains
编写解析方法
根据网站结构在spider中实现数据采集相关内容

保存数据:

在pipelines.py文件中定义对数据处理的管道

在settings.py文件中注册启用管道

启动项目

爬虫文件 spiders.py
代码流程
完善并使用Item数据类:
在items.py中完善要爬取的字段
在爬虫文件中先导入Item
实力化Item对象后,像字典一样直接使用
构造Request对象,并发送请求:
导入scrapy.Request类
在解析函数中提取url
yield scrapy.Request(url, callback=self.parse_detail, meta={})
利用meta参数在不同的解析函数中传递数据:
通过前一个解析函数 yield scrapy.Request(url, callback=self.xxx, meta={}) 来传递meta
在self.xxx函数中 response.meta.get(‘key’, ‘’) 或 response.meta[‘key’] 的方式取出传递的数据
提取数据
解析并获取scrapy爬虫中的数据:
1. response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
2. extract() 返回一个包含有字符串的列表,配合[0]使用
3. extract_first() 返回列表中的*个字符串,列表为空没有返回None
4. get() 提取列表中第1个文本内容(等同于extract_first())

scrapy.Request发送post请求
我们知道可以通过scrapy.Request()指定method、body参数来发送post请求;但是通常使用scrapy.FormRequest()来发送post请求
1
发送post请求
注意:scrapy.FormRequest()能够发送表单和ajax请求,参考阅读 https://www.jb51.net/article/146769.htm

response响应
response.url:当前响应的url地址

1. response.request.url:当前响应对应的请求的url地址
2. response.headers:响应头
3. response.requests.headers:当前响应的请求头
4. response.body:响应体,也就是html代码,byte类型
5. response.status:响应状态码

Cookie
1.在settings.py中通过设置COOKIES_DEBUG=TRUE 能够在终端看到cookie的传递传递过程
2.如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写3.start_request方法并在其中手动添加上cookie
4.如果重新start_requests()方法,则需要去掉start_urls变量

参数解释
中括号里的参数为可选参数
callback:表示当前的url的响应交给哪个函数去处理
meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
dont_filter:默认为False,会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
method:指定POST或GET请求
headers:接收一个字典,其中不包括cookies
cookies:接收一个字典,专门放置cookies
body:接收json字符串,为POST的数据,发送payload_post请求时使用(在下一章节中会介绍post请求)
注意:解析函数中的yield能够传递的对象只能是:BaseItem, Request, dict, None
meta参数的使用
meta的作用:meta可以实现数据在不同的解析函数中的传递
在爬虫文件的parse方法中,提取详情页增加之前callback指定的parse_detail函数:

def parse(self,response):

yield scrapy.Request(detail_url, callback=self.parse_detail,meta={“item”:item})

def parse_detail(self,response):
#获取之前传入的item
item = resposne.meta[“item”]

注意
1. meta参数是一个字典
2. meta字典中有一个固定的键proxy,表示代理ip,关于代理ip的使用我们将在scrapy的下载中间件

管道 piplines.py
管道的基本使用:
1. 完善pipelines.py中的process_item函数
2. 在settings.py中设置开启pipeline
3. pipeline在setting中键表示位置(即pipeline在项目中的位置可以自定义),值表示距离引擎的远近,越近数据会越先经过:权重值小的优先执行
4. 1. 有多个pipeline的时候,process_item的方法必须return item,否则后一个pipeline取到的数据为None值
5. pipeline中process_item的方法必须有,否则item没有办法接受和处理
6. process_item方法接受item和spider,其中spider表示当前传递item过来的spider

pipeline中常用的方法:
process_item(self,item,spider):
管道类中必须有的函数
实现对item数据的处理
必须return item
open_spider(self, spider): 在爬虫开启的时候仅执行一次
close_spider(self, spider): 在爬虫关闭的时候仅执行一次
开启管道
在settings.py设置开启pipeline
1
ITEM_PIPELINES = {
‘myspider.pipelines.ItcastFilePipeline’: 400, # 400表示权重
‘myspider.pipelines.ItcastMongoPipeline’: 500, # 权重值越小,越优先执行!
}

多个管道的开启作用
1. 不同的pipeline可以处理不同爬虫的数据,通过spider.name属性来区分
2. 不同的pipeline能够对一个或多个爬虫进行不同的数据处理的操作,比如一个进行数据清洗,一个进行数据的保存
3. 同一个管道类也可以处理不同爬虫的数据,通过spider.name属性来区分

MongoDB 持久化
# 【1】settings.py中添加
ITEM_PIPELINES = {
# 添加MongoDB管道
‘Tencent.pipelines.TencentMongoPipeline’: 400,
}
MONGO_HOST = ‘127.0.0.1’
MONGO_PORT = 27017
MONGO_DB = ‘tencentdb’
MONGO_SET = ‘tencentset’

# 【2】pipelines.py中新建MongoDB管道类
from .settings import *
import pymongo

class TencentMongoPipeline:
def open_spider(self, spider):
self.conn = pymongo.MongoClient(MONGO_HOST, MONGO_PORT)
self.db = self.conn[MONGO_DB]
self.myset = self.db[MONGO_SET]

def process_item(self, item, spider):
self.myset.insert_one(dict(item))

Json 持久化
import json

class WangyiPipeline(object):

def open_spider(self, spider):
if spider.name == ‘job’:
self.file = open(‘wangyi.json’, ‘w’)

def process_item(self, item, spider):
if spider.name == ‘job’:
item = dict(item)

str_data = json.dumps(item, ensure_ascii=False) + ‘,\n’

self.file.write(str_data)

return item

def close_spider(self, spider):
if spider.name == ‘job’:
self.file.close()

MySql 持久化
1)MySQL建表

create database tencentdb charset utf8;
use tencentdb;
create table tencenttab(
job_name varchar(200),
job_type varchar(200),
job_duty varchar(2000),
job_require varchar(2000),
job_add varchar(100),
job_time varchar(100)
)charset=utf8;

2)MySql数据持久化

# 【1】settings.py添加
ITEM_PIPELINES = {
# 在原来基础上添加MySQL的管道
‘Tencent.pipelines.TencentMysqlPipeline’: 200,
}
MYSQL_HOST = ‘127.0.0.1’
MYSQL_USER = ‘root’
MYSQL_PWD = ‘123456’
MYSQL_DB = ‘tencentdb’
CHARSET = ‘utf8’

# 【2】pipelines.py新建MySQL管道类
from .settings import *
import pymysql

class TencentMysqlPipeline:
def open_spider(self, spider):
self.db = pymysql.connect(MYSQL_HOST, MYSQL_USER, MYSQL_PWD, MYSQL_DB, charset=CHARSET)
self.cur = self.db.cursor()
self.ins = ‘insert into tencenttab values(%s,%s,%s,%s,%s,%s)’

def process_item(self, item, spider):
li = [
item[‘job_name’],
item[‘job_type’],
item[‘job_duty’],
item[‘job_require’],
item[‘job_add’],
item[‘job_time’],
]
self.cur.execute(self.ins, li)
self.db.commit()

return item

def close_spider(self, item, spider):
self.cur.close()
self.db.close()

进阶:mysql连接池
Csv持久化
piplines.py
import csv

class LianjiaspiderPipeline(object):
def open_spider(self, spider):
if spider.name == “home”:
self.file = open(‘lianjia.csv’, ‘w’, encoding=”utf-8″)
self.f_csv = csv.writer(self.file)
headers = [‘地址’, ‘总价’, ‘单价’, ‘户型’, ‘面积’, “朝向”, “楼层”, “装修程度”, “详情页url”]
self.f_csv.writerow(headers)

def process_item(self, item, spider):
if spider.name == “home”:
data = [item[“address”], item[“price”], item[“unit_price”], item[“door_model”], item[“area”],
item[“direction”], item[“floor”], item[“decorate”], item[“info_url”]]
self.f_csv.writerow(data)
print(data)
return item

def close_spider(self, spider):
if spider.name == “home”:
self.file.close()

settings.py
# 管道
ITEM_PIPELINES = {
‘LianJiaSpider.pipelines.LianjiaspiderPipeline’: 300,
}

中间件 middleware.py
中间件的分类
1.下载器中间件
2.爬虫中间件

Scrapy中间的作用(预处理Request和Response对象)
1. 对header以及cookie进行更换和处理
2. 使用代理ip等
3. 对请求进行定制化操作,

但在scrapy默认的情况下 两种中间件都在middlewares.py一个文件中

爬虫中间件使用方法和下载中间件相同,且功能重复,通常使用下载中间件

Downloader Middlewares默认的方法:
process_request(self, request, spider):

当每个request通过下载中间件时,该方法被调用。
2. 返回None值:没有return也是返回None,该request对象传递给下载器,或通过引擎传递给其他权重低的process_request方法
3. 返回Response对象:不再请求,把response返回给引擎
4. 返回Request对象:把request对象通过引擎交给调度器,此时将不通过其他权重低的process_request方法
process_response(self, request, response, spider):

当下载器完成http请求,传递响应给引擎的时候调用
2. 返回Resposne:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法
3. 返回Request对象:通过引擎交给调取器继续请求,此时将不通过其他权重低的process_request方法
在settings.py中配置开启中间件,权重值越小越优先执行

fake_useragent
middlewares.py
from fake_useragent import UserAgent
class RandomUserAgentMiddleware(object):
def process_request(self, request, spider):
ua = UserAgent()
request.headers[‘User-Agent’] = ua.random

settings.py
DOWNLOADER_MIDDLEWARES = {
‘xxx项目名.middlewares.RandomUserAgentMiddleware’: 300,
}

注意:UserAgent中间件设置为None,这样就不会启用,否则默认系统的这个中间会被启用。

ip_proxy
方法一【免费代理】:
settings.py
DOWNLOADER_MIDDLEWARES = {
‘项目名.middlewares.RandomProxy’: 543,
}
PROXY_LIST =[
{“ip_port”: “123.207.53.84:16816”, “user_passwd”: “morganna_mode_g:ggc22qxp”},
# {“ip_port”: “122.234.206.43:9000”},
]

middlewares.py
from 项目名.settings import PROXY_LIST

class RandomProxy(object):

def process_request(self, request, spider):
proxy = random.choice(PROXY_LIST)
print(proxy)
if ‘user_passwd’ in proxy:
# 对账号密码进行编码,python3中base64编码的数据必须是bytes类型,所以需要encode
b64_up = base64.b64encode(proxy[‘user_passwd’].encode())
# 设置认证
request.headers[‘Proxy-Authorization’] = ‘Basic ‘ + b64_up.decode()
# 设置代理
request.meta[‘proxy’] = proxy[‘ip_port’]
else:
# 设置代理
request.meta[‘proxy’] = proxy[‘ip_port’]

方法二【收费代理】:
收费代理ip:

# 人民币玩家的代码(使用abuyun提供的代理ip)
import base64

# 代理隧道验证信息 这个是在那个网站上申请的
proxyServer = ‘http://proxy.abuyun.com:9010’ # 收费的代理ip服务器地址,这里是abuyun
proxyUser = 用户名
proxyPass = 密码
proxyAuth = “Basic ” + base64.b64encode(proxyUser + “:” + proxyPass)

class ProxyMiddleware(object):
def process_request(self, request, spider):
# 设置代理
request.meta[“proxy”] = proxyServer
# 设置认证
request.headers[“Proxy-Authorization”] = proxyAuth

检测代理ip是否可用
在使用了代理ip的情况下可以在下载中间件的process_response()方法中处理代理ip的使用情况,如果该代理ip不能使用可以替换其他代理ip

class ProxyMiddleware(object):
……
def process_response(self, request, response, spider):
if response.status != ‘200’:
request.dont_filter = True # 重新发送的请求对象能够再次进入队列
return requst

settings.py
DOWNLOADER_MIDDLEWARES = {
‘myspider.middlewares.ProxyMiddleware’: 543,
}

Scrapy-redis
settings.py 文件配置[注意:scrapy-redis 与 bloomfilter 二者只能选其一使用]
# scrapy-redis分布式配置 pip install scrapy-redis
# 重新指定调度器: 启用Redis调度存储请求队列!!!
SCHEDULER = “scrapy_redis.scheduler.Scheduler”
# 重新指定去重机制: 确保所有的爬虫通过Redis去重!!!
DUPEFILTER_CLASS = “scrapy_redis.dupefilter.RFPDupeFilter”

# redis配置
REDIS_HOST = ‘127.0.0.1’ # ip
REDIS_PORT = 6379 # 端口
# REDIS_PARAMS = {
# ‘password’: ”, # 密码
# }

Scrapy-bloomfilter布隆过滤器
settings.py文件配置
# 布隆过滤器配置 pip install scrapy-redis-bloomfilter
# 重新指定调度器
SCHEDULER = “scrapy_redis_bloomfilter.scheduler.Scheduler”
# 重新指定去重机制
DUPEFILTER_CLASS = “scrapy_redis_bloomfilter.dupefilter.RFPDupeFilter”
# 使用哈希函数的数量,默认为6
BLOOMFILTER_HASH_NUMBER = 6
# 使用Bloomfilter的Redis内存,30表示2^30 = 128MB,默认为30
BLOOMFILTER_BIT = 30

设置 settings.py
常用变量
设置数据导出编码(主要针对于json文件)
FEED_EXPORT_ENCODING = ‘utf-8’
设置User-Agent
USER_AGENT = ”
设置*大并发数(默认为16)
CONCURRENT_REQUESTS = 32
下载延迟时间(每隔多长时间请求一个网页)
DOWNLOAD_DELAY = 0.5
请求头
DEFAULT_REQUEST_HEADERS = {‘Cookie’ : ‘xxx’}
添加项目管道
ITEM_PIPELINES = {‘目录名.pipelines.类名’ : 优先级}
COOKIES_ENABLED = False

启动运行
方法一【运行单个爬虫文件】:
在根目录下创建start.py

from scrapy import cmdline

cmdline.execute(“scrapy crawl hot”.split())
# cmdline.execute(“scrapy crawl hot -o hot.csv”.split()) # 导出csv

# cmdline.execute(“scrapy crawl hot -o hot.json”.split()) # 导出json

# 注意: settings.py中设置导出编码 – 主要针对json文件
FEED_EXPORT_ENCODING = ‘utf-8’

Excel打开csv时出现乱码

解决办法:用记事本打开CSV,文件菜单中另存为UTF-8保存
方法二【 串行 运行完*个才会运行下一个】:
在根目录下创建main.py

from scrapy.cmdline import execute

execute(“scrapy crawl 爬虫文件名1”.split())
execute(“scrapy crawl 爬虫文件名2”.split())

方法三【在进程里面跑多个爬虫】:
在根目录下创建main.py

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

settings = get_project_settings()

crawler = CrawlerProcess(settings)

crawler.crawl(‘爬虫文件名1’)
crawler.crawl(‘爬虫文件名2’)

crawler.start()
crawler.start()

UE4 Python脚本编辑器扩展

UE4 Python脚本编辑器扩展

Python+编辑器扩展

1. 各种菜单的扩展
1.1 主菜单内添加一个子菜单
mainMenu = menus.find_menu(‘LevelEditor.MainMenu’) // 找到主菜单

ownerName = mainMenu.get_name()
# 该名称用于标识一个菜单下的分区名,如果menu的sectionName一致,它们会被放在一起
sectionName = ‘PythonTools’
subMenuName = ‘MenuTest’
subMenuLabel = ‘MenuTest1’
subMenuTip = ‘This is menutest1’
menus.add_sub_menu(ownerName, sectionName, subMenuName, subMenuLabel, subMenuTip)
# 刷新窗口
menus.refresh_all_widgets()

想要查看ue编辑器内的各个sectionname,可以在EditorPreference中的Misc中打开相应配置,打开一个菜单时会刷新对应的widget,如果想要窗口全部刷新则可以执行如下python命令
py unreal.ToolMenus.get().refresh_all_widgets()

1.2 菜单项下添加一个按钮
menus = unreal.ToolMenus.get()
# 根据上面的subMenuName找到目标菜单
targetMenu = menus.find_menu(‘LevelEditor.MainMenu.MenuTest’)

menuEntry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.MENU_ENTRY)
menuEntry.set_label(‘Test Button 1’)
menuEntry.set_string_command(unreal.ToolMenuStringCommandType.PYTHON, ”, ‘print(‘this is button 1′)’)

sectionname = ”
targetMenu.add_menu_entry(sectionname, menuEntry)
menus.refresh_all_widgets()

按钮的命令:
unreal.ToolMenuStringCommandType.PYTHON,后面的字符串为python代码;
unreal.ToolMenuStringCommandType.COMMAND,后面的字符串为cmd命令,如使用py xxx.py执行脚本;
等同于输出日志中的python控制台和cmd控制台的py命令;

1.3 为ToolBar添加按钮
# 和上面的两个区别,首先是targetMenu,然后是Entry的类型
targetMenu = menus.find_menu(‘LevelEditor.ToolEditorToolBar’)
menuEntry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.TOOL_BAR_BUTTON)
1
2
3
1.4 内容浏览器右键菜单扩展
targetMenu = unreal.ToolMenus.get(‘ContentBrowser.FolderContextMenu’)
entry = unreal.ToolMenuEntry(type=unreal.MultiBlockType,MENU_ENTRY)

# 选中的资源
unreal.ContentBrowserAssetContextMenuContext.get_selected_objects()

1.5 关卡视口中actor右键菜单
可以用如下方式获取选中的actor,但是无法像蓝图一样将actor强转到相应的派生类,因此也就无法获取到实例actor的属性以及不能调用相应的函数;目前的python是不支持这个的,可参考:https://answers.unrealengine.com/questions/938515/casting-a-blueprint-in-python.html;
只能调用actor类已有的内置函数,如set_actor_location()等;

assets = unreal.EditorLevelLibrary.get_selected_level_actors()
for actor in assets:
1
2
但是可以修改bp的默认值,如下所示:
我们需要调用unreal.get_default_object来获取CDO(Class Default Object),然后使用set_editor_property来完成功能;

bp_class = unreal.load_class(None, ‘/Game/NewBlueprint.NewBlueprint_C’)
cdo = unreal.get_default_object(bp_class)
cdo.set_editor_property(‘var’, 102)
cdo.call_method(‘TestFunc’, (actor,))

上述列出的问题虽然python内不能解决,但是能够通过蓝图扩展来完成;
基于python的扩展依然还只是在pie中使用;

2. 基础实践
2.1 日志系统
unreal.log() : python中的print也会在内部通过unreal.log()来处理
unreal.log_warning()
unreal.log_error()
2.2 处理资源
如果需要在项目中处理资源,必须使用Unreal Python API来完成,而不能使用Python内置模块来处理磁盘资源文件,比如资源的移动,如果不适用unreal的api则会导致引用失效,所以要尽量使用unreal.EditorAssetLibrary或unreal.AssetTools

尽可能使用虚幻类型
比如数学类等,要尽可能使用Unreal API提供的类型,如unreal.Vector()

2.3 使用json配置来管理各种扩展
os.open/read/write
import json
json.dumps/loads

3.其它常用api
3.1 资源相关
资源相关的api都在这个库里:unreal.EditorAssetLibrary
资源的保存:save_asset()

3.2 工程路径
系统库:unreal.SystemLibrary
获取项目路径:get_project_directory()

4.结合pyqt5的进阶实践
本想使用ue4的api来打开一个文件对话框,但是没有找到,网上有一些使用C++的扩展;
因此就想到了pyqt5也可以完成,而且ue4也可以调用python,这样就不用在C++层处理了,但是这只能用于编辑器模式下;

4.1 打开一个文件对话框
import unreal
import os
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QToolTip, QPushButton, QMessageBox, QDesktopWidget, QFileDialog, QLabel)

class Example(QFileDialog):

def __init__(self):
super().__init__()
self.open_folder()

def open_folder(self):
path = QFileDialog.getExistingDirectory(self, u’选择文件夹’, unreal.SystemLibrary.get_project_directory())
print(path)

app = QApplication(sys.argv)
ex = Example()
sys.exit(app.quit())

5. 常见问题
5.1 Python missing classes from unreal module
一些模块没有找到是因为我们需要安装对应的插件
我们可以使用如下方式可以遍历到unreal下所有的子模块

import unreal
moduels = dir(unreal)
for module in modules:
print(module)

Python基础入门:九大必学点

Python基础入门:九大必学点

小编整理了一天,希望对想学习的朋友用,认真看与学,你就能敲会简单的码,学习上也就能事功半倍,下面就是本章的内容大概,喜欢就一定要收藏起来。

缩进
Python 函数没有明显的 begin 和 end,没有标明函数的开始和结束的花括号。唯一的分隔符是一个冒号 (?,接着代码本身是缩进的。

例子:

#函数
def func(value):
print value #缩进
if value == 1:
value += 1
elif value == 2:
pass
else:
value += 10

标识符
变量是标识符的例子。 标识符 是用来标识 某样东西 的名字。在命名标识符的时候,你要遵循这些规则:

1.python中的标识符是区分大小写的。

2.标示符以字母或下划线开头,可包括字母,下划线和数字,大小写敏感

3.以下划线开头的标识符是有特殊意义的。

•以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用“from xxx import *”而导入;
•以双下划线开头的(foo)代表类的私有成员;
•以双下划线开头和结尾的(foo)代表python里特殊方法专用的标识,如__init()代表类的构造函数。

4.标识符不能是保留字

and elif global or yield
assert else if pass
break except import print
class exec in raise
continue finally is return
def for lambda try
del from not while

变量
赋值语句
•赋值语句建立对象引用值
•变量名在首次赋值时会被建立
•变量名在引用前必须先赋值,不能引用未声明赋值的变量

赋值方式
•简单赋值
Variable(变量)=Value(值)
s = ‘spam’

•多变量赋值
python中原始的元组和列表赋值语句形成,*后已被通用化,以接受右侧可以是是任何类型的序列,只要长度相等即可。注意,长度一定相等
Variable1,variable2,…=Value1,Value2,…
s,h = ‘a’,‘b’ 元组赋值,位置性 【常用】
[s,h] =[‘a’,‘b’] 列表赋值,位置性
a,b,c,d = ‘spam’ 序列赋值,通用性
a,*b = ‘spam’ 拓展序列解包(python3)

•多目标赋值
a=b=variable
s = h = ‘spam’ 多目标赋值
注意:多个变量内存中指向同一对象,对于可变类型需要,修改一个会对其他造成影响

•自变赋值
如+=,-=,*=等。
在自变赋值中,python仅计算一次,而普通写法需计算两次;
自变赋值会修改原始对象,而不是创建一个新对象。
s +=42 增强赋值
x += y
优点:
程序员输入更少
左侧只需计算一次,优化技术自动原处修改,更快
l +=[] 原处修改
l = l+[] 复制,生成新的对象

运算符
一个表达式可以分解为运算符和操作数

运算符 的功能是完成某件事,它们由如+这样的符号或者其他特定的关键字表示
运算符需要数据来进行运算,这样的数据被称为 操作数
运算符优先顺序列表(从*高到*低)
运算符的描述

‘expr’ 字符串转换
{key:expr,…} 字典
[expr1,expr2…] 列表
(expr1,expr2,…) 元组
function(expr,…) 函数调用
x[index:index] 切片
x[index] 下标索引取值
x.attribute 属性引用
~x 按位取反
+x,-x 正,负
x**y 幂
x*y,x/y,x%y 乘,除,取模
x+y,x-y 加,减
x<<y,x>>y 移位
x&y 按位与
x^y 按位异或
x|y 按位或
x<y,x<=y,x==y,x!=y,x>=y,x>y 比较
x is y,x is not y 等同测试
x in y,x not in y 成员判断
not x 逻辑否
x and y 逻辑与
x or y 逻辑或
lambda arg,…:expr Lambda匿名函数
结合规律

运算符通常由左向右结合,即具有相同优先级的运算符按照从左向右的顺序计算

计算顺序
默认地,运算符优先级表决定了哪个运算符在别的运算符之前计算。然而,如果你想要改变它们的计算顺序,你得使用圆括号。好的做法:默认对复杂的运算加括号,而不是依赖于默认结合和计算顺序

真值
真值测试
•任何非零数字或非空对象都为真
•数字零,空对象以及特殊对象None都为假
•比较和相等测试都会递归地运用到数据结构中
•比较和相等测试会返回True或False
真值表

对象/常量 值
“” 假
“string” 真
0 假
2>=1 真
-2<=-1 真
()空元组 假
[]空列表 假
{}空字典 假
None 假

布尔表达式
三种布尔表达式运算符

x and y
x or y
not x

比较
•数字通过相对大小进行比较
•字符串时按照字典顺序的,一个字符一个字符比较
•列表和元组从左到右对每部分的内容进行比较
•字典通过排序后的键值列表进行比较
•数字混合类型比较在python3是错误的,但是python2.6支持,固定但任意的排序规则
布尔数
•有两个永远不改变的值True,False
•布尔是整型的子类,但不能被再继承
•没有__nonzero__()方法的对象的默认值是True
•对于值为0的任何数字或空集,值False
•在数学运算中,Bollean值的True和False分别对应于1和0

基本控制流
if
基本的条件测试语句,用来判断可能遇到的不同情况,并针对不同的情况进行操作
基本形式

if <条件>:
<语句>
elif <条件>:
<语句>
else:
<语句>

注意
python根据缩进判断, elif和else部分是可选的

例子:

a = 1
b = 2
c = 3;d=4 #两个放一句用分号隔开,不过建议分行
if a < b and c < d:
print(“branch a”)
elif a == b:
print(“branch b”)
else:
print(“branch c”)
switch

python 本身没有 switch 语句,若需要,用if/elif/else实现完成同样的工作,某些情况可以考虑用字典
也可以用dict的形式
if/else三元运算符
A = ((X and Y) or Z)
A = Y if X else Z
例: a = ‘t’ if x else ‘a’
for
在这里插入图片描述

基本语法
循环控制语句,可以用于循环遍历某一序列
else块可选,在循环终止的时候执行,若是break终止循环,else不执行
格式:

for <对象变量> in <对象集合>:
if<条件>:
break
if<条件>:
continue
<其他语句>
else:
<其他语句>

注意:
1.对象集合可以是列表,字典以及元组等
2.for…in循环对于任何序列都适用
3.for遍历一个字典时,遍历的是字典的键
•rang & xrange
可以通过range()函数产生一个整数列表,完成计数循环
range([start,] stop[, step])
start可选参数,起始数
stop终止数,若为x,产生从0-(x-1)的整数列表
step可选参数,步长,未写默认为1
range(1,5) 包含序列为 [1,2,3,4]
xrange和range区别
(python3.x的可无视)

在Range的方法中,它会生成一个list的对象,但是在XRange中,它生成的却是一个xrange的对象,当返回的东西不是很大的时候,或者在一个循环里,基本上都是从头查到底的情况下,这两个方法的效率差不多。但是,当返回的东西很大,或者循环中常常会被Break出来的话,还是建议使用XRange,这样既省空间,又会提高效率。

>>> print range(1, 5)
[1, 2, 3, 4]
>>> print xrange(1, 5)
xrange(1, 5)

在上面语句中,range返回了一个普通List,而xrange返回了一个特定的xrange类型的对象。由于 xrange 方法也创建整数 list(其使用相同参数),所以它与 range 方法非常相似。但是,xrange 方法仅在需要时才在 list 中创建整数。当需要迭代大量整数时,xrange 方法更适用,因为它不会创建*大的 list,那样会消耗大量计算机内存。
while
与if语句类似,含一个条件测试语句,循环,允许重复执行一个语句块。

可选else语句块,同for的else块。

格式:

while <条件>:
if <条件>:
break
if <条件>:
continue
<其他语句>
else:
<语句>

说明:

•while循环条件变为False的时候,else块才被执行
•若是使用break结束循环,while可选的else块不执行
•python没有do while或do until循环语句
break & continue & pass
break,终止循环语句,停止循环,若是for/while循环中终止,其else不执行

continue,结束当前,进入下一轮循环 – 跳到*近所在循环的开头处(来到循环首行)

pass 什么事也不做,只是空占位语句,它用于那些语法上必须要有什么语句,但程序什么也不做的场合

循环else块 :只有循环正常离开时才会执行,即

如果你从for或while循环中break终止 ,任何对应的循环else块将不执行。记住,break语句也可以在for循环中使用

编写循环的技巧
在迭代过程中修改迭代序列不安全(只有在使用链表这样的可变序列时才会有这样的情况)。如果你想要修改你迭代的序列(例如,复制选择项),你可以迭代它的复本。使用切割标识就可以很方便的做到这一点

>>> for x in a[:]: # make a slice copy of the entire list
… if len(x) > 6: a.insert(0, x)

在字典中循环时,关键字和对应的值可以使用 iteritems() 方法同时解读出来

>>> knights = {‘gallahad’: ‘the pure’, ‘robin’: ‘the brave’}
>>> for k, v in knights.iteritems():
… print k, v

gallahad the pure
robin the brave

在序列中循环时,索引位置和对应值可以使用 enumerate() 函数同时得到。

>>> for i, v in enumerate([‘tic’, ‘tac’, ‘toe’]):
… print i, v

python函数lambda表达式

python函数lambda表达式

文章目录
lambda表达式的作用
lambda的语法
lambda表达式的参数形式
无参数
一个参数
默认参数
可变参数
*args
**kwargs
lambda表达式的应用
带判断的lambda表达式
列表数据按照字典键的值排序

lambda表达式的作用
对于一种函数,只有一个返回值,并且只有一句代码。无需再按def函数定义语句书写,使用lambda表达式可以简化代码。
lambda表达式也称为匿名函数。
lambda的语法
lambda 参数列表:表达式/返回值
1
其中:参数列表可有可无,可以接收任意数量的参数,但只能返回一个值。

def fun1():
return 100
print(fun1)
print(fun1())

fun2 = lambda :100
print(fun2)
print(fun2())

<function fun1 at 0x00000213E2812EA0>
100
<function <lambda> at 0x00000213E4675A60>
100

注意fun2是一个函数名字。

练习:计算三个数的平均值

# 计算三个数的平均值
def avg(a,b,c):
return ((a+b+c)/3)
print(avg(1,2,3))

avg2 = lambda a,b,c:((a+b+c)/3)
print(avg2(1,2,3))

2.0
2.0

lambda表达式的参数形式
与函数的参数形式相同

无参数
fun = lambda :100
print(fun())

100

一个参数
fun = lambda a:a*2
print(fun(‘python’))

pythonpython

默认参数
fun = lambda a,b,c=3:((a+b+c)/3)
print(fun(1,2,3))
print(fun(1,2))

2.0
2.0

可变参数
*args
接收不定长的位置参数,返回一个元组。

fun = lambda *args:args
print(fun(10,20,30))

(10, 20, 30)

**kwargs
接收不定长的关键字参数,返回一个字典。

fun = lambda **kwargs:kwargs
print(fun(name = ‘Mary’,age=20))

{‘name’: ‘Mary’, ‘age’: 20}

注意:args和kwargs名称是可变的,但一般默认是这两个。但前面一个*号和两个 *号要注意。

lambda表达式的应用
带判断的lambda表达式
fun = lambda a,b:a if a>b else b # 表示条件成立,执行前面的;条件不成立,执行后面的。

print(fun(100,50))
print(fun(50,100))

100
100

列表数据按照字典键的值排序
student = [
{‘name’:’Mary’,’age’:20},
{‘name’:’Jone’,’age’:25},
{‘name’:’Susan’,’age’:30}
]

student.sort(key=lambda x:x[‘age’])# 按照age对应的值升序排序
print(student)

student.sort(key=lambda x:x[‘age’],reverse=True)# 按照age对应的值降序排序
print(student)

[{‘name’: ‘Mary’, ‘age’: 20}, {‘name’: ‘Jone’, ‘age’: 25}, {‘name’: ‘Susan’, ‘age’: 30}]
[{‘name’: ‘Susan’, ‘age’: 30}, {‘name’: ‘Jone’, ‘age’: 25}, {‘name’: ‘Mary’, ‘age’: 20}]
————————————————
版权声明:本文为CSDN博主「能这样吃么你说」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44870115/article/details/116331647

力扣 740. 删除并获得点数

力扣 740. 删除并获得点数

 

题目描述
给你一个整数数组 nums,你可以对它进行一些操作。

每次操作中,选择任意一个 nums[i],删除它并获得 nums[i] 的点数。之后,你必须删除每个等于 nums[i] – 1 或 nums[i] + 1 的元素。

开始你拥有 0 个点数。返回你能通过这些操作获得的*大点数。

示例 1:

输入:nums = [3,4,2]
输出:6
解释:
删除 4 获得 4 个点数,因此 3 也被删除。
之后,删除 2 获得 2 个点数。总共获得 6 个点数。

示例 2:

输入:nums = [2,2,3,3,3,4]
输出:9
解释:
删除 3 获得 3 个点数,接着要删除两个 2 和 4 。
之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。
总共获得 9 个点数。

提示:

1 <= nums.length <= 2 * 10^4
1 <= nums[i] <= 10^4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-and-earn
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

动态规划
首先分析一下题目中的操作,只要选择了某个数字 num,在获得删除它并获得相应的分值之后,同时会删除数组中的所有 num – 1 以及 num + 1。为了保证得分*高,对于剩下来的那些 num,必须要把它们选完,而且在后续选择过程中,不用删除 num – 1 以及 num + 1,因为在*次操作过程中已经删除完了。

所以对于某个数字 num,如果要选择它,那么对应的*大分值就是 num * c,其中 c 为 num 在 nums 数组中出现的次数。在 Python 语言中,可以借助 collections.Counter 来轻松完成计数工作,它本质上是一个字典。

另外,数组中元素顺序对于结果没有影响,如果我们按照从小到大的顺序考虑某个数字 num 选或者不选,那么不需要考虑 num + 1,因为在升序条件下, num + 1 还未出现。

对于数组中没有出现过的数字,为了应用状态转移方程,可以考虑成出现为 0 次,这样就不算分了。这与 collections.Counter 的工作方式一致,如果访问 Counter 中不存在的元素,会返回 0,而不会抛出 KeyError 异常。

状态定义:f[i] 为数组中数字 1 ~ i 通过操作能获取的*大分值。

状态转移:

对于数字 i,如果选(即删除并获取分值),得分为 f[i – 2] + i * c[i]
对于数字 i,如果不选(即放弃操作),的氛围 f[i – 1]
两者取*大即可
class Solution:
def deleteAndEarn(self, nums: List[int]) -> int:
from collections import Counter
c = Counter(nums)
n = max(c.keys()) + 1
f = [0, c[1]] + [0] * (n – 1)
for i in range(2, n + 1):
f[i] = max(f[i – 1], f[i – 2] + c[i] * i)
return f[-1]

运行结果:

执行结果:通过
执行用时:44 ms, 在所有 Python3 提交中击败了71.78% 的用户
内存消耗:14.8 MB, 在所有 Python3 提交中击败了96.53% 的用户

因为每个新状态只需要记录前两个状态就可以完成状态转移,所以可以使用两个变量代替 f 数组。

class Solution:
def deleteAndEarn(self, nums: List[int]) -> int:
from collections import Counter
c = Counter(nums)
n = max(c.keys()) + 1
pre = 0
cur = c[1]
for i in range(2, n + 1):
pre, cur = cur, max(cur, pre + c[i] * i)
return cur

运行结果:

执行结果:通过
执行用时:52 ms, 在所有 Python3 提交中击败了31.19% 的用户
内存消耗:15 MB, 在所有 Python3 提交中击败了61.63% 的用户

下面是 JavaScript 版本的代码:

/**
* @param {number[]} nums
* @return {number}
*/
var deleteAndEarn = function(nums) {
const max = Math.max(…nums)
const scores = new Array(max + 1).fill(0)
nums.map(num => scores[num] += num)
let pre = 0, cur = scores[1], tmp
for (let i = 2; i < scores.length; i++) {
tmp = cur
cur = Math.max(cur, pre + scores[i])
pre = tmp
}
return cur
};

运行结果:

执行结果:通过
执行用时:88 ms, 在所有 JavaScript 提交中击败了75.00% 的用户
内存消耗:39.2 MB, 在所有 JavaScript 提交中击败了83.33% 的用户

函数

函数

pta python第六周 函数
6-1 组合数据类型-1.计算坐标点欧氏距离
6-2 函数-找钱
6-3 统计字符个数
6-4 缩写词
6-1 组合数据类型-1.计算坐标点欧氏距离
读取若干个点,每个点放入元组。并将所有点的点信息、点的类型、点与原点的距离打印出来。

函数接口定义:
readPoint() #从一行以,分隔的数中读取坐标,放入元组并返回
distance(point) #计算point与原点的距离并返回,要math库中的函数
裁判测试程序样例:
/* 请在这里填写答案 */
n = int(input())
for i in range(n):
p = readPoint()
print(‘Point = {}, type = {}, distance = {:.3f}’.format(p,type(p),distance(p)))
输入格式:
输入n,代表底下要输入n行点坐标。坐标全部为整数。
点坐标x,y,z以,分隔。坐标全部为整数。

注意:坐标以,分隔,相应位置可能无字符或者包含多个空格字符,读入时按照0进行处理。

输出格式:
见输出样例

输入样例:
5
1,1,1
,,
2,,1
3,1,3
5,,
输出样例:
Point = (1, 1, 1), type = <class ‘tuple’>, distance = 1.732
Point = (0, 0, 0), type = <class ‘tuple’>, distance = 0.000
Point = (2, 0, 1), type = <class ‘tuple’>, distance = 2.236
Point = (3, 1, 3), type = <class ‘tuple’>, distance = 4.359
Point = (5, 0, 0), type = <class ‘tuple’>, distance = 5.000

import math

def readPoint():
s = input().split(“,”)
for i in range(len(s)):
try:
s[i] = eval(s[i])
if s[i] >= 0:
s[i] = int(s[i])
except(Exception):
s[i] = 0
return tuple(s)

def distance(p):
return math.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2])

n = int(input())
for i in range(n):
p = readPoint()
print(‘Point = {}, type = {}, distance = {:.3f}’.format(
p, type(p), distance(p)))
exit(0)

6-2 函数-找钱
买单时,营业员要给用户找钱。营业员手里有10元、5元、1元(假设1元为*小单位)几种面额的钞票,其希望以
尽可能少(张数)的钞票将钱换给用户。比如,需要找给用户17元,那么其需要给用户1张10元,1张5元,2张1元。
而不是给用户17张1元或者3张5元与2张1元。

函数接口定义:
giveChange(money) #money为要找的钱。经过计算,应按格式”要找的钱 = x10 + y5 + z1″输出。
裁判测试程序样例:
/ 请在这里填写答案 /
n = int(input())
for i in range(n):
giveChange(int(input()))
输入样例:
5
109
17
10
3
0
输出样例:
109 = 1010 + 15 + 41
17 = 110 + 15 + 21
10 = 110 + 05 + 01
3 = 010 + 05 + 31
0 = 010 + 05 + 01

def giveChange(money):
tp = money
x = money // 10
money -= x * 10
y = money // 5
money -= y * 5
z = money
print(“%d = %d*10 + %d*5 + %d*1” % (tp, x, y, z))

n = int(input())
for i in range(n):
giveChange(int(input()))
exit(0)

6-3 统计字符个数
编写程序统计1行字符串中:

不同字符的个数。
每种字符出现的次数。
函数接口定义:
Freq(line)
函数功能:该函数统计不同字符出现的次数,并*后按照字符升序进行输出。输出格式见输出样例。
参数说明:line为需要统计的字符串。

裁判测试程序样例:
/* 请在这里填写答案 */
line = input()
Freq(line)
输入样例:
abc 123 adex!!!
输出样例:
11
= 2
! = 3
1 = 1
2 = 1
3 = 1
a = 2
b = 1
c = 1
d = 1
e = 1
x = 1
输出格式说明:
第1行输出不同字符的个数。
**=**两边应有空格。
上述输出样例中第2行的字符是空格。
输出按照字符升序排列。

def Freq(line):
s = {}
for i in line:
s[i] = s.get(i, 0) + 1
s = list(s.items())
s.sort(key=lambda x: x[0])
print(len(s))
for i in range(len(s)):
w, c = s[i]
print(“{0} = {1}” .format(w, c))

line = input()
Freq(line)
exit(0)

6-4 缩写词
缩写词是由一个短语中每个单词的*个字母组成,均为大写。例如,CPU是短语“central processing unit”的缩写。

函数接口定义:
acronym(phrase);
phrase是短语参数,返回短语的缩写词
裁判测试程序样例:

/* 请在这里填写答案 */
phrase=input()
print(acronym(phrase))

输入样例:
central processing unit
输出样例:
CPU

def acronym(phrase):
s = phrase.split()
ans = []
for i in s:
ans.append(i[0].upper())
return “”.join(ans)

phrase = input()
print(acronym(phrase))
exit(0)