最近在学习arcpy,参考官方帮助文档及一些博客文章练习了下利用python脚本自动发布各中server服务,顺便将把发布的流程以及遇到的问题进行记录总结。用的是Python2.x,ArcGIS Pro中用的是Python3.x,这两个版本还是有一些差异。本篇先整理了下基于ArcMap利用python脚本自动发布各类服务。作为初学者能力有限,如果文章中有不正确的地方欢迎大家及时指出。
一、发布动态地图服务:
1、首先使用arcpy函数CreateGISServerConnectionFile()(在arcpy.mapping模块中)创建连接到 server服务器的连接文件。
2、使用arcpy.mapping中的CreateMapSDDraft()函数将mxd地图文档转换为服务定义草稿文件(.sddraft),sddraft文件由地图文档、服务器信息和一组服务属性组成。另外可以使用AnalyzeForSD()函数分析.sddraft文件可能存在的错误、警告和消息,以便在将服务定义草稿文件转换为sd文件之前解决潜在的问题。
****发布时注册或复制数据的问题:
在发布时如果选择注册数据(包括文件夹和数据库),可以选择手动去arcmap中或者 server manager进行注册,也可以通过脚本的方式完成注册。使用AddDataStoreItem()将文件夹或数据库注册到 ArcGIS Server 站点中,在注册之前也可以先使用ListDataStoreItems()函数返回在 ArcGIS Server 站点中注册的文件夹或数据库列表以此来判断该文件夹或数据库是否已经存在。如果是选择复制数据,可以CreateMapSDDraft()中copy_data_to_server参数值设为True.
3、使用StageService过渡服务工具将服务定义草稿(.sddraft) 转换为服务定义(.sd)文件;
4、使用 UploadServiceDefinition上载服务定义工具将服务定义 (.sd)文件上传并发布服务到指定的GIS服务器。最后所生成的sd和sddraft文件不会自动删除。
具体示例代码:
# -*- coding: utf-8 -*-
import arcpy
wrkspc="E:/datapy/"
# 1、创建server连接#
connection_type='ADMINISTER_GIS_SERVICES'
connectionfilename='serverags.ags'
server_url='https://wl.arcgisonline.cn/server/admin'
connectionfilepath=wrkspc+connectionfilename
arcpy.mapping.CreateGISServerConnectionFile(connection_type,wrkspcs,connectionfilename,server_url,
'ARCGIS_SERVER',False,wrkspcs,server_username,server_password,
"SAVE_USERNAME")
# 注册文件夹
print "注册文件夹..."
wrkspcs="E:\datapy"
if wrkspcs not in [i[2] for i in arcpy.ListDataStoreItems(connectionfilepath, 'FOLDER')]:
dsStatus = arcpy.AddDataStoreItem(connectionfilepath, "FOLDER", "folderzce", wrkspcs, wrkspcs)
print "Data store : " + str(dsStatus)
# 2、CreateMapSDDraft将地图文档(.mxd)转换为服务定义草稿(.sddraft)
mapdocument = arcpy.mapping.MapDocument(wrkspc+'testmxd.mxd')
service_name='testpy01'
sddraft=wrkspc+service_name+'.sddraft'
sd=wrkspc+service_name+'.sd'
summary='test'
tags='map'
analysis=arcpy.mapping.CreateMapSDDraft(mapdocument,sddraft,service_name,'ARCGIS_SERVER',
connectionfilepath,False,'test',summary,tags)
# Analyze the service definition draft
analysis = arcpy.mapping.AnalyzeForSD(sddraft)
# Print errors, warnings, and messages returned from the analysis
print "The following information was returned during analysis of the MXD:"
for key in ('messages', 'warnings', 'errors'):
print '----' + key.upper() + '---'
vars = analysis[key]
for ((message, code), layerlist) in vars.iteritems():
print ' ', message, ' (CODE %i)' % code
print ' applies to:',
for layer in layerlist:
print layer.name,
print
# Stage and upload the service if the sddraft analysis did not contain errors
if analysis['errors'] == {}:
# 3、 Execute StageService. This creates the service definition.
arcpy.StageService_server(sddraft, sd)
# 4、 Execute UploadServiceDefinition. This uploads the service definition and publishes the service.
arcpy.UploadServiceDefinition_server(sd, connectionfilepath)
print "Service successfully published"
else:
print "Service could not be published because errors were found during analysis."
print arcpy.GetMessages()
二、发布切片服务:
1、使用CreateMapSDDraft()函数将mxd地图文档转换为服务定义草稿文件(.sddraft)。
2、使用Python标准库 xml.dom.minidom 修改 .sddraft 文件,以开启地图服务的缓存功能,之后再将修改后的 sddraft 文件保存到新的文件中。
3、使用 AnalyzeForSD ()函数分析新的 .sddraft 文件中是否包含错误。
4、分析草稿文件后,使用过渡服务地理处理工具过渡服务定义。
5、使用上传服务定义地理处理工具将服务定义上传到服务器并发布地图服务。
以上步骤示例代码:
# -*- coding: utf-8 -*-
import arcpy
import xml.dom.minidom as xmldom
import os
arcpy.env.overwriteOutput = True
wrkspc="E:/datapytest/"
confilename='servertest.ags'
server_url='https://wl.arcgisonline.cn/server/admin'
arcpy.mapping.CreateGISServerConnectionFile('ADMINISTER_GIS_SERVICES',wrkspc,confilename,server_url,
'ARCGIS_SERVER',False,wrkspc,username,password,
"SAVE_USERNAME")
connectionfilepath = wrkspc+confilename
# 注册文件夹
wrkspcs="E:\datapytest"
if wrkspcs not in [i[2] for i in arcpy.ListDataStoreItems(connectionfilepath, 'FOLDER')]:
dsStatus = arcpy.AddDataStoreItem(connectionfilepath, "FOLDER", "zcfwj", wrkspcs, wrkspcs)
print "Data store : " + str(dsStatus)
else:
print('注册文件夹失败')
# 创建服务定义草稿文件
mapdocument=arcpy.mapping.MapDocument(wrkspc+'testmxd.mxd')
servicename='tileservices'
outsddraft=wrkspc+servicename+'.sddraft'
sdfile=wrkspc+servicename+'.sd'
summary='test'
tags='test'
analysis=arcpy.mapping.CreateMapSDDraft(mapdocument,outsddraft,
servicename,'ARCGIS_SERVER',connectionfilepath,False,'testpy',summary,tags)
#用DOM读取以xml的形式读取sddraft文件
doc=xmldom.parse(outsddraft)
print("准备修改服务定义草稿文件内容……")
#打开配置属性中的缓存
configProps = doc.getElementsByTagName('ConfigurationProperties')[0]
propArray = configProps.firstChild
propSets = propArray.childNodes
for propSet in propSets:
keyValues=propSet.childNodes
for keyValue in keyValues:
if keyValue.tagName=='Key':
if keyValue.firstChild.data=="isCached":
keyValue.nextSibling.firstChild.data='true'
print("缓存已开启")
#关闭Kml
typeNames=doc.getElementsByTagName('TypeName')
for typeName in typeNames:
if typeName.firstChild.data=='KmlServer':
extension=typeName.parentNode
for extElement in extension.childNodes:
if extElement.tagName=='Enabled':
extElement.firstChild.data='false'
print("Kml已关闭")
#重新生成服务定义草稿文件
newsddraft=wrkspc+servicename+'.sddraft'
if os.path.exists(newsddraft):
os.remove(newsddraft)
newFile = open(newsddraft,'w')
doc.writexml(newFile)
newFile.close()
analysis=arcpy.mapping.AnalyzeForSD(newsddraft)
print ("重新分析……")
for key in('messages','warnings','errors'):
print "----"+key.upper()+"-----"
vars=analysis[key]
for((message,code),layerlist)in vars.iteritems():
print " ", message, " (CODE %i)" % code
print " applies to:",
for layer in layerlist:
print layer.name
del newFile, doc
# 分析完成,没有错误,准备发服务
if analysis['errors']=={}:
arcpy.StageService_server(newsddraft,sdfile)
arcpy.UploadServiceDefinition_server(sdfile,connectionfilepath)
arcpy.SignOutFromPortal_server()
else:
print "Service could not be published"
6、发布服务后,开始利用CreateMapServerCache_server创建地图缓存。
1)使用默认切片方案创建缓存
# -*- coding: utf-8 -*-
inputService = wrkspc + serverconf + "/" + floder+"/" + serviceName
print inputService
serviceCacheDirectory = "D:/arcgisserver/directories/arcgiscache"
tilingSchemeType = "NEW"
scalesType = "STANDARD"
numOfScales = "4"
scales = ""
dotsPerInch = "96"
tileOrigin = ""
scales = ""
tileSize = "512 x 512"
cacheTileFormat = "PNG"
tileCompressionQuality = ""
storageFormat = "COMPACT"
predefinedTilingScheme = ""
print ("参数初始化成功……")
arcpy.CreateMapServerCache_server(inputService,serviceCacheDirectory,tilingSchemeType, scalesType, numOfScales, dotsPerInch,tileSize, predefinedTilingScheme,tileOrigin, scales,cacheTileFormat,
tileCompressionQuality,storageFormat)
print "创建缓存成功"
report.close()
2)使用自定义切片方案创建缓存
# -*- coding: utf-8 -*-
import arcpy
from arcpy import env
import os, sys, time, datetime, traceback, string
wrkspc="E:/datapytest/"
serverconf = "servertest"
floder="testpy"
serviceName = "tileservices.MapServer"
inputService = wrkspc + serverconf + "/" + floder+"/" + serviceName
print inputService
serviceCacheDirectory = "D:/arcgisserver/directories/arcgiscache"
tilingSchemeType = "PREDEFINED"
scalesType = ""
numOfScales = ""
scales = ""
dotsPerInch = "96"
tileOrigin = ""
scales = ""
tileSize = "256 x 256"
cacheTileFormat = "PNG"
tileCompressionQuality = ""
storageFormat = "COMPACT"
predefinedTilingScheme = "E:/datapytest/xml.xml"
print ("参数初始化成功……")
currentTime = datetime.datetime.now()
arg1 = currentTime.strftime("%H-%M")
arg2 = currentTime.strftime("%Y-%m-%d %H:%M")
file = "E:/datapytest/report_%s.txt" % arg1
print currentTime
report = open(file, 'w')
try:
starttime = time.clock()
result = arcpy.CreateMapServerCache_server(inputService,
serviceCacheDirectory,
tilingSchemeType, scalesType,
numOfScales, dotsPerInch,
tileSize, predefinedTilingScheme,
tileOrigin, scales,
cacheTileFormat,
tileCompressionQuality,
storageFormat)
finishtime = time.clock()
elapsedtime = finishtime - starttime
#打印消息至文件
while result.status < 4:
time.sleep(0.2)
resultValue = result.getMessages()
report.write("completed " + str(resultValue))
print "创建缓存" + \ serviceName + " in " + str(elapsedtime) + " sec \n on " + arg2
except Exception, e:
# 如果发生错误,打印行号和错误消息
tb = sys.exc_info()[2]
report.write("Failed at step 1 \n" "Line %i" % tb.tb_lineno)
report.write(e.message)
print "创建缓存成功"
report.close()
7、最后,使用管理地图服务器缓存切片工具ManageMapServerCacheTiles_server
进行切片。
# -*- coding: utf-8 -*-
#!/usr/bin/python
import arcpy
from arcpy import env
import os, sys, time, datetime, traceback, string
wrkspc="E:/datapytest/"
serverconf = "servertest"
floder="testpy"
servicename = "tileservices.MapServer"
inputService = wrkspc + serverconf + "/" + floder+"/" + servicename
scales = [4622324.434309,2311162.217155]
update_mode="RECREATE_ALL_TILES"
num_of_caching_service_instances="2"
area_of_interest=""
update_extent=""
wait_for_job_completion="WAIT"
currentTime = datetime.datetime.now()
arg1 = currentTime.strftime("%H-%M")
arg2 = currentTime.strftime("%Y-%m-%d %H:%M")
file = "E:/datapytest/report_%s.txt" % arg1
print file
report = open(file, 'w')
try:
starttime = time.clock()
result=arcpy.ManageMapServerCacheTiles_server (inputService,
scales,
update_mode,
num_of_caching_service_instances,
area_of_interest,
update_extent,
wait_for_job_completion)
finishtime = time.clock()
elapsedtime = finishtime - starttime
print result.status
#打印消息至文件
while result.status < 4:
time.sleep(0.2)
resultValue = result.getMessages()
report.write("completed " + str(resultValue))
print "创建缓存" + \
servicename + " in " + str(elapsedtime) + " sec \n on " + arg2
except Exception, e:
# 如果发生错误,打印行号和错误消息
tb = sys.exc_info()[2]
report.write("Failed at step 1 \n" "Line %i" % tb.tb_lineno)
report.write(e.message)
print "管理缓存成功"
report.close()
三、发布要素服务:
参考了http://zhihu.esrichina.com.cn/article/3566链接的文章。
1、使用CreateMapSDDraft()函数将mxd地图文档转换为服务定义草稿文件(.sddraft)。
2、注册sde库
3、使用Python标准库 xml.dom.minidom 修改 .sddraft 文件,以开启FeatureServer
功能,之后再将修改后的 sddraft 文件保存到新的文件中。
3、使用 AnalyzeForSD ()函数分析新的 .sddraft 文件中是否包含错误。
4、分析草稿文件后,使用过渡服务地理处理工具过渡服务定义。
5、使用上传服务定义地理处理工具将服务定义上传到服务器并发布地图服务。
# -*- coding: utf-8 -*-
import arcpy, os, sys
from arcpy import env
from datetime import datetime
import xml.dom.minidom as DOM
arcpy.env.overwriteOutput = True
env.workspace="E:/pyhostfeature"
wrkspc="E:/pyhostfeature/"
connection_type='ADMINISTER_GIS_SERVICES'
out_name='serverags.ags'
server_url='https://wl.arcgisonline.cn/server/admin'
use_arcgis_desktop_staging_folder = False
connectionfile=wrkspc+out_name
arcpy.mapping.CreateGISServerConnectionFile(connection_type,wrkspc,out_name,server_url,
'ARCGIS_SERVER',use_arcgis_desktop_staging_folder,
wrkspc,server_username,server_password,
"SAVE_USERNAME")
# 判断数据库是否注册,并注册
db_conn="C:/Users/admin/AppData/Roaming/Esri/Desktop10.7/ArcCatalog/hostfeature.sde"
if db_conn not in [i[2] for i in arcpy.ListDataStoreItems(connectionfile, 'DATABASE')]:
dsStatus = arcpy.AddDataStoreItem(connectionfile, "DATABASE", "featurepyzc", db_conn, db_conn)
print "Data store : " + str(dsStatus)
print('注册数据库完成..')
mapdocument = arcpy.mapping.MapDocument(wrkspc + 'test.mxd')
service_name='testf'
sddraft=wrkspc+service_name+'.sddraft'
newSDdraft = 'updatedDraft.sddraft'
sd=wrkspc+service_name+'.sd'
summary='test'
tags='map'
print "SD:" + sd + ",,sdDraft:" + sddraft
try:
print'create service definition draft'
# 创建草稿文件
analysis = arcpy.mapping.CreateMapSDDraft(mapdocument, sddraft, service_name, 'ARCGIS_SERVER',
connectionfile, False, 'test', summary, tags)
print'create draft success'
# 用DOM读取以xml的形式读取sddraft文件
doc = DOM.parse(sddraft)
# 开启feature service
typeNames = doc.getElementsByTagName('TypeName')
for typeName in typeNames:
if typeName.firstChild.data == 'FeatureServer':
typeName.parentNode.getElementsByTagName('Enabled')[0].firstChild.data = 'true'
# Write the new draft to disk
f = open(newSDdraft, 'w')
doc.writexml(f)
f.close()
# 分析新的草稿文件
analysis = arcpy.mapping.AnalyzeForSD(newSDdraft)
for key in ('messages', 'warnings', 'errors'):
print "----" + key.upper() + "---"
vars = analysis[key]
for ((message, code), layerlist) in vars.iteritems():
print " ", message, " (CODE %i)" % code
print " applies to:",
for layer in layerlist:
print layer.name
if analysis['errors'] == {}:
print 'analysis true'
# Stage the service
arcpy.StageService_server(newSDdraft, sd)
# 上传发布
arcpy.UploadServiceDefinition_server(sd, connectionfile)
print 'Service successfully published'
# Write messages to a Text File
tFile = open(wrkspc + '{}-log.txt'.format(service_name), "a")
tFile .write(str(datetime.now()) + " | " + "Uploaded and publish service" + "\n")
tFile .close()
else:
# If the sddraft analysis contained errors, display them and quit.
print analysis['errors']
# Write messages to a Text File
tFile = open(wrkspc + '{}-log.txt'.format(service_name), "a")
tFile .write(str(datetime.now()) + " | " + analysis['errors'] + "\n")
txtFile.close()
except:
print arcpy.GetMessages()
# Write messages to a Text File
tFile = open(wrkspc + '{}-log.txt'.format(service_name), "a")
tFile .write(str(datetime.now()) + " | Last Chance Message:" + arcpy.GetMessages() + "\n")
tFile .close()
四、发布托管要素服务
1、将地图文档转换为 .sddraft 文件。
2、使用AnalyzeForSD()分析 sddraft 文件是否存在错误。
3、使用StageService过渡服务工具将服务定义草稿(.sddraft) 转换为服务定义(.sd)文件;
4、使用 UploadServiceDefinition上载服务定义工具将服务定义 (.sd)文件上传并发布服务到指定的portal中。
# -*- coding: utf-8 -*-
import arcpy, os, sys
import xml.dom.minidom as DOM
arcpy.env.overwriteOutput = True
server_username='***'
server_password='***'
# arcpy.SignInToPortal_server(server_username,server_password,"")
wrkspc="E:/pyhostfeature/"
mapdocument=arcpy.mapping.MapDocument(wrkspc+'test.mxd')
serviceName='hfservice'
outsddraft=wrkspc+serviceName+'.sddraft'
newSDdraft =wrkspc+'updatesddraft.sddraft'
sdfile=wrkspc+serviceName+'.sd'
summary='test'
tags='test'
arcpy.mapping.CreateMapSDDraft(mapdocument, outsddraft, serviceName, "MY_HOSTED_SERVICES","",True,"",summary,tags)
# Read the contents of the original SDDraft into an xml parser
print("准备修改服务定义草稿文件内容……")
doc = DOM.parse(outsddraft)
tagsType = doc.getElementsByTagName('Type')
for tagType in tagsType:
if tagType.parentNode.tagName == 'SVCManifest':
if tagType.hasChildNodes():
tagType.firstChild.data = "esriServiceDefinitionType_Replacement"
tagsState = doc.getElementsByTagName('State')
for tagState in tagsState:
if tagState.parentNode.tagName == 'SVCManifest':
if tagState.hasChildNodes():
tagState.firstChild.data = "esriSDState_Published"
# Change service type from map service to feature service
typeNames = doc.getElementsByTagName('TypeName')
for typeName in typeNames:
if typeName.firstChild.data == "MapServer":
typeName.firstChild.data = "FeatureServer"
# Turn off caching
configProps = doc.getElementsByTagName('ConfigurationProperties')[0]
propArray = configProps.firstChild
propSets = propArray.childNodes
for propSet in propSets:
keyValues = propSet.childNodes
for keyValue in keyValues:
if keyValue.tagName == 'Key':
if keyValue.firstChild.data == "isCached":
keyValue.nextSibling.firstChild.data = "false"
# Turn on feature access capabilities
configProps = doc.getElementsByTagName('Info')[0]
propArray = configProps.firstChild
propSets = propArray.childNodes
for propSet in propSets:
keyValues = propSet.childNodes
for keyValue in keyValues:
if keyValue.tagName == 'Key':
if keyValue.firstChild.data == "WebCapabilities":
keyValue.nextSibling.firstChild.data = "Query,Create,Update,Delete,Uploads,Editing"
# Write the new draft to disk
f = open(newSDdraft, 'w')
doc.writexml( f )
f.close()
# Analyze the service
analysis = arcpy.mapping.AnalyzeForSD(newSDdraft)
if analysis['errors'] == {}:
# Stage the service
arcpy.StageService_server(newSDdraft, sdfile)
arcpy.UploadServiceDefinition_server(sdfile, "My Hosted Services", serviceName,
"", "", "", "", "OVERRIDE_DEFINITION", "SHARE_ONLINE",
"PUBLIC", "SHARE_ORGANIZATION", "")
print "Uploaded and overwrote service"
else:
# If the sddraft analysis contained errors, display them and quit.
print analysis['errors']