如何使用一个 class 抓取两个网站
How to use one class to scrape two websites
我正在尝试在 PyQt 中呈现用 java 编写的网站。第一个站点呈现没有问题并抓取了我需要的信息,但是当我想使用相同的 class 呈现另一个站点并检索新数据时,它告诉我在 Render [=21] 中定义的框架=] 未定义(这是为第一个网站定义的,它在检索我需要的数据时工作得很好)。
那么,为什么会这样呢?我是否遗漏了 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'
如有任何帮助,我们将不胜感激!
那是因为 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()
...
所以 "pass" 可以工作,但会消耗 100% cpu 因为循环每秒执行一百万次。使用计时器仅每 1/10 秒检查一次,并且 cpu 消耗非常低。
当然,所有解决方案中最好的是将取决于可用框架的逻辑(即当前在 r=Render(url)
下面的 URL 循环中的代码)放在一个函数中,该函数将当发出 loadFinished
信号时被调用。由于您无法控制信号的顺序,因此最好的选择是将该代码移至 _loadfinished()
方法中。
我正在尝试在 PyQt 中呈现用 java 编写的网站。第一个站点呈现没有问题并抓取了我需要的信息,但是当我想使用相同的 class 呈现另一个站点并检索新数据时,它告诉我在 Render [=21] 中定义的框架=] 未定义(这是为第一个网站定义的,它在检索我需要的数据时工作得很好)。 那么,为什么会这样呢?我是否遗漏了 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'
如有任何帮助,我们将不胜感激!
那是因为 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()
...
所以 "pass" 可以工作,但会消耗 100% cpu 因为循环每秒执行一百万次。使用计时器仅每 1/10 秒检查一次,并且 cpu 消耗非常低。
当然,所有解决方案中最好的是将取决于可用框架的逻辑(即当前在 r=Render(url)
下面的 URL 循环中的代码)放在一个函数中,该函数将当发出 loadFinished
信号时被调用。由于您无法控制信号的顺序,因此最好的选择是将该代码移至 _loadfinished()
方法中。