在Django中使用QT进行一次刮擦工作一次,在下一次运行时崩溃,QApplication未在main()线程

时间:2015-07-28 15:15:32

标签: python django multithreading qt

我正在创建一个基于Django的scraper,用户可以在其中输入搜索词。我使用该搜索词来构建URL并查询该站点,然后返回未呈现的HTML和JS。然后,我可以接受发布请求,通过创建Qwebpage呈现页面,将URL传递给URL并抓取框架的呈现HTML。这在我的Django应用程序中运行一次,下一个POST请求崩溃了该站点。

我首先担心的是,在当前的设置中,我被迫使用xvfb-run包装器来运行。这会在我部署时出现问题 - 更好的问题是:我能以某种方式在生产中使用xvfb包装吗?

据说我可以发一个帖子请求,这会返回我正在寻找的页面。如果我回击并发送另一个请求,我在控制台中看到以下错误,然后关闭./manage.py服务器:

WARNING: QApplication was not created in the main() thread.
QObject::connect: Cannot connect (null)::configurationAdded(QNetworkConfiguration) to QNetworkConfigurationManager::configurationAdded(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationRemoved(QNetworkConfiguration) to QNetworkConfigurationManager::configurationRemoved(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationChanged(QNetworkConfiguration) to QNetworkConfigurationManager::configurationChanged(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::onlineStateChanged(bool) to QNetworkConfigurationManager::onlineStateChanged(bool)
QObject::connect: Cannot connect (null)::configurationUpdateComplete() to QNetworkConfigurationManager::updateCompleted()
Segmentation fault (core dumped)

我承认我不明白错误是什么,因为我对线程概念很新。我不确定这个错误是否意味着它不能重新连接到已经运行的xvfb包装器,或者它确实是一个线程问题。有效的代码就在这里。由于我不想显示我实际抓取的网站,因此略有改变。此外,我不是在寻找此示例中的数据。此示例将简单地将呈现的HTML作为测试提供给您的浏览器:

import sys
from django.shortcuts import render

# Create your views here.
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.views.generic import View
from PyQt4.QtGui import *  
from PyQt4.QtCore import *  
from PyQt4.QtWebKit import * 
from bs4 import BeautifulSoup 

from .forms import QueryForm

def query(request):
        results = google.search("Real Estate")
        context = {'results': results}
        return render(request, 'searchlistings/search.html', context)

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

class SearchView(View):
    form_class = QueryForm
    template_name = 'searchlistings/index.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class()
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            query = form.cleaned_data['query']
            context = self.isOnSite(query)
            #return context
            #return render(request, 'searchlistings/search.html', {'context': context})
            return HttpResponse(context)

    def isOnSite(self, query):
        url = "http://google.com"
        #This does the magic.Loads everything
        r = Render(url)  
        #result is a QString.
        result = r.frame.toHtml()
        r.app.quit()
        return result;

所以我的主要问题是:

  1. 这里的XVFB包装器是否合适,我是否可以在不同的主机上使用此设置。这不会在我当地的流浪盒上工作吗?

  2. main()线程问题 - 这是一个线程问题还是没有连接回xvfb服务器的问题?这个问题可以通过Celery或类似方法解决吗?

  3. 这是做我想要的合适方式吗?我已经看到很多其他解决方案,包括scrapyjs,spynner,selenium等,但它们看起来要么过于复杂,要么基于QT。一个更好的问题是这些替代包中的任何一个解决了main()线程问题吗?

  4. 感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

确定这里的解决方案是使用twill,如此处所记录的http://twill.idyll.org/python-api.html - 我能够在没有xvfb包装器的情况下运行它,并且它比以前的方法快得多,而且开销更少。我可以推荐这个。