python:實戰篇
python
- 實戰
-
§python 實戰篇 - §1、python解壓
- §2、python執行Linux系統命令的3種方法
- §3、python程式碼打包成exe安裝包
- §4、windows下:py檔案引用其他py檔案
- §5、python安裝tar.gz或whl包
- §6、anaconda包遷移
- §7、使用'utf-8'讀寫檔案。
- §8、sys.stdout.flush()重新整理輸出 ---- “時時監控”
- §9、python列表和字典的相互轉換---- 再談談對zip的理解
- §10、字典操作
- §11、多程式和多執行緒應用場景
- §12、目錄操作
- §13、python語法糖測試函式執行時間
- §14、JSON檔案處理
- §15、檢視python某個包的版本
- §16、爬蟲selenium新版本的語法變化
實戰
§python 實戰篇
§1、python解壓
1. python解壓zip、7z
(1)python解壓zip:用自帶zipfile
(2)python 解壓7z:下載py7zr, 用aliyun映象
用法:
path_name = 'C:/p/test.zip'
# 寫法1. with自動關閉法。如同with開啟檔案自動關閉。
with zipfile.ZipFile(path_name) as zip_f:
zip_f.extractall(path_name.rsplit('/', 1)[0]) # 解壓指定檔案路徑C:/p/test/下。可自定義
# 如:zip_f.extractall("C:/AI/test/out/")
# 寫法2: close()手動關閉法。
zip_f= zipfile.ZipFile(path_name)
zip_f.extractall("C:/AI/test/out/") #
zip_f.close()
例項:
import zipfile
import py7zr
def uncompress(path_name):
suffix = path_name.rsplit('.', 1)[1]
if suffix == 'zip':
if zipfile.is_zipfile(path_name):
try:
with zipfile.ZipFile(path_name) as zip_f:
zip_f.extractall(path_name.rsplit('/', 1)[0])
# os.remove(path_name) # 解壓後刪除原壓縮檔案
except Exception as e:
print('Error when uncompress file! info: ', e)
return False
else:
return True
else:
print('This is not a true zip file!)
return False
if suffix == '7z':
if py7zr.is_7zfile(path_name):
try:
with py7zr.SevenZipFile(path_name, mode='r') as sevenZ_f:
sevenZ_f.extractall(path_name.rsplit('/', 1)[0])
# os.remove(path_name)
except Exception as e:
print('Error when uncompress file! info: ', e)
return False
else:
return True
else:
print('This is not a true 7z file!')
return False
if __name__ == '__main__':
uncompress(path_name = 'C:/p/test.zip')
2. python 解壓rar
因為其他7z、zip等解壓演算法都是開源的,所以直接下包就可以解壓。
但rar未開源,故下載rarfile包後,還需要裝rar解壓軟體,然後去呼叫。
1)windows:
- (i)
pip install rarfile
或者找官方下載本地壓縮包解壓後將 rarfile.py 放在C:\Anaconda3\Lib\site-packages
下。 - (ii)下載winrar軟體,裝好後。
法(1):將unrar.exe賦值到專案執行根目錄下,我的是C:\Anaconda3
下,這樣做的目的是rarfile.py 能呼叫到。
所以下面
法(2):將rarfile.py 中的UNRAR_TOOL = "unrar"
改成你的winrar軟體安裝目錄,如我的改成UNRAR_TOOL = "C:/Program Files/WinRAR/UnRAR.exe"
,執行軟體名不區分大小寫,也可改成:
UNRAR_TOOL = "C:/Program Files/WinRAR/unrar.exe"
UNRAR_TOOL = "C:/Program Files/WinRAR/UnRAR"
UNRAR_TOOL = "C:/Program Files/WinRAR/unrar"
if rarfile.is_rarfile(path_name):
with rarfile.RarFile(path_name) as rf:
rf.extractall(path_name.rsplit('/', 1)[0])
此方法受overflow上的一篇回答啟發,參考原文:
2)linux:
(i)同樣,先將官方 rarfile.py 放在Anaconda3/Lib/site-packages
下。(有的系統是anaconda3/lib/python3.7/site-packages
)
(ii)在https://www.rarlab.com/download.htm下載 64 位 的linux版winrar,因為現在大部分linux系統是64位,注意下載的一定是64位,否則報錯。
解壓後,開啟rar資料夾,如下圖,將rar資料夾裡面的rar
二進位制程式放在python執行的根目錄下。
附1:終端執行which python
或whereis python
檢視python安裝目錄,即python執行根目錄
/home/你的使用者名稱/anaconda3/bin/python
附2:linux安裝winrar
將解壓後的rar資料夾存在任意位置,進入rar資料夾
輸入sudo make
或sudo make install
成功!有如下資訊說明已安裝:
mkdir -p /usr/local/bin
mkdir -p /usr/local/lib
cp rar unrar /usr/local/bin
cp rarfiles.lst /etc
cp default.sfx /usr/local/lib
(注:如果系統沒有安裝make命令,也可手動輸入上面的命令資訊,這些命令在解壓後的rar/makefile裡)
配圖:測試:
輸入sudo rar
會有以下資訊說明winrar安裝成功,可以使用:
RAR 5.91 Copyright (c) 1993-2020 Alexander Roshal 25 Jun 2020
Trial version Type 'rar -?' for help
Usage: rar <command> -<switch 1> -<switch N> <archive> <files...>
<@listfiles...> <path_to_extract\>
<Commands>
a Add files to archive
c Add archive comment
ch Change archive parameters
cw Write archive comment to file
(。。。省略。。。)
使用:
(1)壓縮
將test目錄下的所有檔案壓縮成1.rar:
rar a 1.rar test/
將test目錄下的所有檔案及子目錄壓縮成1.rar:
rar -r a 1.rar test/
— r 表遞迴
a 表示 Add files to archive
(2)解壓
rar x 1.rar
§2、python執行Linux系統命令的3種方法
os.system("命令")
os.popen("命令")
subprocess.call("命令")
如下:
§3、python程式碼打包成exe安裝包
(cxfreeze法):適用於python3 — 推薦使用
關於cxfreeze的介紹和使用可參考官方手冊 https://cx-freeze.readthedocs.io/en/latest/distutils.html
安裝
pip install cx-freeze
安裝,安裝後輸入 cxfreeze -h
進行檢測是否安裝成功。
打包
打包需要新建一個setup.py檔案存放打包的相關資訊。
例:
hello.py 檔案,程式碼如下:
import time
print("hello world")
time.sleep(2)
在hello.py同級目錄下新建一個setup.py檔案,程式碼如下:
# -*- coding: utf-8 -*-
from cx_Freeze import setup, Executable
executables = [
Executable('hello.py')
]
setup(
# 安裝在windows後,開啟控制皮膚-》程式-》程式和功能,會發現如下資訊。
name = 'hello',
version = '1.0', # 版本號
author = 'Ace', # 釋出者。 可省略,若省略則釋出者為“未知”
description = 'Sample cx_Freeze script',
executables = executables
)
接下來便可打包了,有兩個方法:
法1:python setup.py build
打包成免安裝的exe檔案。
法2:python setup.py bdist_msi
打包成windows下可安裝的msi檔案。
加密
打包前可將程式碼加密,使用PyArmor法加密。PyArmor 是一個用於加密和保護 Python 指令碼的工具。
關於PyArmor的介紹和使用可參考官方手冊 https://pyarmor.readthedocs.io/zh/latest/index.html
輸入 pip install pyarmor
安裝,
obfuscate 命令引數用來加密指令碼的,輸入 pyarmor obfuscate hello.py
加密 hello.py 檔案,然後 會生成 dist目錄,在dist目錄下會生成pytransform資料夾 以及 新的加密過的hello.py 檔案,同樣地,我們將setup.py放在這個加密後的hello.py下,輸入 python setup.py bdist_msi
即可打包成加密過的windows下可安裝的msi檔案。
【附】
除了cxfreeze法,還有(pyinstaller法):這個僅適用於python2
使用pyinstaller,這個是anaconda自帶,
開啟cmd命令列:
輸入pyinstaller -F test.py
即可將test.py檔案打包成exe,exe安裝包在當前目錄下的dist目錄中生成。
§4、windows下:py檔案引用其他py檔案
py檔案引用其他py檔案時,不同於linux,windows下有時會呼叫不到。
可以程式碼中將被引用的檔案新增到系統路徑裡, sys.path.append("路徑")
為其新增路徑。
例子:
t1.py:
def A():
print("sss")
t2.py:
import sys
sys.path.append("C:/test/t1.py") # 用左斜槓,或者兩個右斜槓\\, 避免轉義
import t1
def start():
t1.A()
if __name__ == '__main__':
start()
或者從工程根目錄下引用,
如工程目錄為C:/test
,其下有t1.py和t2.py,程式碼同上,若想在t2中引用t1,
則在t2中:就得寫from test import t1
或者 import test.t1
§5、python安裝tar.gz或whl包
- whl包:
pip install 包名.whl
2)tar.gz原始碼包:
先解壓,tar -xzvf 包名.tar.gz
,解壓後執行如下命令安裝:
python setup.py install
§6、anaconda包遷移
將anaconda包遷移到其他磁碟或其他電腦,需要改裡面的一些配置資訊,否則會報錯。
1)配置資訊
將如下檔案中的舊的conda安裝路徑改成新的路徑(如/home/user/anaconda3
改成/media/user/disk1/anaconda3
):
#(1)conda 與 pip
anaconda3/bin/conda
anaconda3/bin/pip
anaconda3/bin/pip3
#(2)anaconda3/etc/profile.d/下的所有指令碼
anaconda3/etc/profile.d/conda.sh
anaconda3/etc/profile.d/conda.csh
anaconda3/etc/profile.d/conda.ksh # 如果有這個檔案的話
注:改完 conda.sh要bash執行一下使生效,bash conda.sh
,然後退出終端。
2)環境變數
vim ~/.bashrc
,修改如下資訊:
export PATH="$PATH:/路徑/anaconda3/bin"
source ~/.bashrc
使更改生效。
附:
如果有conda虛擬環境的,先檢視conda安裝的虛擬環境的所在路徑:
conda env list
,然後同樣改相應的pip、pip3等。
注意:
這種遷移方法只能臨時解決大部分情況,最好還是重新安裝包。如有的需要啟動jupyter notebook,
開啟jupyter-run
檔案,原路徑#!/home/user/anaconda3/bin/python
這個就得需要改成新路徑#!/software/anaconda3/bin/python
類似這樣的檔案還有很多很多,無法全部手動改完。所以最好還是重新安裝anacoda包,再將需要的包拷貝過去。
§7、使用’utf-8’讀寫檔案。
— 解決UnicodeEncodeError: 'gbk' codec can't encode character '\u21b5' in position 90422: illegal multibyte sequence
問題
寫爬蟲時,將網路資料流寫入到本地檔案的時候,會遇到:UnicodeEncodeError: 'gbk' codec can't encode character '\u21b5' in position 90422: illegal multibyte sequence...
這個問題。我們使用了decode和encode,試遍了各種編碼,utf8,utf-8,gbk,gb2312等等,該有的編碼都試遍了,還是不好用。
原因:
windows下面,新檔案的預設編碼是gbk,
這樣的話,我們開啟檔案後,
f = open("out.html","w")
python直譯器會用gbk編碼去解析我們的網路資料流,然而此時網路資料流已經是decode過的unicode編碼,這樣的話就會導致解析不了,出現上述問題。
解決辦法:
改變winddows下目標檔案的編碼,開啟檔案:
f = open("out.html","w",encoding='utf-8')
其中 utf-8
寫成utf8
也可以哦。
§8、sys.stdout.flush()重新整理輸出 ---- “時時監控”
sys.stdout.flush()函式的作用是重新整理輸出
例子
import time
import sys
for i in range(5):
print(i, end='')
sys.stdout.flush() # 重新整理輸出。
time.sleep(1)
這個程式本意是每隔一秒輸出一個數字,但是如果把這句話sys.stdout.flush()註釋的話,就只能等到程式執行完畢,螢幕上會一次性輸出01234
。
如果你加上sys.stdout.flush(),重新整理stdout,這樣就能每隔一秒輸出一個數字了。
典型應用(下載檔案進度條顯示)
import os
from six.moves import urllib
import sys
DATA_URL = 'http://www.python.org/ftp/python/2.7.5/Python-2.7.5.tar.bz2'
filename = DATA_URL.split('/')[-1]
def _loading(block_num, block_size, total_size):
'''回撥函式(自定義)
@block_num: 已經下載的資料塊數目
@block_size: 每個資料塊的大小
@total_size: 檔案總大小
'''
if total_size < 8192:
sys.stdout.write('\r>> Downloading: 100.0%')
else:
percent = float(block_size * block_num) / float(total_size) * 100.0
if percent > 100:
percent = 100
sys.stdout.write('\r>> Downloading: %0.1f%%' % percent) # 與print類似。輸出
sys.stdout.flush()
# urllib.request.urlretrieve方法會返回一個包含兩個元素的元組(filename, headers),filename表示儲存到本地的路徑,header表示伺服器的響應頭。
filepath, _ = urllib.request.urlretrieve(url=DATA_URL, filename=filename, reporthook=_loading)
print() # 好習慣!呼叫完 _loading() 中的sys.stdout.write()記得要換行!否則:下一次sys.stdout.write()會覆蓋,下一次print會尾隨其後輸出
註釋: urllib.request.urlretrieve()函式
- 描述
urllib.request.urlretrieve(url, filename=None, reporthook=None, data=None)
- 函式說明
將URL表示的網路物件複製到本地檔案。如果URL指向本地檔案,則物件將不會被複制,除非提供檔名。返回一個元組()(filename,header),其中filename是可以找到物件的本地檔名,header是urlopen()返回的物件的info()方法(用於遠端物件)。第二個引數(如果存在)指定要複製到的檔案位置(如果沒有,該位置將是一個生成名稱的 tempfile)。第三個引數,如果存在,則是一個回撥函式,它將在建立網路連線時呼叫一次,並且在此後每個塊讀取後呼叫一次。這個回撥函式將傳遞三個引數;到目前為止傳輸的塊計數,以位元組為單位的塊大小,以及檔案的總大小。第四個引數可能是-1,在舊的FTP伺服器上,它不返回檔案大小以響應檢索請求。
- 引數說明
url:外部或者本地url
filename:指定了儲存到本地的路徑(如果未指定該引數,urllib會生成一個臨時檔案來儲存資料);
reporthook:是一個回撥函式,當連線上伺服器、以及相應的資料塊傳輸完畢的時候會觸發該回撥。我們可以利用這個回撥函式來顯示當前的下載進度。
data:指post到伺服器的資料。
- 返回值
該方法返回一個包含兩個元素的元組(filename, headers),filename表示儲存到本地的路徑,header表示伺服器的響應頭。
§9、python列表和字典的相互轉換---- 再談談對zip的理解
9.1 列表轉換為字典
例1. 如何列表 l = [‘aaa’, ‘ddd’, ‘ccc’] 轉換為字典?
由於字典屬於key-val,不妨用預設key為0,1,2… 去對應列表l
key = [0, 1, 2]
l = ['aaa', 'ddd', 'ccc']
dict_from_l = dict(zip(k , l))
print(dict_from_l)
"""
結果:{0: 'aaa', 1: 'ddd', 2: 'ccc'}
"""
例2. 如何將兩個列表 k = [‘key1’, ‘key2’, ‘key3’] 和 v = [‘val1’, ‘val2’, ‘val3’] 轉換為字典?(其中k為鍵,v為值)
k = ['key1', 'key2', 'key3']
v = ['val1', 'val2', 'val3']
dic = dict(zip(k, v))
print(dic)
"""
結果:{'key1': 'val1', 'key2': 'val2', 'key3': 'val3'}
"""
9.2 字典轉換為列表
分為兩種
1)將字典value值轉換為列表
dic = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'}
l = list(dic.values())
print(l)
"""
結果:['val1', 'val2', 'val3']
"""
2)將字典key鍵轉換為列表
dic = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'}
l = list(dic)
print(l)
"""
結果:['key1', 'key2', 'key3']
"""
9.3 對zip的理解
zip 相當於將 k, v兩個列表有順序的打包捆綁了。就像將兩條長盒綁了起來(有順序,如:一左一右)。
例:
k = ['key1', 'key2', 'key3']
v = ['val1', 'val2', 'val3']
""" 1. zip 相當於將 k, v兩個列表有順序的打包捆綁了。就像將兩條長盒綁了起來(有順序,如:一左一右)"""
for k, v in zip(k, v):
print(k, v)
""" 2. zip將k, v兩個列表打包捆綁後,一齊轉換成字典"""
dic = dict(zip(k, v))
print(dic)
§10、字典操作
10.1 追加元素
法一、鍵值對直接賦值追加
dic = {
'k1':'v1',
'k2':'v2',
}
# 根據鍵值對追加
dic['k3'] = 'v3'
print(dic)
"""
結果:
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
"""
# 根據鍵值對追加
dic['k4'] = 'v4'
print(dic)
"""
結果:
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3', 'k4': 'v4'}
可看到,前面新增的一組元素k3-v3還在,說明是追加
"""
方法二:使用update方法
dic = {
'k1':'v1',
'k2':'v2',
}
elem1 = {
'k3':'v3',
}
# 使用update方法追加一組元素
dic.update(elem1)
print(dic)
"""
結果:
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
"""
elem2 = {
'k4':'v4',
'k5':'v5'
}
# 使用update方法追加多組元素
dic.update(elem2)
print(dic)
"""
結果:
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3', 'k4': 'v4', 'k5': 'v5'}
可看到,前面新增的一組元素k3-v3還在,說明是追加
"""
10.2 刪除元素
(1)刪除單個元素
方法一:使用del函式
dic = {
'k1':'v1',
'k2':'v2',
'k3':'v3',
'k4':'v4'
}
del[dic['k4']]
print(dic)
"""
結果:
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
"""
del[dic['k3']]
print(dic)
"""
結果:
{'k1': 'v1', 'k2': 'v2'}
可看到,前面刪除的一組元素k4-v4已不在,本次刪除的k3-v3也已成功刪除
"""
方法二:使用pop函式,並返回值
dic = {
'k1':'v1',
'k2':'v2',
'k3':'v3',
'k4':'v4'
}
current_elem_v = dic.pop('k4')
print(current_elem_v) # v4,返回刪除的k4鍵對應的值v4
print(dic) # {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
"""
結果:
v4
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
"""
dic.pop('k3')
print(dic)
"""
結果:
{'k1': 'v1', 'k2': 'v2'}
可看到,前面刪除的一組元素k4-v4已不在,本次刪除的k3-v3也已成功刪除
"""
(2)刪除所有元素(清空)
方法:clear函式:清空,刪除所有
dic = {
'k1':'v1',
'k2':'v2',
'k3':'v3',
'k4':'v4'
}
dic.clear()
print(dic) # {},為空
"""
結果:
{}
"""
§11、多程式和多執行緒應用場景
先了解下GIL(Global Interpreter Lock)全域性直譯器。
作用:管理執行緒的執行的。如同鑰匙,獲得GIL鑰匙的執行緒才能執行,會把其他執行緒上鎖,保證只有一個執行緒執行。
背景:在沒有GIL之前,一般,當啟用多執行緒會造成引用計數的競爭條件,從而導致記憶體出錯。為了避免,CPython引入了GIL來管理python執行緒的執行。即:Python執行緒的執行必須先競爭到GIL許可權才能執行。
結論:無論單核還是多核CPU,任意給定時刻,只有一個執行緒會被python直譯器執行。
(這也是在多核CPU上,python中的多執行緒有時效率並不高的根本原因。)
特點:當執行緒執行過程中遇到I/O處理時,該執行緒會暫時釋放鎖。
11.1 多程式 Process
適合CPU密集型:CPU需要大量的計算佔用大量的CPU資源。
例子:計數器count
def count(n):
sum = 0
while n > 0:
sum += n
n -= 1
return sum
更適合多程式Process
11.2 多執行緒 Thread
適合I/O密集型:讀寫檔案、訪問DB、收發資料、網路連線等。
如:有3個執行緒要執行任務,執行緒1執行時獲得了GIL許可權,其他執行緒則一直在等待,但當遇到I/O處理時,執行緒1就會將GIL釋放了,從而執行緒2得到GIL,獲得執行許可權,執行緒2開始執行,如此反覆直到任務完成。
例子:延時器count
這裡同樣起名count,方便比較。
import time
def count(n):
time.sleep(0.01)
11.3 多程式 Process和多執行緒 Thread對比
例子1、計數器count:
from multiprocessing import Process
from threading import Thread
from timeit import timeit
import time
# 計數器
def count(n):
sum = 0
while n > 0:
sum += n
n -= 1
return sum
# 單執行緒方式
def test_normal():
count(1000000)
count(1000000)
# 多程式方式
def test_Process():
t1 = Process(target=count, args=(1000000, ))
t2 = Process(target=count, args=(1000000, ))
t1.start()
t2.start()
t1.join()
t2.join()
# 多執行緒方式
def test_Thread():
t1 = Thread(target=count, args=(1000000, ))
t2 = Thread(target=count, args=(1000000, ))
t1.start()
t2.start()
t1.join()
t2.join()
if __name__ == '__main__':
# 下面timeit()專門測試效率的函式。
# 用法:timeit('被測函式()', 'from 執行域 import 被測函式名', number=測試次數) # 測試number次,會取執行時間最小那次測試的值,以防止測試的時候被其他程式干擾時間不精準。
print("test_normal:", timeit('test_normal()', 'from __main__ import test_normal', number=100))
print("test_Process:", (timeit('test_Process', 'from __main__ import test_Process', number=100)))
print("test_Thread", timeit('test_Thread', 'from __main__ import test_Thread', number=100))
例子2、延時器count:
from multiprocessing import Process
from threading import Thread
from timeit import timeit
import time
# 延時器
def count():
time.sleep(0.01)
# 單執行緒方式
def test_normal():
count()
count()
# 多程式方式
def test_Process():
t1 = Process(target=count, args=())
t2 = Process(target=count, args=())
t1.start()
t2.start()
t1.join()
t2.join()
# 多執行緒方式
def test_Thread():
t1 = Thread(target=count, args=())
t2 = Thread(target=count, args=())
t1.start()
t2.start()
t1.join()
t2.join()
if __name__ == '__main__':
print("test_normal:", timeit('test_normal()', 'from __main__ import test_normal', number=100))
print("test_Process:", (timeit('test_Process', 'from __main__ import test_Process', number=100)))
print("test_Thread", timeit('test_Thread', 'from __main__ import test_Thread', number=100))
§12、目錄操作
1) 獲取當前目錄
import os
current_dir = os.path.abspath('.') # 獲取當前目錄絕對路徑。== linux “pwd”
2) 遍歷當前目錄(常用!重要!)
實戰:遍歷某個資料夾,以便處理該資料夾下的所有子資料夾和子檔案。
import os
for root, dirs, files in os.walk('test_dir'):
print(root) # 正在遍歷的資料夾(可以是,根資料夾/子資料夾)
print(dirs) # 正在遍歷的資料夾,裡面的資料夾集合
print(files) # 正在遍歷的資料夾,裡面的檔案集合
print('------------------')
例如:
展開:
執行結果:
test_dir
['1', '2']
['readme1.md', 'readme2.md']
------------------
test_dir/1
[]
['1.txt', '2.txt']
------------------
test_dir/2
[]
['1.py', '2.py']
------------------
3) 列出當前目錄下的內容、刪除目錄、刪除檔案
實戰:處理某個目錄下所有子目錄和子檔案,其中,將空目錄刪除,將沒有字尾名的檔案刪除。
import os
def deal(input_dir):
# 列出當前目錄下的內容
dir_contents = os.listdir(input_dir)
# 刪除空目錄
if dir_contents == []:
os.removedirs(input_dir)
for i in dir_contents:
path = os.path.join(input_dir, i)
# 對於目錄。遞迴處理
if os.path.isdir(path):
deal(path)
# 對於檔案。刪除無字尾名的檔案
if os.path.isfile(path) and len(path.split('.', 1)) == 1:
os.remove(path)
if __name__ == '__main__':
input_dir = '/media/user/disk_1T/AI/test/test_dir'
deal(input_dir)
§13、python語法糖測試函式執行時間
如下,先定義一個測試函式執行時間的timeit_test(func),其中func為被測函式;然後寫一個測試函式test(),要想知道test()函式的執行時間,只需要在定義函式的頂部加上前面定義好的函式@timeit_test
,這樣當呼叫test()函式的時間,就會自動呼叫這個函式timeit_test
,而且是在test()函式執行完以後自動呼叫這個函式timeit_test
。這種寫法被稱為python語法糖。這種功能可以很方便的用在函式執行效率測試上!
import time
def timeit_test(func):
"""
測試func函式的執行時間
:param func: 被測函式
:return: 函式wrapper
"""
#----- 先定義函式wrapper -----#
def wrapper(*args, **kwargs):
"""
:param args: 元組。所有傳入的實參無賦值的,如a,b 會整合到元組(a,b)
:param kwargs: 字典。所有傳入的實參有賦值的,如c=1, d=2 會整合到字典{"c":1, "d":2}
:return:
"""
"""
# time.time()精度上相對沒有那麼高,而且受系統的影響,適合表示日期時間或者大程式程式的計時。
# time.perf_counter()適合小一點的程式測試,經常用在測試程式碼時間上,精度高!具有最高的可用解析度。
"""
start = time.perf_counter()
func(*args, **kwargs)
elapsed = time.perf_counter() - start
print('Time used: ', elapsed)
#----- 再呼叫函式wrapper -----#
return wrapper
@timeit_test
def test():
sum = 0
for i in range(1000000):
sum += i
return sum
if __name__ == '__main__':
test()
"""
執行結果:
Time used: 0.0685293
"""
§14、JSON檔案處理
常用來資料預處理如股票資料等。
下面程式碼摘自我業餘開發的程式中的部分程式碼。
未經處理的原json檔案資料為
{"rc":0,"rt":6,"svr":181669432,"lt":1,"full":1,"data":{"total":3781,"diff":[{"f2":55.15,"f12":"300792","f13":0,"f14":"N壹網"},{"f2":3.17,"f12":"002504","f13":0,"f14":"弘高創意"},{"f2":5.91,"f12":"002699","f13":0,"f14":"美盛文化"},{"f2":13.04,"f12":"600363","f13":1,"f14":"聯創光電"},{"f2":18.65,"f12":"603933","f13":1,"f14":"睿能科技"},{"f2":7.46,"f12":"002581","f13":0,"f14":"未名醫藥"},{"f2":8.23,"f12":"002152","f13":0,"f14":"廣電運通"},{"f2":9.66,"f12":"002326","f13":0,"f14":"永太科技"},{"f2":24.26,"f12":"300576","f13":0,"f14":"容大感光"},{"f2":21.52,"f12":"300380","f13":0,"f14":"安碩資訊"},
......(此處省略10000行)
......
記錄下我的處理過程:
(i)clean_jsonData.py
import json
with open('all_stock_list_initData_bak.json', 'r', encoding='gbk') as fs:
content = json.load(fs)
print(content)
core_info = content['data']['diff']
all_stock_dic = {}
for item in core_info:
stock_code = item['f12']
stock_name = item['f14']
all_stock_dic[stock_code] = stock_name
print(all_stock_dic)
# # 儲存法1(不推薦):將dict轉化為str儲存到json檔案中
# all_stock_str = str(all_stock_dic)
# print(all_stock_str)
# with open('all_stock_list.json', 'w', encoding='utf8') as fs:
# fs.write(all_stock_str)
# 儲存法2(推薦):將dict以json方式儲存到json檔案中
with open('../all_stock_list.json', 'w', encoding='utf8') as fs:
"""
indent=4 為了格式化美觀。
ensure_ascii=False為了不讓中文變成ascii碼
"""
fs.write(json.dumps(all_stock_dic, indent=4, ensure_ascii=False))
(ii)deal_jsonData.py
import json
with open('../all_stock_list.json', 'r', encoding='utf8') as fs:
all_stock_dic = json.load(fs)
print(all_stock_dic)
# 將all_stock_dic的鍵值翻轉。存放在all_stock_reverse_dic
all_stock_reverse_dic = {}
for key in all_stock_dic:
all_stock_reverse_dic[all_stock_dic[key]] = key
print(all_stock_reverse_dic)
# 儲存
with open('../all_stock_list_reverse.json', 'w', encoding='utf8') as fs:
fs.write(json.dumps(all_stock_reverse_dic, indent=4, ensure_ascii=False))
§15、檢視python某個包的版本
如檢視selenium包的版本
法1(推薦)------ pip show 包名
終端直接輸入:
pip show selenium
法2 ------- py程式碼:help(包名)
終端輸入python
進入python環境,輸入如下程式碼:
import selenium
help(selenium)
§16、爬蟲selenium新版本的語法變化
新版selenium如4.1.3+ 用法有變化。
實戰
先貼上一個我預設自動化訪問(爬取)百度的程式碼:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup as bs
import re
import urllib.parse # url中文處理
import random
import time
def get_headers():
user_agents = ['Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11',
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0",
"Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0) like Gecko",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11",
"Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
"Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
"Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
"Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
"Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
"Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
"Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+",
"Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0",
"Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)",
"UCWEB7.0.2.37/28/999",
"NOKIA5700/ UCWEB7.0.2.37/28/999",
"Openwave/ UCWEB7.0.2.37/28/999",
"Mozilla/4.0 (compatible; MSIE 6.0; ) Opera/UCWEB7.0.2.37/28/999",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)",
"Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; Trident/5.0)",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1)",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"
]
header = random.choice(user_agents)
return header
def auto_access_internet():
header = get_headers()
chrome_options = Options()
# chrome_options.add_argument('--headless')
chrome_options.add_argument('user-agent=' + header)
driver = webdriver.Chrome(
options=chrome_options,
# 舊版用 chrome_options=chrome_options
service=Service(executable_path=r'/software/anaconda3/lib/python3.7/site-packages/scripts/chromedriver'),
# 舊版用 executable_path=r'/software/anaconda3/lib/python3.7/site-packages/scripts/chromedriver'
)
driver.get('https://www.baidu.com')
time.sleep(3)
driver.maximize_window()
time.sleep(4)
"""
新版selenium不支援PhantomJS了,可以安裝舊版selenium: pip uninstall selenium 再pip install selenium==2.48.0
新版selenium不建議用find_element_by_id、find_element_by_class_name等,而用如下代替:
• find_element(By.ID,”loginName”)
• find_element(By.NAME,”SubjectName”)
• find_element(By.CLASS_NAME,”u-btn-levred”)
• find_element(By.TAG_NAME,”input”)
• find_element(By.LINK_TEXT,”退出”)
• find_element(By.PARTIAL_LINK_TEXT,”退”)
• find_element(By.XPATH,”.//*[@id=’Title”)
• find_element(By.CSS_SELECTOR,”[type=submit]”)
"""
driver.find_element(By.ID, 'kw').send_keys('python')
# 舊版用 driver.find_element_by_id('kw').send_keys('python')
time.sleep(1)
s = driver.find_element(By.ID, 'su')
# 舊版用 s = driver.find_element_by_id('su')
print(s)
s.click()
time.sleep(3)
a = driver.find_element(By.CLASS_NAME, 'wbrjf67')
# 舊版用 a = driver.find_element_by_class_name("wbrjf67")
time.sleep(1)
print(a)
a.click()
time.sleep(2)
driver.quit()
if __name__ == '__main__':
auto_access_internet()
1) 新版呼叫chrome用法有變化
例如:
from selenium.webdriver.chrome.service import Service
chrome_options = Options()
# chrome_options.add_argument('--headless')
chrome_options.add_argument('user-agent=' + header)
driver = webdriver.Chrome(
options=chrome_options,
# 舊版用 chrome_options=chrome_options
service=Service(executable_path=r'/software/anaconda3/lib/python3.7/site-packages/scripts/chromedriver'),
# 舊版用 executable_path=r'/software/anaconda3/lib/python3.7/site-packages/scripts/chromedriver'
)
完整程式碼:
2) 新版selenium不建議用find_element_by_id、find_element_by_class_name等,而用如下代替:
• find_element(By.ID,”loginName”)
• find_element(By.NAME,”SubjectName”)
• find_element(By.CLASS_NAME,”u-btn-levred”)
• find_element(By.TAG_NAME,”input”)
• find_element(By.LINK_TEXT,”退出”)
• find_element(By.PARTIAL_LINK_TEXT,”退”)
• find_element(By.XPATH,”.//*[@id=’Title”)
• find_element(By.CSS_SELECTOR,”[type=submit]”)
例如:
from selenium.webdriver.common.by import By
driver.find_element(By.ID, 'kw').send_keys('python')
# 舊版用 driver.find_element_by_id('kw').send_keys('python')
如果不想用selenium的新語法,在安裝的時候注意要選擇低版本,如:
pip uninstall selenium
pip install selenium==3.11.0
另外,新版selenium如4.1.3+ 不再支援PhantomJS了,當然還是一直推薦用谷歌chrome。
相關文章
- python基礎篇實戰Python
- 「docker實戰篇」python的docker爬蟲技術-pythonDockerPython爬蟲
- Python爬蟲入門實戰之貓眼電影資料抓取(實戰篇)Python爬蟲
- Sentinel 實戰-限流篇
- 實戰篇——CSRF漏洞pikachu靶場實戰
- DDD實戰課(實戰篇)--學習筆記筆記
- Sentinel 實戰-控制檯篇
- Susy 2 教程 — 實戰篇
- 機器學習實戰之開篇機器學習
- Flutter實戰之動畫實現篇Flutter動畫
- LSMT 實戰-pythonPython
- Flutter實戰之路由功能篇Flutter路由
- Linux 企業實戰篇Linux
- Java 8 Stream之實戰篇Java
- JqueryUI實戰操作 按鈕篇jQueryUI
- Systemd 入門教程:實戰篇
- Ant實戰篇 (一)(3) (轉)
- Ant實戰篇 (一)(4) (轉)
- Python - Kaggle實戰篇1- 為什麼選擇KagglePython
- Python - 函式實戰Python函式
- python實戰專案Python
- Python開發實戰Python
- python機器學習實戰(二)Python機器學習
- Python 爬蟲實戰Python爬蟲
- Flutter實戰之畫布使用篇Flutter
- Flutter實戰之基本佈局篇Flutter
- Flutter實戰之手勢基礎篇Flutter
- iOS 元件化實戰篇(私有庫)iOS元件化
- JVM效能調優與實戰篇JVM
- DirectShow之介面實戰篇(一) (轉)
- DirectShow之介面實戰篇(二) (轉)
- DirectShow之介面實戰篇(三) (轉)
- 實戰篇——檔案包含漏洞一
- Flutter完整開發實戰詳解(二、快速開發實戰篇)Flutter
- 「docker實戰篇」python的docker- 多裝置端併發抓取抖DockerPython
- iOS窺探KVO底層實現實戰篇iOS
- Python | 資料分析實戰ⅠPython
- python實戰GUI介面+mysqlPythonGUIMySql