2016-02-06 48 views
1

如何從JavaScript呈現的網頁上的鏈接下載? Python是首選語言。如何從JavaScript下載呈現的網頁?

到目前爲止,我已經嘗試在無頭服務器上使用Python bindings for Selenium。這種方法非常緩慢,充滿錯誤,並且不能可靠地確定下載進度或成功。另外,無頭服務器會干擾我的剪貼板(這是一個問題)。我使用Firefox,因爲它可以配置爲下載到默認目錄,但我認爲Chrome的情況並不會更好。

另外,我試過使用WebKit。

def render(url): 
    """Fully render a webpage (JavaScript and all) and return the HTML.""" 

    import subprocess 
    from textwrap import dedent 

    script = dedent("""\ 
    import sys 
    from PyQt4.QtCore import QUrl 
    from PyQt4.QtGui import QApplication 
    from PyQt4.QtWebKit import QWebPage 

    class Render(QWebPage): 

     def __init__(self, url): 
      self.app = QApplication(sys.argv) 
      QWebPage.__init__(self) 
      self.loadFinished.connect(self._loadFinished) 
      self.mainFrame().load(QUrl(url)) 
      self.app.exec_() 

     def _loadFinished(self, result): 
      self.frame = self.mainFrame() 
      self.app.quit() 

    render = Render(sys.argv[1]) 
    print render.frame.toHtml().toAscii()""").encode() 

    process = subprocess.Popen(['python2', '-', url], 
           stderr=subprocess.PIPE, 
           stdin=subprocess.PIPE, 
           stdout=subprocess.PIPE) 

    # pipe script into Python's stdin 
    return process.communicate(script)[0].decode('latin1') 

這將是偉大的,如果不是因爲我需要下載是在同一個會話的事實。有沒有辦法保留用於渲染頁面的會話? PyQt4和WebKit只是一堆共享庫。我不知道如何撕毀他們的膽量,或者甚至可能這樣的事情。

現在我只是做了以下內容:

with requests.Session() as session: 
    html = session.get(url).text 
    link = get_url(html) 
    download(link, session=session) 

沒有進入細節,get_url(html, url)只需從頁面中提取的JavaScript,黑客客場DOM任何電話,然後在node執行它。真的很討厭的東西...

任何方式,我可以安全地呈現一個網頁,並保持會話?

如果Python不合適或者JavaScript替代品更優雅,我也可以在節點中完全實現它。它看起來像也許node-dom可能就足夠了?我不是很熟悉它,但我對任何建議感興趣。

+0

也許你可以使用「開發者工具」在Chrome來分析瀏覽器和服務器找到使用JavaScript從服務器獲取數據的URL之間的流量。然後你可以在Python腳本中使用這個URL而不需要渲染頁面。 – furas

+0

btw:添加網頁網址以獲得更好的答案。 – furas

+0

該URL是通過嵌入式JS例如在瀏覽器中的客戶端確定的。 ''並且不與服務器交互。所以一個接受HTML頁面源代碼並返回像WebKit這樣的源代碼的工具將是完美的。也許我會看看如果我可以讓WebKit接受頁面源而不是頁面URL ... – Six

回答

-1

在Python 2或3中的PyQt5在這種情況下做的伎倆。請注意,該函數過於複雜,以支持使用WebKit的早期版本的PyQt5以及使用WebEngine的更高版本。

import sys 


def render(source_html): 
    """Return rendered HTML.""" 
    try: 
     from PyQt5.QtCore import QEventLoop 
     from PyQt5.QtWebEngineWidgets import QWebEngineView 
     from PyQt5.QtWidgets import QApplication 

     class Render(QWebEngineView): 
      """Render HTML with PyQt5 WebEngine.""" 

      def __init__(self, html): 
       self.html = None 
       self.app = QApplication(sys.argv) 
       QWebEngineView.__init__(self) 
       self.loadFinished.connect(self._loadFinished) 
       self.setHtml(html) 
       while self.html is None: 
        self.app.processEvents(
         QEventLoop.ExcludeUserInputEvents | 
         QEventLoop.ExcludeSocketNotifiers | 
         QEventLoop.WaitForMoreEvents) 
       self.app.quit() 

      def _callable(self, data): 
       self.html = data 

      def _loadFinished(self, result): 
       self.page().toHtml(self._callable) 
    except ImportError: 
     from PyQt5.QtWebKitWidgets import QWebPage 
     from PyQt5.QtWidgets import QApplication 

     class Render(QWebPage): 
      """Render HTML with PyQt5 WebKit.""" 

      def __init__(self, html): 
       self.html = None 
       self.app = QApplication(sys.argv) 
       QWebPage.__init__(self) 
       self.loadFinished.connect(self._loadFinished) 
       self.mainFrame().setHtml(html) 
       self.app.exec_() 

      def _loadFinished(self, result): 
       self.html = self.mainFrame().toHtml() 
       self.app.quit() 

    return Render(source_html).html 

或者PyQt4的Python中2

import sys 
from PyQt4.QtGui import QApplication 
from PyQt4.QtWebKit import QWebPage 


class Render(QWebPage): 

    """Fully render HTML, JavaScript and all.""" 

    def __init__(self, html): 
     self.app = QApplication(sys.argv) 
     QWebPage.__init__(self) 
     self.loadFinished.connect(self._loadFinished) 
     self.mainFrame().setHtml(html) 
     self.app.exec_() 

    def _loadFinished(self, result): 
     self.frame = self.mainFrame() 
     self.app.quit() 

render = Render(html) 
result = str(render.frame.toHtml().toAscii()) 
+0

我無法運行你的代碼,因爲我無法在PyQt5中找到QtWebKitWidgets模塊 – uday

+0

@uday你運行的是什麼版本的PyQt5?原代碼是爲v5.4.1編寫的。 WebKit此後不贊成使用WebEngine(它有很大的不同並使用異步API),因此可以解釋爲什麼您無法運行它。爲了支持v5.6,我更新了示例。我還沒有機會在v5.7上測試它,所以讓我知道你是否還有其他問題。 – Six

+0

非常感謝更新的版本。我認爲我有v5.6。我嘗試了你的新功能,但它似乎沒有工作。例如,我試圖從這個頁面中刪除表格:http://www.nasdaqomxnordic.com/optionsandfutures/microsite?工具= SE0000337842(順便說一句,由於查詢,表格可能需要一段時間才能加載該網頁) – uday