前言
最近和我们学校的IT社长写一个网页下载工具,今天刚更新命令行参数功能,踩了坑getopt模块中的一个坑,main.py文件完整源码如下
# coding=utf-8
import sys
import getopt
from DownloadWebPage import DownloadWebPage
# url = 'https://mbd.baidu.com/newspage/data/landingsuper?context=%7B%22nid%22%3A%22news_8912090858788091154%22%7D&n_type=0&p_from=1'
def _usage() -> str:
print("""
Download WebPage Main Program
-h,--help Display help.
-e,--encoding Set encoding for website files recoding.
-p,--path Set webpage all files main path.(Default on ./data)
-s,--static Set webpage static files path.(Default on {path}/static)
-t,--timeout Set request timeout.(Default 30sec)
Examples:
python main.py http://www.google.com
python main.py http://www.google.com -t 60
python main.py http://www.google.com --path ./website
python main.py http://www.google.com --path ./website --static /res
""")
def main(argv):
try:
opts, args = getopt.getopt(argv, "he:t:p:s:", [
"encoding=", "timeout=", "path=", "static=", ])
except getopt.GetoptError as err:
print(err)
_usage()
sys.exit()
if len(args) < 1:
print('[!!!] No url!')
sys.exit()
# assert False
else:
url = args[0]
if len(opts) < 1:
path = static = encoding = timeout = None
for opt, value in opts:
if opt in ('-h', '--help'):
_usage()
sys.exit(0)
path = value if opt in ('-p', '--path') else None
static = value if opt in ('-s', '--static') else None
encoding = value if opt in ('-e', '--encoding') else None
timeout = int(value) if opt in ('-t', '--timeout') else None
dwp = DownloadWebPage(url, path, static, encoding, timeout)
dwp.save()
# 当为主程序入口
if __name__ == '__main__':
if len(sys.argv) < 2:
_usage()
sys.exit()
main(sys.argv[1:])
以上逻辑看起来很完美(这里不得不佩服社长,代码敲的比我六)。
编码问题,意料之中
试下刚更新的命令行参数功能,加个 utf-8 完成测试
这次结果出乎意料,加了utf-8一样报错,开始各种测试(为什么不怀疑是解码的问题?因为之前的编码问题已经解决,加utf-8是可以解决的),最后发现是getopt模块的问题
开始测试getopta模块
嗯,为了不影响开发分支,单独开一个文件 test.py
源码如下
import getopt
import sys
def _usage():
print(
"""
-h,--help Help information
-d,--delete Delete file
-a,--add Add file
"""
)
def main():
opts,args = getopt.getopt(sys.argv[1:], "hd:a:", ["help","delete=","add="])
print("opts:",opts)
print("srgs:",args)
if __name__ == "__main__":
main()
大概测试了一遍,发现是参数顺序问题
getopt.getopt()
会同时返回两个列表
一个列表由参数的 "选项/值" 所组成的元组组成例如-d是删除文件按的一个选项python test.py -d test.txt -a new.txt
,处理后会返回[('-d','test.txt'), ('-a','new.txt')]
另一个列表由无选项参数组成,例如python main.py file.txt file2.txt
,处理后会返回['file.txt', 'file2.txt']
小提示:
在以下测试中 getopt.getopt()
返回的带选项的参数列表的名称为opts
返回的不带选项的参数列表为args
如果把带选项
的参数放到开头,无选项参数放到末尾,getopt运行正确
但要是反过来就要命了 从上方图片可以看到 ,getopt把
-e delete_file.txt
作为不带选项的参数来处理,这并不是我们期待的结果,说了这么多,没有解决方法不都是废话么?
解决方法
解决方法很简单,使用getopt.gnu_getopt()函数就行了。
这个函数像
getopt()
一样工作,除了默认使用GNU样式扫描模式。这意味着选项和非选项参数可以混合。一旦遇到非选项参数,getopt()
函数就停止处理选项。
如果选项字符串的第一个字符是“+”,或者如果设置了环境变量POSIXLY_CORRECT
,那么一旦遇到非选项参数,选项处理就会停止。
gun_getopt()允许参数混合,嗯。。。。光速修改替换getopt()
为 gun_getopt()
import getopt
import sys
def _usage():
print(
"""
-h,--help Help information
-d,--delete Delete file
-a,--add Add file
"""
)
def main():
# getopt() -> gun_getopt()
opts,args = getopt.gnu_getopt(sys.argv[1:], "hd:a:", ["help","delete=","add="])
print("opts:",opts)
print("srgs:",args)
if __name__ == "__main__":
main()
修改后的运行结果
哦~~ 完美
网友评论