2015-11-05 58 views
0

嗯,你好。使用PyQT刮刀下載「變相」文件

我很難用PyQT抓取一個網站。事情是,該網站使用JSF,並且這個URL中的所有內容都是相同的。在這個例子中,我們使用「http://somesi.te/searchData.jsf」。

我打開它,填寫表單(目標是相同的URL),提交,並在同一頁面中獲得結果。直到那裏我的腳本工作正常。

但是,結果會返回爲1000頁分頁,並且底部有一個錨標記可用於下載一個Excel文件,並將所有結果放在一個文件中。 這個錨#靶向性,與onClick事件調用鑽嘴魚科功能,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方法(評論上面的代碼片段),但他們都沒有工作,我總是最終得到一個損壞的xls文件,它是一個真正的HTML文件,源代碼爲這一頁。

當我取消註釋postData項「javax.faces.ViewState」時,服務器返回一個錯誤。我猜這裏是缺少的關鍵,因爲這個特定行上的特殊字符。

你知道我在做什麼錯嗎?我知道我用python的方式,但我根本不是專家。

如果有任何需要澄清,請讓我知道。

我目前使用python 2.7.9和PyQT 4.8.7。

+0

你能提供一個真實網站的鏈接嗎?我希望看到提交表單所產生的確切請求。 –

+0

此外,'javax.faces.ViewState' [可能](http://www.beyondjava.net/blog/jsf-viewstate-and-csrf-hacker-attacks/)既包含CSRF(預防)令牌,也包含一些狀態,這就是爲什麼服務器沒有它拒絕請求。 –

+0

對不起,我無法提供實際的鏈接,因爲它是我的客戶之一的內部系統。 我的確做到了,它是特殊字符。我真的需要ViewState,但其上的「+」,「/」和「=」符號正在崩潰。 在Firefox上進行調試時,發現發送時,實際數據上的特殊字符被HTML十六進制代碼替代(即:%2A,%3D)。 當更換這些並再次發送時,它的工作非常出色。 –

回答

0

在這裏,我創建了這段代碼:

def specialCharsToHtmlHex(self, rawString, jsfViewState=False): 
    parsedString = (rawString.replace('+', '%2B') 
          .replace('/', '%2F') 
          .replace(':', '%3A') 
          .replace('?', '%3F')) 

    if jsfViewState: 
     parsedString = parsedString.replace('=', '%3D') 

    return parsedString 

我這樣做特殊處理的ViewState的,因爲我不能改造「=」,他們實際上是後結構的一部分。

然後我叫這樣的代碼:

postData = QByteArray() 

    postData.append(self.specialCharsToHtmlHex("formX=formX&")) 
    postData.append(self.specialCharsToHtmlHex("formX:idSelecao_input=1&")) 
    postData.append(self.specialCharsToHtmlHex("formX:dataJanela_input="+self.searchData['startDate']+"&")) 
    postData.append(self.specialCharsToHtmlHex("formX:dataAte_input="+self.searchData['endDate']+"&")) 
    postData.append(self.specialCharsToHtmlHex(self.fieldNames['horaJanela']+"=&")) 
    postData.append(self.specialCharsToHtmlHex(self.fieldNames['tipoPortabilidade']+"=&")) 
    postData.append(self.specialCharsToHtmlHex(self.fieldNames['statusBilhete']+"="+self.searchData['statusValue']+"&")) 
    postData.append(self.specialCharsToHtmlHex(self.fieldNames['operadora']+"=0&")) 
    postData.append(self.specialCharsToHtmlHex("formX:produto_input="+self.searchData['productValue']+"&")) 
    postData.append(self.specialCharsToHtmlHex("formX:options=1&")) 
    postData.append(self.specialCharsToHtmlHex("formX:cpf=&")) 
    postData.append(self.specialCharsToHtmlHex(self.fieldNames['janelaBloqueada']+"=0&")) 
    postData.append(self.specialCharsToHtmlHex("formX:dataTable_selection=&")) 
    postData.append(self.specialCharsToHtmlHex("javax.faces.ViewState="+self.specialCharsToHtmlHex(self.searchData['jsfViewState'], jsfViewState=True)+"&")) 
    postData.append(self.specialCharsToHtmlHex(self.fieldNames['mojarraHiddenInput']+"="+self.searchData['mojarraHiddenValue'])) 

    self.reply = self.webView.page().networkAccessManager().post(reply.request(), postData) 

而且問題解決了,這樣,我得到了我想要的Excel文件。

我知道有一些冗餘,但我決定保持它爲了padronization。