2016-02-05 64 views
2

我想呈现在Java中编写的PyQt的网站。第一个站点呈现没有问题,并为我需要的信息而被抓取,但是当我想用同一个类来渲染另一个站点并检索新数据时,它告诉我Render类中定义的框架没有定义(这是为第一个网站定义,在检索我需要的数据时工作得很好)。 那么,为什么会发生这种情况呢?我在Python中缺少什么基础?我的理解是,当第一个站点已经被渲染时,对象将被垃圾收集,第二个可以被渲染。下面是指代码:如何使用一个类来刮两个网站

import sys 
from PyQt4.QtGui import * 
from PyQt4.QtCore import * 
from PyQt4.QtWebKit import * 
from lxml import html 

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() 

urls = ['http://pycoders.com/archive/', 'http://us4.campaign-archive2.com/home/?u=9735795484d2e4c204da82a29&id=64134e0a27'] 

for url in urls: 
    r = Render(url) 
    result = r.frame.toHtml() 
    #This step is important.Converting QString to Ascii for lxml to process 
    #QString should be converted to string before processed by lxml 
    formatted_result = str(result) 
    #Next build lxml tree from formatted_result 
    tree = html.fromstring(formatted_result) 
    #Now using correct Xpath we are fetching URL of archives 
    archive_links = tree.xpath('//div[@class="campaign"]/a/@href')[1:5] 
    print (archive_links) 

该错误消息我得到:

File "javaweb2.py", line 24, in <module> 
    result = r.frame.toHtml() 
AttributeError: 'Render' object has no attribute 'frame' 

任何帮助,将不胜感激!

回答

0

这是因为self.frame仅在调用self._loadFinished()时才被定义,仅当QWebPage实例发出信号时才会发生。所以,除非几个可疑的做法我在您发布的代码中看到的,下面就可以解决这个问题(不与****行很重要):

class Render(QWebPage): 
    def __init__(self, url): 
     self.app = QApplication(sys.argv) 
     self.frame = None # ***** 
     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() 

urls = ['http://pycoders.com/archive/', 'http://us4.campaign-archive2.com/home/?u=9735795484d2e4c204da82a29&id=64134e0a27'] 

for url in urls: 
    r = Render(url) 
    # wait till frame arrives: 
    while r.frame is None: 
     # pass # option 1: works, but will cause 100% cpu 
     time.sleep(0.1) # option 2: much better 

    result = r.frame.toHtml() 
    ... 

所以“通行证”的工作,但会消耗100 %cpu,因为循环每秒执行一百万次。使用定时器只会每1/10秒检查一次,并且CPU消耗非常低。

当然,最好的解决方案是将依赖于帧的逻辑(即当前处于URL循环中的代码在r=Render(url)以下)放入函数中,该函数在发射loadFinished信号时将被调用。由于您无法控制信号的顺序,因此最佳选择是将该代码移动到_loadfinished()方法中。

+0

我把建议的代码放入_loadfinished()方法中,并从主函数中调用类。它可以在一个url上正常工作,但只要我想一个接一个地呈现两个网站,它就会挂在第一个网站的第一个呈现对象上。看起来我不得不跳出渲染类(将范围从事件循环中移出)继续到第二个网站。有没有办法做到这一点?使用exit()只是退出程序。也许Python应用程序必须关闭并重新打开才能呈现下一页,这是不可能的,因为应用程序在终端中重新打开了? – PythonTAE

+0

你可以发布一个单独的问题与代码,因为你已经修复它。谢谢。 – Schollii

+0

这是另外一个问题:http://stackoverflow.com/questions/35311673/how-to-scrape-several-websites-with-pyqt4-scope-change – PythonTAE