从网站下载文件的方法

3

这是我的第一个问题,如果我有任何错误之处,请您多多包涵。

我正在使用Python 3.3中的requests模块来自动下载一些网站上的文件,但是尝试获取csv文件时这个网站特别麻烦。我在Python方面具备可行的能力,但就网站交互而言,我对HTML和JavaScript不太熟悉。

以下是相关代码:

import requests
import datetime

now = datetime.datetime.now().strftime("%Y%m%d")

folder = 'some path'

url = 'https://gats.pjm-eis.com/gats2/PublicReports/RenewableGeneratorsRegisteredInGATS/'#ExportTo'
payload = {'exportType' : 'CSV',
           'tabNumber' : ''}
doc = requests.post(url, data=payload, stream=True)

output = open(folder+now+'_GATSRegistered.csv','wb')
output.write(doc.content)
output.close()

我没有遇到任何错误,但我创建的文档基于错误页面。在网址直接指向文件的网站上,我已经成功做到了这一点('http://www.place.com/path/file.xlsx'),因此我知道获取文件后该怎么做。不过那只需要一个“get”请求。
所以,我的问题是:
  • 应该使用正确的请求方式是什么?
  • 使用“post”是正确的吗?
  • 这是一种特殊情况还是我应该知道如何一般性地解决它?
  • 有什么其它我应该做出的不同决策吗?

1
Post用于向服务器发送数据,get仅用于获取数据(尽管它也可以发送数据,但不安全)。 - rlms
3
可以尝试使用Python的with关键字来打开文件,这样在使用完后会自动关闭文件。 - user2555451
@user2387370 当我使用get时,我只会得到原始页面,就像没有有效负载一样。我的想法是需要发送一些数据让服务器知道我已经“点击”了CSV按钮,但你是说这可以用get方法完成吗? - ess
1
@user41790 get可以用于发送数据,尽管我不知道请求的详细信息。如果您在URL末尾看到&foo=7&bar=8等内容,则get通过将其附加到URL来发送数据,那就是一个get请求。 - rlms
1个回答

1

我在Chrome中查看了该页面,并打开了开发者控制台,其中网络选项卡是开启的。在那里,您可以看到单击“CSV”按钮会发送一个带有大量表单数据的POST请求。

exportType:CSV
tabNumber:
CSV_CH:1
PRN_CH:0
GridView$DXFREditorcol0:
GridView$DXFREditorcol1:
GridView$DXFREditorcol2:
GridView$DXFREditorcol3:
GridView$DXFREditorcol4:
GridView$DXFREditorcol5:
GridView$DXFREditorcol6:
GridView$DXFREditorcol7:
GridView$DXFREditorcol8:
GridView$DXFREditorcol9:
GridView$DXFREditorcol10:
GridView$DXFREditorcol11:
GridView$DXFREditorcol12:
GridView$DXFREditorcol13:
GridView$DXFREditorcol14:
GridView$DXFREditorcol15:
GridView$DXFREditorcol16:
GridView$DXFREditorcol17:
GridView$DXFREditorcol18:
GridView$DXFREditorcol19:
GridView$DXFREditorcol20:
GridView$DXFREditorcol21:
GridView$DXFREditorcol22:
GridView$DXFREditorcol23:
GridView$DXFREditorcol24:
GridView$DXFREditorcol25:
GridView$DXFREditorcol26:
GridView_custwindowWS:0:0:-1:-10000:-10000:0:1px:-10000:1:0:0:0
GridView_DXHFPWS:0:0:-1:-10000:-10000:0:180px:100px:1:0:0:0
GridView_DXPagerBottom_PSPSI:2
GridView$DXSelInput:
GridView$DXKVInput:[]
GridView$CallbackState:BwMHAQIFU3RhdGUGEAEHGwcAAgEHAQIBBwICAQcDAgEHBAIBBwUCAQcGAgEHBwIBBwgCAQcJAgEHCgIBBwsCAQcMAgEHDQIBBw4CAQcPAgEHEAIBBxECAQcSAgEHEwIBBxQCAQcVAgEHFgIBBxcCAQcYAgEHGQIBBxoCAQcABxsHAAcABwEHAAcCBwAHAwcABwQHAAcFBwAHBgcABwcHAAcIBwAHCQcABwoHAAcLBwAHDAcABw0HAAcOBwAHDwcABxAHAAcRBwAHEgcABxMHAAcUBwAHFQcABxYHAAcXBwAHGAcABxkHAAcaBwAHAAcAAgAFAAAAgAkCCUVudGl0eUtleQkCAAIAAwcEAgAHAAIBBTaVAAAHAAIBBwAHAAIQRmlsdGVyRXhwcmVzc2lvbgcCAAIIUGFnZVNpemUDBzI=
GridView$DXSyncInput:
GridView_DXFilterRowMenuCI:
DXScript:1_142,1_80,1_135,1_91,14_0,1_90,1_113,14_23,14_10,1_98,1_105,1_77,1_128,1_126,1_124,1_133,1_119,1_127,1_104,1_101,1_84,1_109,1_92,14_1,1_94,1_97,1_95,1_96,1_106,14_4,1_100,1_117,1_103,14_12,14_13,1_102,1_129,1_107,1_137,1_114,14_16,10_2,10_1,10_3,10_4,14_3
DXMVCEditorsValues:{"GridView_DXFREditorcol0":null,"GridView_DXFREditorcol1":null,"GridView_DXFREditorcol2":null,"GridView_DXFREditorcol3":null,"GridView_DXFREditorcol4":null,"GridView_DXFREditorcol5":null,"GridView_DXFREditorcol6":null,"GridView_DXFREditorcol7":null,"GridView_DXFREditorcol8":null,"GridView_DXFREditorcol9":null,"GridView_DXFREditorcol10":null,"GridView_DXFREditorcol11":null,"GridView_DXFREditorcol12":null,"GridView_DXFREditorcol13":null,"GridView_DXFREditorcol14":null,"GridView_DXFREditorcol15":null,"GridView_DXFREditorcol16":null,"GridView_DXFREditorcol17":null,"GridView_DXFREditorcol18":null,"GridView_DXFREditorcol19":null,"GridView_DXFREditorcol20":null,"GridView_DXFREditorcol21":null,"GridView_DXFREditorcol22":null,"GridView_DXFREditorcol23":null,"GridView_DXFREditorcol24":null,"GridView_DXFREditorcol25":null,"GridView_DXFREditorcol26":null}

你可以看到以上哪些是必须发送到服务器的。我怀疑不是所有的都是必需的(但我可能错了 :))。
话虽如此,当使用 stream=True 时,你应该使用 iter_content。因此,你的代码应该像这样:
payload = {
# Form contents
}
r = requests.post(url, data=payload, stream=True)
with open(filename, 'wb') as output:
    for chunk in r.iter_content():
        output.write(chunk)

for循环确保当数据可用时将其写入您的文件。当它被阻塞时,您不必担心它会挂起。


非常好,这非常有帮助。我认为并不是所有的表单数据都是绝对必要的,但为了证明概念,我首先尝试了所有的数据。我该如何将Chrome控制台视图转换为Python/请求?我真的不知道什么应该是数组、列表、字典、字符串等。 - ess
看起来该网站正在使用唯一标识符来防止通过欺诈,这会导致在此级别上防止帖子互动(我想)。尽管如此,我将此答案标记为正确的。 - ess

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接