2016-02-06 24 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