subprocess, re模塊,logging, 包等使用方法
'''
subprocess:
sub: 子
process: 進程
能夠經過python代碼給操做系統終端發送命令,而且能夠返回結果
'''
import subprocess
while True:
#一、讓用戶輸入終端命令
cmd_str = input('請輸入終端命令:').strip()
#Popen(cmd命令,shell=True,
# stdout=subprocess.PIPE,stderr=subprocess.PIPE)
#調用Popen就會將用戶的終端命令傳給本地的操做系統終端
#而且會獲得一個對象,對象中包含着正確或錯誤的結果
obj = subprocess.Popen(cmd_str, shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
success = obj.stdout.read().decode('gbk')
#中國windows的操做系統默認是中文,因此需轉成gbk
if success:
print(success, '正確的結果')
error = obj.stderr.read().decode('gbk')
if error:
print(error, '錯誤的結果')
'''
請輸入終端命令:dir
驅動器 D 中的卷是 新加捲
卷的序列號是 38A2-829E
D:\python的pycharm\正式課\day17 的目錄
2019/11/19 14:33 <DIR> .
2019/11/19 14:33 <DIR> ..
2019/11/19 14:33 947 subprocess模塊.py
2019/11/19 08:09 459 日考.py
2 個文件 1,406 字節
2 個目錄 132,886,355,968 可用字節
正確的結果
請輸入終端命令:yafeng
'yafeng' 不是內部或外部命令,也不是可運行的程序
或批處理文件。
'''
'''
奪命三問:
一、什麼是正則表達式與re模塊?
-正則表達式:
-正則表達式是一門獨立的技術,任何;語言均可以使用正則表達式
-正則表達式是由一堆特殊的字符組合而來
-re模塊
在python中,若想要使用正則表達式,必須經過re模塊使用
二、爲何要使用正則?
-好比要獲取'一堆字符串'中的'某些字符',正則表達式能夠幫咱們過濾,
-並提取想要的字符串數據,好比從'afahafkfyafeng666'中獲取'yafeng666'
-應用場景:
-爬蟲:re,bs4,xpath,selector
-數據分析過濾數據:re,pandas,numpy
-用戶名與密碼手機認證:檢測輸入內容的合法性
三、如何使用?
-import re
- 字符組:
- [0-9] 能夠匹配到一個0-9的字符
- [9-0]: 報錯, 必須從小到大
- [a-z]: 從小寫的a-z
- [A-Z]: 從大寫A-Z
- [z-A]: 錯誤, 只能從小到大,根據ascii表來匹配大小。
- [A-z]: 總大寫的A到小寫的z。
注意: 順序必需要按照ASCII碼數值的順序編寫。
'''
'''
- 元字符:
*******根據博客的表格來記 (看一眼)
https://images2015.cnblogs.com/blog/1036857/201705/1036857-20170529203214461-666088398.png
- 組合使用
- \w\W: 匹配字母數字下劃線與非字母數字下劃線,匹配全部。
- \d\D: 不管是數字或者非數字均可以匹配。
- \t: table
- \n: 換行
- \b: 匹配單詞結尾,tank jasonk
- ^: startswith
- '^'在外面使用: 表示開頭。
- [^]: 表示取反的意思。
- $: endswith
- ^$: 配合使用叫作精準匹配,如何限制一個字符串的長度或者內容。
- |: 或。ab|abc若是第一個條件成立,則abc不會執行,怎麼解決,針對這種狀況把長的寫在前面就行了,必定要將長的放在前面。
- [^...]: 表示取反的意思。
- [^ab]: 表明只去ab之外的字符。
- [^a-z]: 取a-z之外的字符。
'''
'''
re模塊三種比較重要的方法:
- findall(): ----> []
能夠匹配 "全部字符" ,拿到返回的結果,返回的結果是一個列表。
'awfwaghowiahioawhio' # a
['a', 'a', 'a', 'a']
- search():----> obj ----> obj.group()
'awfwaghowiahioawhio' # a
在匹配一個字符成功後,拿到結果後結束,不日後匹配。
'a'
- match():----> obj ----> obj.group()
'awfwaghowiahioawhio' # a
'a'
'wfwaghowiahioawhio' # a
None
從匹配字符的開頭匹配,若開頭不是想要的內容,則返回None。
'''
![](https://img2018.cnblogs.com/blog/1843751/201911/1843751-20191119193657126-368101467.png)
![](https://img2018.cnblogs.com/blog/1843751/201911/1843751-20191119193714291-753474729.png)
#re校驗手機號碼的合法性
# 需求: 11位、開頭13/15/17開頭
# import re
# while True:
# phone_number = input('請輸入您的號碼:').strip()
# # 需求: 11位、開頭13/15/19
# # # 參數1: 正則表達式 ''
# # # 參數2: 須要過濾的字符串
# # # ^: 表明「開頭」
# # # $: 表明「結束」
# # # |: 表明「或」
# # # (13|14): 能夠獲取一個值,判斷是不是13或14.
# # # {9}: 須要獲取9個值 限制數量
# # # []: 分組限制取值範圍
# # # [0-9]: 限制只能獲取0——9的某一個字符。
# if re.match('^(13)|(15)|(19)[0-9]{9}$', phone_number):
# print('該號碼合法')
# break
# else:
# print('該號碼不合法')
#>>>請輸入您的號碼:13012345678
#>>>該號碼合法
#請輸入您的號碼:161234456789
#>>>該號碼不合法
#match的用法
import re
str1 = 'abcdefgyafeng666'
res = re.match('[A-z0-9]', str1)
print(res)
#>>><re.Match object; span=(0, 1), match='a'>
print(res.group()) #只能獲取一個值
#>>>a
#findall的用法
res = re.findall('[a-z0-9]{7}', str1)
print(res) #能夠獲取多個值
#>>>['abcdefg', 'yafeng6']
#search的用法
res = re.search('[a-y6-7]', str1)
print(res.group()) #只能獲取一個值
#>>>a
'''
爬取豆瓣TOP250電影信息
第1頁:
https://movie.douban.com/top250?start=0&filter=
...
第9頁:
https://movie.douban.com/top250?start=200&filter=
第10頁:
https://movie.douban.com/top250?start=225&filter=
爬蟲四部原理:
1.發送請求: requests
2.獲取響應數據: 對方機器直接返回的
3.解析並提取想要的數據: re
4.保存提取後的數據: with open()
爬蟲三部曲:
1.發送請求
2.解析數據
3.保存數據
# 往10個連接發送請求獲取響應數據
- requests模塊 ---》 請求庫
'''
import requests
import re
# 爬蟲三部曲
# 一、發送請求
def get_page(url):
response = requests.get(url)
# response.content#獲取二進制數據流,好比圖片,視頻
# response.text#獲取響應文本,好比HTML代碼
return response
# 僞代碼:
# response = get_page('url地址')
# parser_page(response.text)
# 二、解析數據
def parse_page(text):
# re.findall('正則表達式', '過濾的文本')
'''
'<div class="item">.*?<a href="(.*?)">.*?<span class="title">(.*?)</span>.*?<span class="rating_num".*?>(.*?)</span>.*?<span>(.*?)人評價'
:param text:
:return:
'''
res_list = re.findall(
'<div class="item">.*?<a href="(.*?)">.*?<span class="title">(.*?)</span>.*?<span class="rating_num".*?>(.*?)</span>.*?<span>(.*?)人評價'
, text, re.S) ## response.text
for movie_tuple in res_list:
yield movie_tuple
# 三、保存數據
# 僞代碼:
# res_list = parser_page(text)
# save_data(res_list)
def save_data(res_list_iter):
with open('douban.txt', 'a', encoding='utf-8')as f:
for movie_tuple in res_list_iter:
movie_url, movie_name, movie_point, movie_num = movie_tuple
# 寫入文件
str1 = f'''
電影地址:{movie_url}
電影名字:{movie_name}
電影評分:{movie_point}
評價人數:{movie_num}'''
f.write(str1)
# 獲取10個鏈接
n = 0
for line in range(10):
url = f'https://movie.douban.com/top250?start={n}&filter='
n += 25
print(url)
response = get_page(url)
res_list_iter = parse_page(response.text)
# print(res_list)
save_data(res_list_iter)
# logging的配置信息
"""
logging配置
"""
import os
import logging.config
# 定義三種日誌輸出格式 開始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' #其中name爲getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
# 定義日誌輸出格式 結束
# ****************注意1: log文件的目錄
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
logfile_dir = os.path.join(BASE_PATH, 'log_dir')
# print(logfile_dir)
# ****************注意2: log文件名
logfile_name = 'user.log'
# 若是不存在定義的日誌目錄就建立一個
if not os.path.isdir(logfile_dir):
os.mkdir(logfile_dir)
# log文件的全路徑
logfile_path = os.path.join(logfile_dir, logfile_name)
# ****************注意3: log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {},
'handlers': {
#打印到終端的日誌
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
# 打印到文件的日誌,收集info及以上的日誌
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日誌文件
'maxBytes': 1024*1024*5, # 日誌大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日誌文件的編碼,不再用擔憂中文log亂碼了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)傳遞
},
},
}
# 注意4:
def get_logger(user_type):
# 1.加載log配置字典到logging模塊的配置中
logging.config.dictConfig(LOGGING_DIC)
# 2.獲取日誌對象
# logger = logging.getLogger('user')
# logger = logging.getLogger('bank')
# logger = logging.getLogger('shop')
logger = logging.getLogger(user_type)
return logger
# logging.config.dictConfig(LOGGING_DIC)
# # 調用獲取日誌函數的到日誌對象
# logger = logging.getLogger('user')
# 經過logger日誌對象,調用內部的日誌打印
logger = get_logger('user')
# '只要思想不滑坡,方法總比問題多!'就是須要記錄的日誌信息
logger.info('學習不要浮躁,一步一個腳印!')
logger.info('只要思想不滑坡,方法總比問題多!')
def func():
print('from test1.func...')
# func()
# __name__屬於模塊名稱空間中的一個名字
# 當咱們執行該模塊時就會產生
print(__name__) # 在當前文件中名字爲:__main__ 被導入時: 模塊的名字
# 注意: 記住--》 main + 回車鍵
if __name__ == '__main__':
print('在當前模塊下執行功能')
func()
else:
print('當前模塊已被導入')
5.包的理論
- 奪命三問:
1.什麼是包?
包是一個帶有__init__.py的文件夾,包也能夠被導入,
而且能夠一併導入包下的全部模塊。
2.爲何要使用包?
包能夠幫咱們管理模塊,在包中有一個__init__.py, 由它來幫咱們管理模塊。
3.怎麼使用包?
- import 包.模塊名
包.模塊.名字
- from 包 import 模塊名
- from 包.模塊名 import 模塊中的名字
- 導入包時發生的事情:
1.當包被導入時,會以包中的__init__.py來產生一個名稱空間。
2.而後執行__init__.py文件, 會將__init__.py中的全部名字添加到名稱空間中。
3.接着會將包下全部的模塊的名字加載到__init__.py產生的名稱空間中。
4.導入的模塊指向的名稱空間其實就是__init__.py產生的名稱空間中。