前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初学者也能快速写Python脚本啦——通用功能代码分享

初学者也能快速写Python脚本啦——通用功能代码分享

作者头像
Sidchen
发布2020-10-10 10:02:03
6540
发布2020-10-10 10:02:03
举报
文章被收录于专栏:规划领域技术规划领域技术

满打满算也算是编写了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****************************\n\n')
   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) 

就是这些了吧~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 规划人在路上 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档