初学者也能快速写Python脚本啦——通用功能代码分享
满打满算也算是编写了5个应用场景的Python脚本,其实做的工作大多是从高德地图那里“偷”数据(对不起,高德)。编写今天这个“GetDistance”的脚本的时候,发觉,其实有很多操作是通用的,比如交互式输入、请求数据、储存数据为Excel表格等等,所以编的过程中整理了一下,把它们都做成自定义函数,方便后期调用。
*如果你对Python一无所知,或者阅读本文时遇到任何不懂得,我建议你后台回复“规划人简单学编程”获取学习笔记
从网络上“偷”数据(真的超级简单)的思路,大体是
确认需求(要怎么偷) → 确定入口(从哪里偷,url [+key]) → 请求网页(开始偷) → 剥离目标数据(挑值钱的) → 保存数据(快,藏起来!) → 结束程序(大声喊出来:偷完了)
(如果网页有防爬虫机制(上锁了,或者像古灵阁那样有复制咒防卫),就另说了)
01 删除上次的保存路径
防止重复写入数据(p是文件路径)
# recreate a file
def file_delete(p):
if os.path.exists(p):
print('检测到"{}"文件夹,为避免重复写入数据将自动删除'.format(p))
try:
shutil.rmtree(p)
except:
input('{}文件夹下可能有打开的文件,请关闭后再运行程序,任意键退出'.format(p))
exit()
if not os.path.exists(p):
os.makedirs(p)
02 确认基础文件
获取哪些数据的“哪些”(p是文件路径)
# file must existence
def exist(p):
if not os.path.exists(p):
input('"{}"文件不存在,请确认,任意键退出'.format(p))
exit()
03 读取本地的Excel表格
确认存在后,就开始读取了(p文件路径, c表格列数确认(最简单的确认,不过还是不敢保证数据是合乎要求的,也就是说还是存在程序执行中遇错自动退出的情况), f用于储存读取内容的list)
# open a xlsx file and read data
def excel_read(p, c, f):
exist(p)
data = xlrd.open_workbook(p)
table = data.sheets()[0]
lines = table.nrows
cols = table.ncols
if cols != c:
input('"{}"文件格式不正确,请确认,任意键退出'.format(p))
exit()
for i in range(lines - 1):
f.append(table.row_values(i + 1))
return
04 检查key的有效性
开放API类数据的获取(p是文件路径)
# check key
def key_check(p):
print('正在读取"{}"文件(高德web服务端API接口)'.format(p))
exist(p)
k= open(p, 'r', encoding='utf-8')
key = k.read()
if len(key) == 0:
input('key.txt为空')
exit()
#这一步是为了检查key是否有效,region_find是另一个自定义函数,后面需要替换
info = region_find(118.779425, 32.055004, key)[1]
if info != 'OK':
input('key出错,原因:{}'.format(info))
exit()
print('Key读取成功,确认有效!')
return key
05 获取坐标点的行政区名称
高德的API(lgt经度, lat纬度, k密匙)
# define administrative region
def region_find(lgt, lat, k):
url ='https://restapi.amap.com/v3/geocode/regeo?location={},{}&key={}'.format(lgt,lat, k)
# get_data是另一个自定义函数,用于打开url,返回数据(info是url是否获取成功的提示)
data, info = get_data(url, 'region')
region = ''
if info.upper() == 'OK':
rg = data['regeocode']['addressComponent']
# municipality has no city part and county has no district part
region = (str(rg['province']) + str(rg['city']) +str(rg['district'])).replace('[]', '')
else:
print('行政区域识别失败,原因:{}'.format(info))
return region, info
06 打开url获取数据
数据获取的第一步
# request data from internet
def get_data(u, m):
#avoid key limitation
time.sleep(1)
data =json.loads(request.urlopen(u).read())
# 这里是基于高德的开发文档定制的部分
if m == 'bicycling':
m = 'errmsg'
else:
m = 'info'
return data, data[m]
07 交互式输入的检查
有时候我们需要根据程序使用者的输入,定制个性化的数据获取方案(must_in输入的必须是哪些, l最大输入长度, f用于储存有效输入的list-需要在主程序中定义)
# interaction check
def input_check(must_in, l, f):
#three chances
for i in range(4):
if i == 3:
input('请重新运行脚本,任意键退出')
exit()
r = input()
# numbers limit
if len(r) == 0:
print('输入值为空,剩余输入次数为:', (2 - i))
continue
elif len(r) > l:
print('输入值超出限制,剩余输入次数为:', (2 - i))
continue
else:
rr = r.split(',')
# avoid same number
g = 'out'
rrr = set()
for j in rr:
# must fit the set mode
for k in must_in:
if int(j) == k:
g = 'in'
rrr.add(j)
break
else:
g = 'out'
if g == 'out':
print('输入错误,剩余输入次数为:', (2 - i))
continue
else:
for m in rrr:
f.append(m)
break
08 合并两个列表的数据
我习惯于把剥离的目标数据先储存在数组中,如果有多个目标数据组,那么可能是这样的,组1:[(1, 1), (2, 2],组2:[(1, 1), (2, 2)]……为方便最终的数组写入Excel,还是要把数据组的数据合并在一个里面,组:[(1, 1,1, 1, ……), (2, 2, 2, 2, ……), ……]
仅支持两两合并,多于两组的可以重复多次操作(ls1组1, ls2组2, ls3合并组需在主程序先定义)
# combine data from two lists which hassame length but contains tuple and the like
def list_combine(ls1, ls2, ls3):
for k in range(len(ls1)):
ex = []
for i in ls1[k]:
ex.append(i)
for j in ls2[k]:
ex.append(j)
ls3.append(ex)
09 将数据写入Excel
(ph文件保存路径, data需要写入的数据所在的list)
# create a table and write in data
def excel_write(ph, data):
table = xlsxwriter.Workbook(ph)
sheet = table.add_worksheet('sheet1')
#write head
sheet.write(0, 0, 'ID')
for k in range(len(data[0])):
sheet.write(0, k + 1, data[0][k])
#write data
for i in range(len(data) - 1):
# write ID column
sheet.write(i + 1, 0, i + 1)
for j in range(len(data[i + 1])):
try:
sheet.write(i + 1, j + 1,data[i + 1][j])
except:
sheet.write(i + 1, j + 1,str(data[i + 1][j]))
table.close()
print('###save as ' + ph)
10 结束程序的提示
挺清晰、美丽的提示
# end remark
def end():
print('n'
'n****************************'
'n*数据已全部获取,任意键退出*'
'n****************************nn')
input()
exit()
11 坐标转换脚本
转换总是不太准确的,但是都大体能用(代码来自网络,涵盖百度坐标系、GCJ-02坐标系、WGS-84坐标系;传入的参数为经度,纬度)
def bd09togcj02(bd_lon, bd_lat):
x_pi = 3.14159265358979324 * 3000.0 / 180.0
x= bd_lon - 0.0065
y= bd_lat - 0.006
z= math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
gg_lng = z * math.cos(theta)
gg_lat = z * math.sin(theta)
#minus based on test
return [gg_lng-0.012, gg_lat-0.012]
def gcj02tobd09(lng, lat):
x_PI = 3.14159265358979324 * 3000.0 / 180.0
z= math.sqrt(lng * lng + lat * lat) + 0.00002 * math.sin(lat * x_PI)
theta = math.atan2(lat, lng) + 0.000003 * math.cos(lng * x_PI)
bd_lng = z * math.cos(theta) + 0.0065
bd_lat = z * math.sin(theta) + 0.006
#minus based on test
return [bd_lng-0.006264, bd_lat-0.001279]
def wgs84togcj02(lng, lat):
PI = 3.1415926535897932384626
ee = 0.00669342162296594323
a= 6378245.0
dlat = transformlat(lng - 105.0, lat - 35.0)
dlng = transformlng(lng - 105.0, lat - 35.0)
radlat = lat / 180.0 * PI
magic = math.sin(radlat)
magic = 1 - ee * magic * magic
sqrtmagic = math.sqrt(magic)
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * PI)
mglat = lat + dlat
mglng = lng + dlng
return [mglng, mglat]
def gcj02towgs84(lng,lat):
PI = 3.1415926535897932384626
ee = 0.00669342162296594323
a= 6378245.0
dlat = transformlat(lng - 105.0, lat - 35.0)
dlng = transformlng(lng - 105.0, lat - 35.0)
radlat = lat / 180.0 * PI
magic = math.sin(radlat)
magic = 1 - ee * magic * magic
sqrtmagic = math.sqrt(magic)
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * PI)
mglat = lat + dlat
mglng = lng + dlng
return [str(lng * 2 - mglng), str(lat * 2 - mglat)]
def transformlat(lng, lat):
PI = 3.1415926535897932384626
ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat *
lat + 0.1 * lng * lat + 0.2 * math.sqrt(abs(lng))
ret += (20.0 * math.sin(6.0 * lng * PI) + 20.0 *
math.sin(2.0 * lng * PI)) * 2.0 / 3.0
ret += (20.0 * math.sin(lat * PI) + 40.0 *
math.sin(lat / 3.0 * PI)) * 2.0 / 3.0
ret += (160.0 * math.sin(lat / 12.0 * PI) + 320 *
math.sin(lat * PI / 30.0)) * 2.0 / 3.0
return ret
def transformlng(lng, lat):
PI = 3.1415926535897932384626
ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng +
0.1 * lng * lat + 0.1 * math.sqrt(abs(lng))
ret += (20.0 * math.sin(6.0 * lng * PI) + 20.0 *
math.sin(2.0 * lng * PI)) * 2.0 / 3.0
ret += (20.0 * math.sin(lng * PI) + 40.0 *
math.sin(lng / 3.0 * PI)) *2.0 / 3.0
ret += (150.0 * math.sin(lng / 12.0 * PI) + 300.0 *
math.sin(lng / 30.0 * PI)) * 2.0 / 3.0
return ret
def bd09towgs84(lng, lat):
lng1, lat1 = bd09togcj02(lng, lat)
return gcj02towgs84(lng1, lat1)
def wgs84tobd09(lng, lat):
lng1, lat1 = wgs84togcj02(lng, lat)
return gcj02tobd09(lng1, lat1)
就是这些了吧~
- J2EE相关总结
- (53) 剖析Collections - 算法 / 计算机程序的思维逻辑
- Flask使用Blueprint进行多模块应用的编写
- 优雅的在终端中编写Python
- Eclipse相关问题
- (54) 剖析Collections - 设计模式 / 计算机程序的思维逻辑
- Django 博客教程(三):创建应用和编写数据库模型
- package-info.java文件详解
- 在Spring下集成ActiveMQ
- Java中只有按值传递,没有按引用传递!
- 我是如何使用Python来自动化我的婚礼的
- left join 过滤条件写在on后面和写在where 后面的区别
- 如何在大量jar包中搜索特定字符
- sql自连接经典示例
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 一日一技:更友好的格式化数据提取方案
- 『深度应用』YoloV5 RTX2080Ti TensorRT与PyTorch速度对比
- 0797-使用HDP或CDP的Atlas采集CDH6的元数据和血缘
- 现代通信理论与新技术 PPT笔记整理
- 找找规律——LeetCode题目6:Z字形变换
- 给你点信心——LeetCode题目7:整数反转
- Python -二叉树 创建与遍历算法(很详细,转自国外教程)
- APP流量来源追踪方式——Android篇
- 从浏览器输入网址回车到看到页面过程到底经历了什么?
- Flutter Bloc 官方文档(BlocBuilder翻译)
- OpenGL ES 3.0 | 统一变量和属性的概念与(在程序中的)获取流程、统一变量缓冲区对象详解、std140块规范、用 命名统一变量块 建立 统一变量缓冲区对象 的流程 和 相关API 和...
- 深入浅出SVM(PART III)
- 高频原题——LeetCode题目8:字符串转换整数 (atoi)
- 不转字符串判断——LeetCode题目9:回文数
- 关于双指针的简单理解