首先,我是自学编码员,并接受任何对我在下面发布的代码的批评和/或建议。这个问题一直很愉快,因为我喜欢挑战自己,但我担心我遇到了一堵砖墙需要一些指导。我将在下面详细说明我的脚本的整体情况,然后展示我在标题中解释的实际问题的位置。
我正在整理一个脚本,该脚本将自动下载并下载数据,上传并导出到GDB。我们服务于广泛的用户区域,并拥有一个非常大的企业SDE设置,其中包含大量公共数据,我们必须为最终用户搜索和更新这些数据。我们的大部分数据都是由当地政府实体每月更新的,我们必须出去手动搜索数据,下载,解压缩,QAQC等。我想把一个脚本放在一起,这将自动化这个过程的第一部分通过外出并下载我的所有数据并导出到本地GDB,从那里我可以QAQC所有内容并上传到我们的SDE供我们的用户访问。
到目前为止,这个过程非常直接,直到我遇到了这个我面前的问题。我的脚本将在网页中搜索特定关键字并找到相关链接并开始下载。对于这篇文章,我将使用两个例子,一个是有效的,一个是目前给我的问题。我的功能是搜索和下载Metro GIS数据集,下面显示了我当前查找此数据的过程。到目前为止,我所包含的所有http网站都将使用下面的发布功能。像Metro一样,我计划为每组数据定义一个函数。
import requests, zipfile, StringIO, time, arcpy, urllib2, urlparse
from BeautifulSoup import BeautifulSoup
arcpy.env.overwriteOutput = True
workPath = -- #The output GDB
timestr = time.strftime("%Y%m%d")
gdbName = "GlobalSDEUpdate_" + timestr
gdbPath = workPath + "\\" + gdbName + ".gdb"
class global_DataFinder(object):
def __init__(self):
object.__init__(self)
self.gdbSetup()
self.metro()
def gdbSetup(self):
arcpy.CreateFileGDB_management(workPath, gdbName)
def fileDownload(self, key, url, dlPath, dsName):
page = urllib2.urlopen(url).read()
urlList = []
soup = BeautifulSoup(page)
soup.prettify()
for link in soup.findAll('a', href = True):
if not 'http://' in link['href']:
if urlparse.urljoin(url, link['href']) not in urlList:
zipDL = urlparse.urljoin(url, link['href'])
if zipDL.endswith(".zip"):
if key in zipDL:
urlList.append(zipDL)
for x in urlList:
print x
r = requests.get(x, stream=True)
z = zipfile.ZipFile(StringIO.StringIO(r.content))
z.extractall(dlPath)
arcpy.CreateFeatureDataset_management(gdbPath, dsName)
arcpy.env.workspace = dlPath
shpList = []
for shp in arcpy.ListFeatureClasses():
shpList.append(shp)
arcpy.FeatureClassToGeodatabase_conversion(shpList, (gdbPath + "\\" + dsName))
del shpList[:]
def metro(self):
key = "METRO_GIS_Data_Layers"
url = "http://www.ridemetro.org/Pages/NewsDownloads.aspx"
dlPath = -- *#Where my zipfiles output to*
dsName = "Metro"
self.fileDownload(key, url, dlPath, dsName)
global_DataFinder()
正如您在上面所看到的,这是我开始使用Metro作为我的第一个测试点的方法,目前这种方法很有用。我希望我的所有网站都能继续这样,但是当我到达FEMA时,我遇到了一个问题。
网站National Flood Hazard Layer (NFHL) Status为全国许多县提供洪泛区数据,任何希望使用它的人都可以免费使用。到达网站后,您会看到您可以搜索您想要的县,然后表格查询搜索,然后您只需点击并下载您想要的县。在检查来源时,这是我遇到的并在 iframe 中注意到它。
通过Chrome访问iframe源链接并检查png源网址时,这就是您所获得的内容 - https://hazards.fema.gov/femaportal/NFHL/searchResult
现在这里是我的问题所在,与http网站不同,我很快就了解到访问安全的https网站并抓取页面是不同的,特别是当它使用javascript来显示表格时。我花了几个小时在论坛上搜索并尝试了不同的python包,如selenium,mechanize,requests,urllib,urllib2,在我可以安全地建立连接并解析网页并搜索我的县zipfile之前,我似乎总是遇到死胡同。 。下面的代码显示了我得到的最接近的代码,并显示了我得到的错误代码。
(我总是在一个单独的脚本中测试,然后当它工作时我把它带到我的主脚本,这就是为什么下面的代码片段与我原来的分开)
import urllib2, httplib, socket, ssl
from BeautifulSoup import BeautifulSoup
url = "http://www.floodmaps.fema.gov/NFHL/status.shtml"
def test():
page = urllib2.urlopen(url).read()
urlList = []
soup = BeautifulSoup(page)
soup.prettify()
for link in soup.findAll("iframe", src=True):
r = urllib2.urlopen(link['src'])
iFrame = link['src']
print iFrame
def connect_patched(self):
"Connect to a host on a given (SSL) port."
sock = socket.create_connection((self.host, self.port),
self.timeout, self.source_address)
if self._tunnel_host:
self.sock = sock
self._tunnel()
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
ssl_version=ssl.PROTOCOL_SSLv2)
httplib.HTTPSConnection.connect = connect_patched
test()
运行此测试时出错
urllib2.URLError:urlopen错误[Errno 6] _ssl.c:504:TLS / SSL连接已关闭
我希望一个更有经验的编码人员可以看到我做了什么,并告诉我目前的方法是否可行,如果是,如何通过这个最终错误并正确解析数据表。
使用@crmackey进行编辑
import requests
import os
import zipfile
from pyquery import PyQuery
from requests.packages.urllib3.exceptions import InsecureRequestWarning, InsecurePlatformWarning, SNIMissingWarning
import httplib
httplib.HTTPConnection._http_vsn = 10
httplib.HTTPConnection._http_vsn_str = 'HTTP/1.0'
# disable ssl warnings (we are not verifying SSL certificates at this time...future ehnancement?)
for warning in [SNIMissingWarning, InsecurePlatformWarning, InsecureRequestWarning]:
requests.packages.urllib3.disable_warnings(warning)
def download_zips(out_path):
url = 'http://www.floodmaps.fema.gov/NFHL/status.shtml'
download_prefix = 'https://hazards.fema.gov/femaportal/NFHL'
pq = PyQuery(requests.get(url, verify=False).content) #verify param important for SSL
src = pq.find('iframe').attr('src')
pq = PyQuery(requests.get(src, verify=False).content)
table = pq.find('table')
for a in table.find('a'):
href = a.attrib.get('href')
print href
url = '/'.join([download_prefix, href])
print url
r = requests.get(url, stream=True, verify=False)
out_zip = os.path.join(out_path, href.split('=')[-1])
with open(out_zip, 'wb') as f:
for chunk in r.iter_content(1024 *16): #grab 1KB at a time
if chunk:
f.write(chunk)
print 'downloaded zip: "{}"'.format(href.split('=')[-1])
out_path = r"C:\Users\barr\Desktop\Test"
download_zips(out_path)
我添加的只是httplib并更改了顶部的HTTPConnection。这允许我使用您的脚本连接到该站点。现在这是当前的问题。我只在out_path中获得1个zip文件,并且zip文件为空。我检查了调试窗口中的打印源,并显示它试图从表中下载TERRITORY OF THE VIRGIN ISLAND zip文件,所以看起来它正在尝试,但它没有下载任何东西。在输出一个空的zip文件后,脚本完成并不再显示错误消息。我暂时删除了解压缩文件的行,因为它们返回错误,因为文件夹是空的。
答案 0 :(得分:1)
我能够使用请求模块下载zip文件,并且还选择使用PyQuery而不是Beautiful Soup。我认为您面临的问题与SSL证书验证有关,如果您将requests
参数设置为verify
,False
模块将允许您跳过检查证书。< / p>
下面的函数将下载所有zip文件并解压缩,从那里,您可以将shapefile导入地理数据库:
import requests
import os
import zipfile
from pyquery import PyQuery
from requests.packages.urllib3.exceptions import InsecureRequestWarning, InsecurePlatformWarning, SNIMissingWarning
# disable ssl warnings (we are not verifying SSL certificates at this time...future ehnancement?)
for warning in [SNIMissingWarning, InsecurePlatformWarning, InsecureRequestWarning]:
requests.packages.urllib3.disable_warnings(warning)
def download_zips(out_path):
url = 'http://www.floodmaps.fema.gov/NFHL/status.shtml'
download_prefix = 'https://hazards.fema.gov/femaportal/NFHL'
pq = PyQuery(requests.get(url, verify=False).content) #verify param important for SSL
src = pq.find('iframe').attr('src')
pq = PyQuery(requests.get(src, verify=False).content)
table = pq.find('table')
for a in table.find('a'):
href = a.attrib.get('href')
url = '/'.join([download_prefix, href])
r = requests.get(url, stream=True, verify=False)
out_zip = os.path.join(out_path, href.split('=')[-1])
with open(out_zip, 'wb') as f:
for chunk in r.iter_content(1024 *16): #grab 1KB at a time
if chunk:
f.write(chunk)
print 'downloaded zip: "{}"'.format(href.split('=')[-1])
# do more stuff like unzip?
unzipped = out_zip.split('.zip')[0]
with zipfile.Zipfile(out_zip, 'r') as f:
f.extractall(unzipped)