Python - 从网页下载带链接的CSV文件
我想通过一个Python脚本从这个页面下载CSV文件。
但是,当我在浏览器中直接访问CSV文件的链接时,会出现一个协议表单。我必须先同意这个表单,才能下载文件。
我无法获取到CSV文件的确切网址。这个链接背后有一个值被发送到数据库,用来获取文件,比如说PERIOD_ID=2013-0
:
我试过用urllib2.open()
和urllib2.read()
,但是得到的却是协议表单的HTML内容,而不是文件内容。
我该怎么写Python代码来处理这个重定向,然后获取CSV文件并保存到磁盘上呢?
2 个回答
3
你需要设置一个叫做 ASP.NET_SessionId
的cookie。你可以通过在Chrome浏览器中右键点击网页,选择 检查元素 来找到它,或者使用Firefox浏览器和 Firebug 插件。
在Chrome中操作:
- 在网页上右键点击(确保你已经同意了相关条款),然后选择 检查元素
- 点击 资源 -> Cookies
- 选择列表中唯一的那个元素
- 复制
ASP.NET_SessionId
元素的 值
在Firebug中操作:
- 在网页上右键点击(同样要确保你已经同意了相关条款),然后点击 *用Firebug检查元素
- 点击 Cookies
- 复制
ASP.NET_SessionId
元素的 值
在我的情况下,我得到了 ihbjzynwfcfvq4nzkncbviou
- 这个值可能对你也有效,如果不行,你需要按照上面的步骤来操作。
把这个cookie添加到你的请求中,然后使用 requests
模块下载文件(这个方法是根据 eladc 的一个回答):
import requests
cookies = {'ASP.NET_SessionId': 'ihbjzynwfcfvq4nzkncbviou'}
r = requests.get(
url=('https://www.paoilandgasreporting.state.pa.us/publicreports/Modules/'
'DataExports/ExportProductionData.aspx?PERIOD_ID=2013-0'),
cookies=cookies
)
with open('2013-0.csv', 'wb') as ofile:
for chunk in r.iter_content(chunk_size=1024):
ofile.write(chunk)
ofile.flush()
1
这是我的建议,关于如何自动应用服务器的cookie,基本上就是模拟标准的客户端会话行为。
(这灵感来自@pope的回答 554580。)
import urllib2
import urllib
from lxml import etree
_TARGET_URL = 'https://www.paoilandgasreporting.state.pa.us/publicreports/Modules/DataExports/ExportProductionData.aspx?PERIOD_ID=2013-0'
_AGREEMENT_URL = 'https://www.paoilandgasreporting.state.pa.us/publicreports/Modules/Welcome/Agreement.aspx'
_CSV_OUTPUT = 'urllib2_ProdExport2013-0.csv'
class _MyHTTPRedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_302(self, req, fp, code, msg, headers):
print 'Follow redirect...' # Any cookie manipulation in-between redirects should be implemented here.
return urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
http_error_301 = http_error_303 = http_error_307 = http_error_302
cookie_processor = urllib2.HTTPCookieProcessor()
opener = urllib2.build_opener(_MyHTTPRedirectHandler, cookie_processor)
urllib2.install_opener(opener)
response_html = urllib2.urlopen(_TARGET_URL).read()
print 'Cookies collected:', cookie_processor.cookiejar
page_node, submit_form = etree.HTML(response_html), {} # ElementTree node + dict for storing hidden input fields.
for input_name in ['ctl00$MainContent$AgreeButton', '__EVENTVALIDATION', '__VIEWSTATE']: # Form `input` fields used on the ``Agreement.aspx`` page.
submit_form[input_name] = page_node.xpath('//input[@name="%s"][1]' % input_name)[0].attrib['value']
print 'Form input \'%s\' found (value: \'%s\')' % (input_name, submit_form[input_name])
# Submits the agreement form back to ``_AGREEMENT_URL``, which redirects to the CSV download at ``_TARGET_URL``.
csv_output = opener.open(_AGREEMENT_URL, data=urllib.urlencode(submit_form)).read()
print csv_output
with file(_CSV_OUTPUT, 'wb') as f: # Dumps the CSV output to ``_CSV_OUTPUT``.
f.write(csv_output)
f.close()
祝你好运!
[编辑]
关于事情的原因,我觉得@Steinar Lima说得对,确实需要一个会话cookie。不过,除非你已经访问过Agreement.aspx
页面并通过提供商的网站提交了响应,否则你从浏览器的网页检查器复制的cookie只会导致你再次跳转到欢迎来到PA DEP石油和天然气报告网站的欢迎页面。这当然就失去了用Python脚本来完成这项工作的意义。