马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 qiuyouzhi 于 2020-4-22 10:11 编辑
Python DEBUG 小技巧(1)
为什么要写这篇帖子?
因为论坛上的 "傻问题" 太多了!
光一个:
list1 = [1,2,3,4,5]
list2 = list1.reverse()
print(list2)
打印的结果为什么是None的问题,
就已经被问烂了!
本来,我试图搞一个Python FAQ,
结果发现根本没人看的。。。
(链接:https://fishc.com.cn/forum.php?m ... =view&ctid=1659)
我和痛心,同时,还发现一大批看报错信息就能知道的问题,
却还要发帖询问为什么。
所以,这就是这篇帖子的由来。
学会看报错信息
假设有这么一段代码:
大家是不是一眼就能看出来问题在哪里?
但是,如果改成这样:
'''
Function:
音乐下载器
Author:
Charles
微信公众号:
Charles的皮卡丘
'''
import sys
if __name__ == '__main__': from modules import *
else: from .modules import *
'''basic info'''
BASICINFO = '''************************************************************
Function: 音乐下载器 V2.1.2
Author: Charles
微信公众号: Charles的皮卡丘
操作帮助:
输入r: 重新初始化程序(即返回主菜单)
输入q: 退出程序
下载多首歌曲: 选择想要下载的歌曲时,输入{1,2,5}可同时下载第1,2,5首歌
歌曲保存路径:
当前路径下的results文件夹内
************************************************************'''
'''音乐下载器'''
class musicdl():
def __init__(self, configpath=None, config=None, **kwargs):
self.config = loadConfig('config.json') if config is None else config
self.logger_handle = Logger(self.config['logfilepath'])
self.initializeAllSources()
'''非开发人员外部调用'''
def run(self, target_srcs=None):
while True:
print(BASICINFO)
# 音乐搜索
user_input = self.dealInput('请输入歌曲搜索的关键词: ')
target_srcs = ['baiduFlac', 'kugou', 'kuwo', 'qq', 'qianqian', 'netease', 'migu', 'xiami', 'joox'] if target_srcs is None else target_srcs
search_results = self.search(user_input, target_srcs)
# 打印搜索结果
title = ['序号', '歌手', '歌名', '大小', '时长', '专辑', '来源']
items = []
records = {}
idx = 0
for key, values in search_results.items():
for value in values:
items.append([str(idx), value['singers'], value['songname'], value['filesize'], value['duration'], value['album'], value['source']])
records.update({str(idx): value})
idx += 1
printTable(title, items)
# 音乐下载
user_input = self.dealInput('请输入想要下载的音乐编号: ')
need_download_numbers = user_input.split(',')
songinfos = []
for item in need_download_numbers:
songinfo = records.get(item, '')
if songinfo: songinfos.append(songinfo)
self.download(songinfos)
'''音乐搜索'''
def search(self, keyword, target_srcs):
search_results = {}
if 'baiduFlac' in target_srcs:
try:
search_results.update({'baiduFlac': self.baiduFlac.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('baiduFlac', keyword))
if 'kugou' in target_srcs:
try:
search_results.update({'kugou': self.kugou.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('kugou', keyword))
if 'kuwo' in target_srcs:
try:
search_results.update({'kuwo': self.kuwo.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('kuwo', keyword))
if 'netease' in target_srcs:
try:
search_results.update({'netease': self.netease.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('netease', keyword))
if 'qianqian' in target_srcs:
try:
search_results.update({'qianqian': self.qianqian.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('qianqian', keyword))
if 'qq' in target_srcs:
try:
search_results.update({'qq': self.qq.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('qq', keyword))
if 'migu' in target_srcs:
try:
search_results.update({'migu': self.migu.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('migu', keyword))
if 'xiami' in target_srcs:
try:
search_results.update({'xiami': self.xiami.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('xiami', keyword))
if 'joox' in target_srcs:
try:
search_results.update({'joox': self.joox.search(keyword)})
except:
self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('joox', keyword))
return search_results
'''音乐下载'''
def download(self, songinfo):
for songinfo in songinfos:
if songinfo['source'] == 'baiduFlac':
self.baiduFlac.download([songinfo])
elif songinfo['source'] == 'kugou':
self.kugou.download([songinfo])
elif songinfo['source'] == 'kuwo':
self.kuwo.download([songinfo])
elif songinfo['source'] == 'netease':
self.netease.download([songinfo])
elif songinfo['source'] == 'qianqian':
self.qianqian.download([songinfo])
elif songinfo['source'] == 'qq':
self.qq.download([songinfo])
elif songinfo['source'] == 'migu':
self.migu.download([songinfo])
elif songinfo['source'] == 'xiami':
self.xiami.download([songinfo])
elif songinfo['source'] == 'joox':
self.joox.download([songinfo])
'''run'''
if __name__ == '__main__':
dl_client = musicdl('config.json')
dl_client.run()
(感谢Charles未晞,这是TA的代码
这里由于篇幅问题,只展示部分代码)
你在不运行的情况下,是不是很难找到错误?
这时候,就体现报错信息的重要性了:
Traceback (most recent call last):
File "C:\Users\rzzl\Desktop\Music-Downloader-master\Music-Downloader-master\musicdl\musicdl.py", line 158, in <module>
dl_client.run()
File "C:\Users\rzzl\Desktop\Music-Downloader-master\Music-Downloader-master\musicdl\musicdl.py", line 60, in run
self.download(songinfos)
File "C:\Users\rzzl\Desktop\Music-Downloader-master\Music-Downloader-master\musicdl\musicdl.py", line 112, in download
for songinfo in songinfos:
NameError: name 'songinfos' is not defined
(运行代码试试)
来分析报错信息:
1,看line,这是最有用的信息,它大多数都可以帮你定位到错误源。
2,看错误类型和错误信息,这是告诉你错误的详细内容。
可以发现,是112行的错误,直接翻到112:
for songinfo in songinfos:
发现这是整个函数的开头,于是错误就变得好找了很多,
songinfos是哪里来的呢?可以发现,是函数的一个参数。
def download(self, songinfo):
纳尼?这个参数怎么变成songinfo了?
赶紧改过来。
这时候再运行,发现没有问题了(这里鱼油
不需要自己尝试)。
这就是一次成功的DEBUG!
善用print()和DEBUG思想
有了print,你甚至可以不用调试功能!
(反正我是没有用过调试功能)
怎么做呢?
再拿一段代码例子:
from requests import get
from bs4 import BeautifulSoup as BS
def open_url(url):
headers={'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3741.400 QQBrowser/10.5.3863.400'}
res = get(url,headers=headers)
return res
def get_MovieName(res):
soup = BS(res.text, "html.parser")
# 下面这段代码等同于soup.find_all()
target = soup("div", class_='p12')
for each in target:
print(each.a.span.text)
def main():
url = 'https://movie.douban.com/chart'
res = open_url(url)
get_MovieName(res)
if __name__ == "__main__":
main()
运行一下:
诶嘿?怎么什么都没有打印出来?
理论上是可以的啊?
这时候,我们就要分析一下
有可能错误的原因:
1,get()能不能抓取到数据?
2,find_all方法的class_有没有写错?
3,确定打印的是each.a.span.text?
这时候,就需要我们的print()了:
打印一下返回的数据:
OK,打印成功,大约有1600多行,
现在已经可以初步确定,get方法没有问题了。
但保险起见,还是展开看一下(防止是错误页面)
简单扫了扫,没有问题,证明这里是正确的。
然后看第二点,class_有没有写错?
翻源代码:
<a class="nbg" href="https://movie.douban.com/subject/34805219/" title="饥饿站台">
<img src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2566870171.webp" width="75" alt="饥饿站台" class=""/>
</a>
</td>
<td valign="top">
<div class="pl2">
<a href="https://movie.douban.com/subject/34805219/" class="">
饥饿站台
/ <span style="font-size:13px;">饥饿斗室(港) / 绝命大平台(台)</span>
</a>
感觉并没有问题啊?
看看div的class,感觉是这里不对
把它复制过来:
我去,原来是pl(L)2,不是p12!
改过来之后,打印一下,成功了!
(第三点和第二点一起检查了)
3,打印所有错误类型
用这段代码:
>>> for error in dir(__builtins__)[:72]:
print(error)
4.try-except大法
这个东西可以捕获所有(貌似有一个错误捕获不到)的错误,
比如这里有一个爬虫程序,程序里面有一个for循环,
只要运行这个程序就会报错(索引超出范围),
这时我们怎么做呢?
直接把这个for循环放进try里面,然后except的时候
退出循环。
P.S:获取报错信息可以:except Errortype as reason:
当然,如果你想获取任何错误的报错信息(By zltzlt):
except BaseException as reason:
|