Python 基于来自scrapy的信号在主线程内更新PyQt5 Gui

Python 基于来自scrapy的信号在主线程内更新PyQt5 Gui,python,python-3.x,pyqt,scrapy,pyqt5,Python,Python 3.x,Pyqt,Scrapy,Pyqt5,我有一个非常基本的蜘蛛,它看起来像是刮痧蜘蛛中的followall蜘蛛 重新导入 进口刮痧信号 从scrapy.http导入请求,HtmlResponse 从scrapy.LinkExtractor导入LinkExtractor 从six.moves.urllib.parse导入urlparse 从页面导入页面 类蜘蛛(刮毛蜘蛛): 定义初始化(自): super()。\uuuu init\uuuuu() name='followall' 自定义设置={ “CLOSESPIDER_PAGECOU

我有一个非常基本的蜘蛛,它看起来像是刮痧蜘蛛中的followall蜘蛛

重新导入
进口刮痧信号
从scrapy.http导入请求,HtmlResponse
从scrapy.LinkExtractor导入LinkExtractor
从six.moves.urllib.parse导入urlparse
从页面导入页面
类蜘蛛(刮毛蜘蛛):
定义初始化(自):
super()。\uuuu init\uuuuu()
name='followall'
自定义设置={
“CLOSESPIDER_PAGECOUNT”:2,
“提要”:{
“items.csv”:{“格式”:“csv”},
},
}
def初始功率(自身功率,**kw):
超级(天顶蜘蛛,自我)。\uuuuu初始功率(**kw)
url=kw.get('url')或kw.get('domain')或'http://scrapinghub.com/'
如果不是url.startswith('http://')而不是url.startswith('https://'):
url='http://%s/'%url
self.url=url
self.allowed_domains=[re.sub(r'^www'.','',urlparse(url.hostname)]
self.link_extractor=LinkExtractor()
def start_请求(自我):
return[请求(self.url,callback=self.parse,dont\u filter=True)]
def解析(自我,响应):
“”“分析一个页面项和所有要遵循的请求
@网址http://www.scrapinghub.com/
@返回项目1
@返回请求1
@抓取url标题foo
"""
页面=自我获取项目(响应)
r=[第页]
r、 扩展(自我提取请求(响应))
返回r
def_获取_项目(自我、响应):
项目=[]
项目=第页(
url=response.url,
size=str(len(response.body)),
status=response.status,
#content\u type=response.request.headers.get('content-type'),
#encoding=response.request.headers.get('encoding'),
#referer=response.request.headers.get('referer'),
)
自我设置标题(项目、响应)
自我设置描述(项目、响应)
退货项目
定义提取请求(自我、响应):
r=[]
如果存在(响应、HtmlResponse):
links=self.link\u提取器.extract\u链接(响应)
r、 对链接中的x进行扩展(请求(x.url,callback=self.parse)
返回r
定义设置标题(自我、页面、响应):
如果存在(响应、HtmlResponse):
title=response.xpath(“//title/text()”).extract()
如果标题为:
页面['title']=标题[0]
定义设置描述(自我、页面、响应):
如果存在(响应、HtmlResponse):
description=response.xpath(“//meta[@name='description']/@content”).extract()
如果说明:
页面['description']=说明[0]
我从下面的脚本中调用这个蜘蛛。爬行器使用CrawlRunner类运行,当它获取一个项目时,会发出一个信号p.signals.connect,该信号随后调用方法crawler\u results并打印刮下的项目

据我所知,我不能将爬行移动到它自己的类中,因为这样信号就不能与PyQt5一起工作

import scrapy
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import QRunnable, pyqtSlot, QThread, pyqtSignal, QTimer
from PyQt5.QtWidgets import QTableWidgetItem, QLabel
from scrapy import signals
from scrapy.crawler import CrawlerProcess, CrawlerRunner
from twisted.internet import reactor
from scrapy.utils.log import configure_logging

from Layout import Ui_MainWindow
from ZenSpider import ZenSpider


class MainWindow( QtWidgets.QMainWindow, Ui_MainWindow ) :

    def __init__(self, parent=None) :
        super(MainWindow, self).__init__()

        self.setupUi( self )
        self.pushButton.pressed.connect( self.on_url_entered )

    def crawler_results(self, item) :
        print( "SCRAPED AN ITEM" )
        ##Do Something here ##

    def on_url_entered(self) :
        # global userInput
        # userInput = self.urlbar.text()
        configure_logging()
        runner = CrawlerRunner()
        runner.crawl(ZenSpider, domain="google.com.au")
        for p in runner.crawlers :
            p.signals.connect(self.crawler_results, signal=signals.item_scraped)
        reactor.run()

if __name__ == "__main__" :
    app = QtWidgets.QApplication( [] )
    main_window = MainWindow()
    main_window.show()
    app.exec_()

我有一个布局,有一个简单的QTableWidget和一个按钮

#-*-编码:utf-8-*-
#从读取ui文件“basic.ui”生成的表单实现
#
#创建人:PyQt5 UI代码生成器5.14.2
#
#警告!在此文件中所做的所有更改都将丢失!
从PyQt5导入QtCore、QtGui、QtWidgets
类Ui_主窗口(对象):
def设置UI(自我,主窗口):
MainWindow.setObjectName(“MainWindow”)
主窗口。调整大小(1034803)
self.centralwidget=qtwidts.QWidget(主窗口)
self.centralwidget.setObjectName(“centralwidget”)
self.tableWidget=qtwidts.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(140200831401))
self.tableWidget.setObjectName(“tableWidget”)
self.tableWidget.setColumnCount(1)
self.tableWidget.setRowCount(0)
item=QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0,项)
self.pushButton=qtwidts.QPushButton(self.centralwidget)
自身按钮设置几何(QtCore.QRect(88061018925))
self.butdown.setObjectName(“butdown”)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar=qtwidts.QStatusBar(主窗口)
self.statusbar.setObjectName(“statusbar”)
main window.setStatusBar(self.statusbar)
自重传(主窗口)
QtCore.QMetaObject.connectSlotsByName(主窗口)
def重新传输(自身,主窗口):
_translate=QtCore.QCoreApplication.translate
setWindowTitle(_translate(“MainWindow”、“MainWindow”))
item=self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate(“主窗口”、“URL”))
self.putton.setText(_translate(“主窗口”、“开始”))
如果名称=“\uuuuu main\uuuuuuuu”:
导入系统
app=qtwidts.QApplication(sys.argv)
MainWindow=QtWidgets.QMainWindow()
ui=ui\u主窗口()
ui.setupUi(主窗口)
MainWindow.show()
sys.exit(app.exec_())
当我按下按钮时,我可以看到爬虫程序正在运行,并在打印刮下的项目时进入爬虫程序结果方法。spider将每个项目作为以下值返回

{'size': '164125',
 'status': 200,
 'title': 'Google Advanced Search',
 'url': 'https://www.google.com.au/advanced_search?hl=en-AU&authuser=0'}
页面只是我的零碎物品

import scrapy

class Page(scrapy.Item):
    url = scrapy.Field()
    size = scrapy.Field()
    status = scrapy.Field()
    title = scrapy.Field()

我的问题是,如何将这些数据转换到GUI中,并让它在爬行器运行时自动刷新。这意味着每次刮取项目时,GUI都会更新,然后爬行器会继续

到目前为止,我一直在探索

  • 运气不好就用刮痧
  • 插槽/信号,但我无法更新GUI
  • Qtimer函数每秒钟更新一次GUI,但同样不会产生任何结果

  • 非常感谢任何帮助

    您必须安装与Qt事件循环兼容的反应器,例如使用:

    • python-mpipinsta