【发布时间】:2015-11-05 16:32:40
【问题描述】:
你好。
我很难使用 PyQT 抓取网站。问题是,该站点使用 JSF,并且其中所有内容的 URL 都是相同的。我们在这个例子中使用“http://somesi.te/searchData.jsf”。
我打开它,填写一个表单(目标是同一个 URL),提交,然后在同一个页面中得到结果。直到那里我的脚本工作正常。
但是返回的结果就像 1000 个分页页面,底部有一个锚标记,用于下载一个 Excel 文件,所有结果都在一个文件中。 这个锚点是#-targeted,onClick事件调用一个MoJarra函数,jsfcljs:
<a href="#" onclick="mojarra.jsfcljs(document.getElementById('formX'),{'formX:j_idt999':'formX:j_idt999'},'');return false">
分析函数,它只是在表单中附加一个<input type="hidden">,然后再次提交,大概是为了让服务器理解它并发送Excel文件而不是网页。
问题是:服务器将文件“伪装”为网页返回。 URL 仍然是“somesi.te/searchData.jsf”,浏览器将其识别为文件,因为标题。
当我尝试使用 unsupportedContent() 来获取文件时,它似乎没有跟随流,它只是尝试获取在 unsupportedContent 信号中接收到的 URL。作为当前 URL “somesi.te/searchData.jsf”,当我保存文件时,我得到的是页面的源代码,而不是我的文件。
这是我现在使用的代码:
def getTicketDetails(self):
self.webView.loadFinished.disconnect(self.getTicketDetails)
self.webView.page().setForwardUnsupportedContent(True)
self.webView.page().unsupportedContent.connect(self.downloadExcel)
downloadButton = documentElement.findFirst('input[id="force_download"]')
downloadButton.evaluateJavaScript("this.click();")
def downloadExcel(self, reply):
self.manager = self.webView.page().networkAccessManager()
self.manager.finished.connect(self.saveExcel)
postData = QByteArray()
postData.append("formX=formX&")
postData.append("formX:idSelecao_input=1&")
postData.append("formX:dataJanela_input=03/11/2015&")
postData.append("formX:dataAte_input=07/11/2015&")
postData.append("formX:j_idt106_input=all&")
postData.append("formX:j_idt120_input=0&")
postData.append("formX:produto_input=VLR&")
postData.append("formX:options=1&")
postData.append("formX:j_idt133_input=0&")
#postData.append("javax.faces.ViewState=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&")
postData.append("formX:j_idt999=formCI:j_idt999")
self.request = reply.request()
#self.reply = self.manager.get(self.request)
self.reply = self.manager.post(reply.request(), postData)
def saveExcel(self):
f = open('C:\\path\\to\\file\\searchResults.xls', 'wb')
f.write(str(self.reply.readAll()))
f.flush()
f.close()
self.exit()
这里故意更改了文件的路径。
我尝试使用 post 方法和 get 方法(在上面的 sn-p 中评论),但它们都不起作用,我总是得到一个损坏的 xls 文件,它实际上是一个带有源代码的 HTML 文件页面。
当我取消注释 postData 项“javax.faces.ViewState”时,服务器返回错误。我猜这里是缺少的关键,因为这个特定行上的特殊字符。
你知道我做错了什么吗?我知道我使用 python 的方式,但我根本不是专家。
如果有任何需要澄清的地方,请告诉我。
我目前正在使用 python 2.7.9 和 PyQT 4.8.7。
【问题讨论】:
-
你能提供一个真实网站的链接吗?我想查看提交表单时生成的确切请求。
-
另外,
javax.faces.ViewStateprobably 持有 CSRF(预防)令牌和一些状态,这就是服务器拒绝没有它的请求的原因。 -
抱歉,我无法提供实际链接,因为它是我的一个客户的内部系统。我确实设法做对了,这是特殊字符。我真的需要 ViewState,但它上面的“+”、“/”和“=”符号崩溃了。在 Firefox 上调试,我发现在发送时,实际数据上的特殊字符被替换为 HTML 十六进制代码(即:%2A、%3D)。更换这些并再次发送时,效果非常好。
-
在这种情况下,您能否提供有关您的浏览器在您访问和提交表单时提出的请求的详细信息?
-
我解决了这个问题,但感谢分享有关 javax.faces.ViewState 的知识,它确实帮助我走上了正确的轨道:)
标签: python jsf download web-scraping pyqt