From e5ff671c976646c6b0cff412df775aa46bd412d9 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 8 Nov 2023 16:09:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BE=93=E5=87=BA=E7=AE=80=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- main.ui | 315 ++++++++++++++++++++++++++--------- mycode/main.py | 12 +- requirements.txt | 3 +- start.py | 164 +++++++++++++----- summary/template_report.docx | Bin 0 -> 28668 bytes ui_mainwindow.py | 135 ++++++++++----- zcspider/middlewares.py | 11 ++ zcspider/settings.py | 5 + zcspider/spiders/base.py | 77 +++++---- 10 files changed, 524 insertions(+), 202 deletions(-) create mode 100644 summary/template_report.docx diff --git a/.gitignore b/.gitignore index f7e7641..af168f9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,9 @@ __pycache__/ twistd.pid ~$* *.xlsx -!template.xlsx +*.docx +!template*.xlsx +!template*.docx wechat_dir/* *.csv .idea/* diff --git a/main.ui b/main.ui index 42213ed..00dc8f7 100644 --- a/main.ui +++ b/main.ui @@ -7,7 +7,7 @@ 0 0 600 - 763 + 830 @@ -19,13 +19,13 @@ 600 - 763 + 830 600 - 763 + 830 @@ -123,70 +123,13 @@ - - - - 10 - 380 - 191 - 91 - - - - - 11 - - - - 2.确认分析对比库 - - - - - 20 - 30 - 151 - 24 - - - - background-color:#409EFF; color: white; border-radius: 2px - - - 打开分析标准Excel - - - - - - 20 - 60 - 151 - 16 - - - - - 楷体 - 10 - false - - - - color: red; - - - 请在修改后保存并关闭 - - - 10 - 650 + 540 581 - 71 + 121 @@ -195,13 +138,13 @@ - 最终结果 + 汇总分析 10 - 20 + 70 91 16 @@ -219,7 +162,7 @@ 10 - 40 + 90 91 16 @@ -237,7 +180,7 @@ 10 - 30 + 80 561 16 @@ -250,7 +193,7 @@ 110 - 15 + 65 381 21 @@ -268,7 +211,7 @@ 110 - 40 + 90 381 16 @@ -286,7 +229,7 @@ 520 - 10 + 60 51 24 @@ -302,7 +245,7 @@ 520 - 40 + 90 51 24 @@ -311,6 +254,71 @@ 打开 + + + + 20 + 30 + 151 + 24 + + + + + 11 + + + + background-color:#409EFF; color: white; border-radius: 2px + + + 打开分析标准Excel + + + + + + 180 + 30 + 151 + 16 + + + + + 楷体 + 11 + false + + + + color: red; + + + 请在修改后保存并关闭 + + + + + + 420 + 30 + 151 + 24 + + + + + 12 + + + + background-color:#409EFF; color: white; border-radius: 2px + + + 开始分析 + + @@ -345,10 +353,10 @@ - 210 + 220 280 371 - 361 + 251 @@ -357,7 +365,7 @@ - 日志显示 + 操作日志显示 @@ -365,7 +373,7 @@ 10 20 351 - 321 + 221 @@ -382,7 +390,7 @@ 10 - 490 + 380 191 151 @@ -393,7 +401,7 @@ - 2.确认需要抓取的网站 + 2.确认需要爬取的官网 @@ -491,7 +499,160 @@ background-color:#409EFF; color: white; border-radius: 2px - 开始巡查 + 开始爬取 + + + + + + + 10 + 670 + 581 + 111 + + + + + 11 + + + + 总院官微 + + + + + 10 + 60 + 91 + 16 + + + + + 10 + + + + 汇总结果Excel: + + + + + + 10 + 80 + 91 + 16 + + + + + 10 + + + + 汇总打分Excel: + + + + + + 10 + 70 + 561 + 16 + + + + Qt::Horizontal + + + + + + 110 + 55 + 381 + 21 + + + + + 9 + + + + + + + + + + 110 + 80 + 381 + 16 + + + + + 9 + + + + + + + + + + 520 + 50 + 51 + 24 + + + + background-color:#409EFF; color: white; border-radius: 2px + + + 打开 + + + + + + 520 + 80 + 51 + 24 + + + + 打开 + + + + + + 20 + 30 + 151 + 24 + + + + + 11 + + + + background-color:#409EFF; color: white; border-radius: 2px + + + 汇总打分 diff --git a/mycode/main.py b/mycode/main.py index 7f83388..b3ecc6c 100644 --- a/mycode/main.py +++ b/mycode/main.py @@ -1,7 +1,7 @@ import pandas as pd import os import sqlite3 -from .base import BASE_DIR +from mycode.base import BASE_DIR wechat_dir = os.path.join(BASE_DIR, 'article') web_dir = os.path.join(BASE_DIR, 'web_dir') @@ -53,6 +53,10 @@ def ana_wechat(): if not result.empty: for ind2, row2 in result.iterrows(): + if row['错误表述'] == '“两学一做”学习' and '“两学一做”学习教育' in row2['content']: + continue + if row['错误表述'] == '20大': + continue output_row = [ index, row2['nickname'], @@ -85,6 +89,10 @@ def ana_web(): result = df[mask] if not result.empty: for ind2, row2 in result.iterrows(): + if row['错误表述'] == '“两学一做”学习' and '“两学一做”学习教育' in row2['text']: + continue + if row['错误表述'] == '20大': + continue output_row = [ index, row2['name'], @@ -101,4 +109,6 @@ def ana_web(): return output_data +if __name__ == "__main__": + ana_web() diff --git a/requirements.txt b/requirements.txt index afd9d5c..04bbe22 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ openpyxl==3.1.2 scrapy-xlsx==0.1.1 selenium==4.9.1 pyside6==6.5.2 -pywin32==306 \ No newline at end of file +pywin32==306 +docxtpl==0.16.7 \ No newline at end of file diff --git a/start.py b/start.py index 8c5864e..847f0aa 100644 --- a/start.py +++ b/start.py @@ -13,6 +13,9 @@ import pandas as pd from urllib.parse import urlparse from openpyxl import load_workbook import threading +import traceback +from docxtpl import DocxTemplate +import json # from queue import Queue BASE_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -20,6 +23,8 @@ WEB_SITES_PATH = os.path.join(BASE_DIR, 'web_sites.xlsx') BIAO_PATH = os.path.join(BASE_DIR, 'biao.xlsx') PYTHON_PATH = os.path.join(BASE_DIR, 'runtime/python.exe') TEMPLATE_PATH = os.path.join(BASE_DIR, 'summary/template.xlsx') +TEMPLATE_REPORT_PATH = os.path.join(BASE_DIR, 'summary/template_report.docx') + def fix_url_scheme(url, default_scheme='http'): # 检查URL是否包含方案 @@ -37,26 +42,49 @@ class MyApplication(QApplication): self.main_window = MainWindow() return self.main_window -class MyThread(QThread): - update_signal = Signal(dict) +def gen_doc(w1, w2): + now = datetime.datetime.now() + now_3 = now - datetime.timedelta(days=3) + # with open('w2.json', 'r', encoding='utf-8') as f: + # w2 = json.loads(f.read()) + # with open('w1.json', 'r', encoding='utf-8') as f: + # w1 = json.loads(f.read()) + gdbs = 0 + yzbs = 0 + ybwz = 0 + zzcc = 0 + context = {'y': now.year, 'm': now.month, 'd': now.day, 'mo': now_3.month, 'do': now_3.day, 'su': 'xx', 'w1': w1, 'w2': w2} + output_report_path = os.path.join(BASE_DIR, f'summary/{now.year}年{now.month}月-分析结果简报.docx') + doc = DocxTemplate(TEMPLATE_REPORT_PATH) + for i in w1: + if i[5] == '固定表述错误': + gdbs =gdbs + 1 + elif i[5] == '严重表述错误': + yzbs = yzbs +1 + elif i[5] == '一般文字差错': + ybwz = ybwz +1 + elif i[5] == '政治差错': + zzcc = zzcc +1 + for i in w2: + if i[5] == '固定表述错误': + gdbs =gdbs + 1 + elif i[5] == '严重表述错误': + yzbs = yzbs +1 + elif i[5] == '一般文字差错': + ybwz = ybwz +1 + elif i[5] == '政治差错': + zzcc = zzcc +1 - def __init__(self, lsize) -> None: - super().__init__() - self.lsize = lsize - self.processes = [] - self.running = False + context['su'] = f'固定表述错误{gdbs}项, 严重表述错误{yzbs}项, 一般文字差错{ybwz}项, 政治差错{zzcc}项' + + doc.render(context) + doc.save(output_report_path) + return output_report_path +class AnaThread(QThread): + update_signal = Signal(object) - def capture_output(self, p): - while self.running and p.poll() is None: - output = p.stdout.readline() - err = p.stderr.readline() - if err: - self.update_signal.emit({'msg': err.strip()}) - if output: - self.update_signal.emit({'msg': output.strip()}) - def ana(self): - month = datetime.datetime.now().month + now = datetime.datetime.now() self.update_signal.emit({'msg': '对比开始...'}) self.update_signal.emit({'msg': '正在组合微信公众号爬取内容...'}) make_simple_csv_from_db() @@ -65,9 +93,10 @@ class MyThread(QThread): self.update_signal.emit({'msg': '开始对比分析所有内容...'}) wechat_results = ana_wechat() web_results = ana_web() - output_excel_path = os.path.join(BASE_DIR, f'summary/{month}月-总院宣传阵地巡查结果汇总表.xlsx') + # 生成汇总表 + self.update_signal.emit({'msg': '开始生成汇总表...'}) + output_excel_path = os.path.join(BASE_DIR, f'summary/{now.year}年{now.month}月-分析结果汇总表.xlsx') workbook = load_workbook(TEMPLATE_PATH) - # 选择要操作的工作表 wechat_sheet = workbook['公众号'] web_sheet = workbook['网站'] for row in wechat_results: @@ -76,7 +105,46 @@ class MyThread(QThread): web_sheet.append(row) workbook.save(output_excel_path) workbook.close() - self.update_signal.emit({'msg': '分析完毕, 请查看结果栏, 可手动校对', 'output_excel_path': output_excel_path}) + # with open('w1.json', 'w', encoding='utf-8') as f: + # f.write(json.dumps(wechat_results, ensure_ascii=False)) + + # with open('w2.json', 'w', encoding='utf-8') as f: + # f.write(json.dumps(web_results, ensure_ascii=False)) + # 生成简报 + self.update_signal.emit({'msg': '开始生成汇总简报...'}) + output_report_path = gen_doc(wechat_results, web_results) + self.update_signal.emit({'msg': '分析完毕, 请查看结果栏, 可手动校对', 'output_excel_path': output_excel_path, 'output_report_path': output_report_path}) + + def run(self) -> None: + try: + self.ana() + except Exception as e: + self.update_signal.emit({'msg': traceback.format_exc()}) + + +class MyThread(QThread): + update_signal = Signal(object) + + def __init__(self, lsize) -> None: + """ + lsize: 多少kb需要调取Chrome + """ + super().__init__() + self.lsize = lsize + self.processes = [] + self.running = False + + def capture_output(self, p): + while self.running and p.poll() is None: + output = p.stdout.readline() + if output: + self.update_signal.emit({'msg': output.strip()}) + + def capture_err(self, p): + while self.running and p.poll() is None: + err = p.stderr.readline() + if err: + self.update_signal.emit({'msg': err.strip()}) def run(self) -> None: self.update_signal.emit({'msg': '开始进行网站爬取...'}) @@ -95,6 +163,8 @@ class MyThread(QThread): self.running = True getlog_thread = threading.Thread(target=self.capture_output, args=(process,), daemon=True) getlog_thread.start() + getlog_thread_err = threading.Thread(target=self.capture_err, args=(process,), daemon=True) + getlog_thread_err.start() for process in self.processes: process.wait() @@ -114,8 +184,6 @@ class MyThread(QThread): self.update_signal.emit({'msg': '存在未爬取站点,正在调用Chrome继续爬取...'}) chrom_main_from_list(info_to_save) self.update_signal.emit({'msg': '网站爬取完毕!'}) - self.ana() - self.exec() def close(self): self.running = False @@ -129,7 +197,8 @@ class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() - self.worker_thread = None + self.web_thread = None + self.ana_thread = None self.wcplus = False self.logModel= QStringListModel([]) self.ui = Ui_MainWindow() @@ -139,6 +208,7 @@ class MainWindow(QMainWindow): self.ui.bWebSite.clicked.connect(self.open_websites_xlsx) self.ui.bBiao.clicked.connect(self.open_biao_xlsx) self.ui.bStart.clicked.connect(self.start) + self.ui.bAna.clicked.connect(self.start_ana) self.ui.bRes1.clicked.connect(self.open_res1) self.ui.bRes2.clicked.connect(self.open_res2) self.ui.vLog.setModel(self.logModel) @@ -170,9 +240,9 @@ class MainWindow(QMainWindow): def open_res2(self): if self.ui.lRes2.text(): - app = win32.Dispatch("Excel.Application") + app = win32.Dispatch("Word.Application") app.Visible = True - app.Workbooks.Open(self.ui.lRes2.text()) + app.Documents.Open(self.ui.lRes2.text()) app.WindowState = 3 def get_time(self): @@ -180,34 +250,45 @@ class MainWindow(QMainWindow): return now.strftime('%H:%M:%S') def start(self): - if self.ui.bStart.text() == '开始巡查' or self.ui.bStart.text() == '重新开始': + if self.ui.bStart.text() == '开始爬取' or self.ui.bStart.text() == '重新开始': self.log('', True) if self.res1Workbook: self.res1Workbook.Close() self.ui.lSize.setEnabled(False) - self.ui.bStart.setText('停止巡查') + self.ui.bStart.setText('停止爬取') self.start_web(int(self.ui.lSize.text())) - elif self.ui.bStart.text() == '停止巡查': + elif self.ui.bStart.text() == '停止爬取': self.update_log({'msg': '正在停止...'}) - if self.worker_thread: - self.worker_thread.close() + if self.web_thread: + self.web_thread.close() self.log('', True) self.ui.lSize.setEnabled(True) - self.ui.bStart.setText('开始巡查') + self.ui.bStart.setText('开始爬取') def start_web(self, lsize): - self.worker_thread = MyThread(lsize) - self.worker_thread.update_signal.connect(self.update_log) - self.worker_thread.start() + self.web_thread = MyThread(lsize) + self.web_thread.update_signal.connect(self.update_log) + self.web_thread.start() + def start_ana(self): + self.ana_thread = AnaThread() + self.ana_thread.update_signal.connect(self.update_log) + self.ana_thread.start() def update_log(self, rdict): - self.log(f'{self.get_time()}-{rdict["msg"]}', False) - if 'output_excel_path' in rdict: - self.ui.lRes1.setText(rdict['output_excel_path']) - self.ui.bStart.setText('重新开始') - self.ui.lSize.setEnabled(True) + if isinstance(rdict, str): + self.log(f'{self.get_time()}-{rdict}', False) + elif isinstance(rdict, dict): + self.log(f'{self.get_time()}-{rdict["msg"]}', False) + if 'output_report_path' in rdict: + self.ui.lRes2.setText(rdict['output_report_path']) + # self.ui.bStart.setText('重新开始') + # self.ui.lSize.setEnabled(True) + if 'output_excel_path' in rdict: + self.ui.lRes1.setText(rdict['output_excel_path']) + # self.ui.bStart.setText('重新开始') + # self.ui.lSize.setEnabled(True) def log(self, logLine: str, clear=False): log_list = self.logModel.stringList() @@ -228,12 +309,13 @@ class MainWindow(QMainWindow): except Exception as e: print(f"Error while terminating wcplus.exe: {str(e)}") self.wcplus = False - if self.worker_thread: - self.worker_thread.close() + if self.web_thread: + self.web_thread.close() event.accept() if __name__ == "__main__": + # gen_doc() app = MyApplication(sys.argv) main_window = app.createMainWindow() main_window.show() diff --git a/summary/template_report.docx b/summary/template_report.docx new file mode 100644 index 0000000000000000000000000000000000000000..13dc734f0551a4591b195ec660a25a1cf50edc09 GIT binary patch literal 28668 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 literal 0 HcmV?d00001 diff --git a/ui_mainwindow.py b/ui_mainwindow.py index f849192..38d6bb9 100644 --- a/ui_mainwindow.py +++ b/ui_mainwindow.py @@ -23,14 +23,14 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") - MainWindow.resize(600, 763) + MainWindow.resize(600, 830) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) - MainWindow.setMinimumSize(QSize(600, 763)) - MainWindow.setMaximumSize(QSize(600, 763)) + MainWindow.setMinimumSize(QSize(600, 830)) + MainWindow.setMaximumSize(QSize(600, 830)) icon = QIcon() icon.addFile(u"start.ico", QSize(), QIcon.Normal, QIcon.Off) MainWindow.setWindowIcon(icon) @@ -63,79 +63,87 @@ class Ui_MainWindow(object): font1.setBold(False) self.label_5.setFont(font1) self.label_5.setStyleSheet(u"color: red;") - self.groupBox_3 = QGroupBox(self.centralwidget) - self.groupBox_3.setObjectName(u"groupBox_3") - self.groupBox_3.setGeometry(QRect(10, 380, 191, 91)) - self.groupBox_3.setFont(font) - self.bBiao = QPushButton(self.groupBox_3) - self.bBiao.setObjectName(u"bBiao") - self.bBiao.setGeometry(QRect(20, 30, 151, 24)) - self.bBiao.setStyleSheet(u"background-color:#409EFF; color: white; border-radius: 2px") - self.label_4 = QLabel(self.groupBox_3) - self.label_4.setObjectName(u"label_4") - self.label_4.setGeometry(QRect(20, 60, 151, 16)) - self.label_4.setFont(font1) - self.label_4.setStyleSheet(u"color: red;") self.groupBox_5 = QGroupBox(self.centralwidget) self.groupBox_5.setObjectName(u"groupBox_5") - self.groupBox_5.setGeometry(QRect(10, 650, 581, 71)) + self.groupBox_5.setGeometry(QRect(10, 540, 581, 121)) self.groupBox_5.setFont(font) self.label_7 = QLabel(self.groupBox_5) self.label_7.setObjectName(u"label_7") - self.label_7.setGeometry(QRect(10, 20, 91, 16)) + self.label_7.setGeometry(QRect(10, 70, 91, 16)) font2 = QFont() font2.setPointSize(10) self.label_7.setFont(font2) self.label_8 = QLabel(self.groupBox_5) self.label_8.setObjectName(u"label_8") - self.label_8.setGeometry(QRect(10, 40, 91, 16)) + self.label_8.setGeometry(QRect(10, 90, 91, 16)) self.label_8.setFont(font2) self.line = QFrame(self.groupBox_5) self.line.setObjectName(u"line") - self.line.setGeometry(QRect(10, 30, 561, 16)) + self.line.setGeometry(QRect(10, 80, 561, 16)) self.line.setFrameShape(QFrame.HLine) self.line.setFrameShadow(QFrame.Sunken) self.lRes1 = QLabel(self.groupBox_5) self.lRes1.setObjectName(u"lRes1") - self.lRes1.setGeometry(QRect(110, 15, 381, 21)) + self.lRes1.setGeometry(QRect(110, 65, 381, 21)) font3 = QFont() font3.setPointSize(9) self.lRes1.setFont(font3) self.lRes2 = QLabel(self.groupBox_5) self.lRes2.setObjectName(u"lRes2") - self.lRes2.setGeometry(QRect(110, 40, 381, 16)) + self.lRes2.setGeometry(QRect(110, 90, 381, 16)) self.lRes2.setFont(font3) self.bRes1 = QPushButton(self.groupBox_5) self.bRes1.setObjectName(u"bRes1") - self.bRes1.setGeometry(QRect(520, 10, 51, 24)) + self.bRes1.setGeometry(QRect(520, 60, 51, 24)) self.bRes1.setStyleSheet(u"background-color:#409EFF; color: white; border-radius: 2px") self.bRes2 = QPushButton(self.groupBox_5) self.bRes2.setObjectName(u"bRes2") - self.bRes2.setGeometry(QRect(520, 40, 51, 24)) + self.bRes2.setGeometry(QRect(520, 90, 51, 24)) + self.bBiao = QPushButton(self.groupBox_5) + self.bBiao.setObjectName(u"bBiao") + self.bBiao.setGeometry(QRect(20, 30, 151, 24)) + self.bBiao.setFont(font) + self.bBiao.setStyleSheet(u"background-color:#409EFF; color: white; border-radius: 2px") + self.label_4 = QLabel(self.groupBox_5) + self.label_4.setObjectName(u"label_4") + self.label_4.setGeometry(QRect(180, 30, 151, 16)) + font4 = QFont() + font4.setFamilies([u"\u6977\u4f53"]) + font4.setPointSize(11) + font4.setBold(False) + self.label_4.setFont(font4) + self.label_4.setStyleSheet(u"color: red;") + self.bAna = QPushButton(self.groupBox_5) + self.bAna.setObjectName(u"bAna") + self.bAna.setGeometry(QRect(420, 30, 151, 24)) + font5 = QFont() + font5.setPointSize(12) + self.bAna.setFont(font5) + self.bAna.setStyleSheet(u"background-color:#409EFF; color: white; border-radius: 2px") self.label_9 = QLabel(self.centralwidget) self.label_9.setObjectName(u"label_9") self.label_9.setGeometry(QRect(150, 0, 291, 31)) - font4 = QFont() - font4.setFamilies([u"\u6977\u4f53"]) - font4.setPointSize(12) - font4.setBold(False) - font4.setItalic(False) - self.label_9.setFont(font4) + font6 = QFont() + font6.setFamilies([u"\u6977\u4f53"]) + font6.setPointSize(12) + font6.setBold(False) + font6.setItalic(False) + self.label_9.setFont(font6) self.label_9.setStyleSheet(u"color:white;") self.label_9.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) self.label_9.setMargin(6) self.groupBox_6 = QGroupBox(self.centralwidget) self.groupBox_6.setObjectName(u"groupBox_6") - self.groupBox_6.setGeometry(QRect(210, 280, 371, 361)) + self.groupBox_6.setGeometry(QRect(220, 280, 371, 251)) self.groupBox_6.setFont(font) self.vLog = QListView(self.groupBox_6) self.vLog.setObjectName(u"vLog") - self.vLog.setGeometry(QRect(10, 20, 351, 321)) + self.vLog.setGeometry(QRect(10, 20, 351, 221)) self.vLog.setFont(font3) self.vLog.setStyleSheet(u"") self.groupBox_2 = QGroupBox(self.centralwidget) self.groupBox_2.setObjectName(u"groupBox_2") - self.groupBox_2.setGeometry(QRect(10, 490, 191, 151)) + self.groupBox_2.setGeometry(QRect(10, 380, 191, 151)) self.groupBox_2.setFont(font) self.bWebSite = QPushButton(self.groupBox_2) self.bWebSite.setObjectName(u"bWebSite") @@ -158,10 +166,45 @@ class Ui_MainWindow(object): self.bStart = QPushButton(self.groupBox_2) self.bStart.setObjectName(u"bStart") self.bStart.setGeometry(QRect(20, 110, 151, 24)) - font5 = QFont() - font5.setPointSize(12) self.bStart.setFont(font5) self.bStart.setStyleSheet(u"background-color:#409EFF; color: white; border-radius: 2px") + self.groupBox_7 = QGroupBox(self.centralwidget) + self.groupBox_7.setObjectName(u"groupBox_7") + self.groupBox_7.setGeometry(QRect(10, 670, 581, 111)) + self.groupBox_7.setFont(font) + self.label_10 = QLabel(self.groupBox_7) + self.label_10.setObjectName(u"label_10") + self.label_10.setGeometry(QRect(10, 60, 91, 16)) + self.label_10.setFont(font2) + self.label_11 = QLabel(self.groupBox_7) + self.label_11.setObjectName(u"label_11") + self.label_11.setGeometry(QRect(10, 80, 91, 16)) + self.label_11.setFont(font2) + self.line_2 = QFrame(self.groupBox_7) + self.line_2.setObjectName(u"line_2") + self.line_2.setGeometry(QRect(10, 70, 561, 16)) + self.line_2.setFrameShape(QFrame.HLine) + self.line_2.setFrameShadow(QFrame.Sunken) + self.lCalRes1 = QLabel(self.groupBox_7) + self.lCalRes1.setObjectName(u"lCalRes1") + self.lCalRes1.setGeometry(QRect(110, 55, 381, 21)) + self.lCalRes1.setFont(font3) + self.lCalRes2 = QLabel(self.groupBox_7) + self.lCalRes2.setObjectName(u"lCalRes2") + self.lCalRes2.setGeometry(QRect(110, 80, 381, 16)) + self.lCalRes2.setFont(font3) + self.bOpenCalRes1 = QPushButton(self.groupBox_7) + self.bOpenCalRes1.setObjectName(u"bOpenCalRes1") + self.bOpenCalRes1.setGeometry(QRect(520, 50, 51, 24)) + self.bOpenCalRes1.setStyleSheet(u"background-color:#409EFF; color: white; border-radius: 2px") + self.bOpenCalRes2 = QPushButton(self.groupBox_7) + self.bOpenCalRes2.setObjectName(u"bOpenCalRes2") + self.bOpenCalRes2.setGeometry(QRect(520, 80, 51, 24)) + self.bCal = QPushButton(self.groupBox_7) + self.bCal.setObjectName(u"bCal") + self.bCal.setGeometry(QRect(20, 30, 151, 24)) + self.bCal.setFont(font) + self.bCal.setStyleSheet(u"background-color:#409EFF; color: white; border-radius: 2px") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menubar.setObjectName(u"menubar") @@ -182,24 +225,32 @@ class Ui_MainWindow(object): self.groupBox.setTitle(QCoreApplication.translate("MainWindow", u"1.\u5fae\u4fe1\u516c\u4f17\u53f7\u4fe1\u606f\u6293\u53d6", None)) self.bWechat.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00\u5de5\u5177", None)) self.label_5.setText(QCoreApplication.translate("MainWindow", u"\u8bf7\u786e\u4fdd\u6240\u6709\u516c\u4f17\u53f7\u6293\u53d6\u5b8c\u6bd5", None)) - self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow", u"2.\u786e\u8ba4\u5206\u6790\u5bf9\u6bd4\u5e93", None)) - self.bBiao.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00\u5206\u6790\u6807\u51c6Excel", None)) - self.label_4.setText(QCoreApplication.translate("MainWindow", u"\u8bf7\u5728\u4fee\u6539\u540e\u4fdd\u5b58\u5e76\u5173\u95ed", None)) - self.groupBox_5.setTitle(QCoreApplication.translate("MainWindow", u"\u6700\u7ec8\u7ed3\u679c", None)) + self.groupBox_5.setTitle(QCoreApplication.translate("MainWindow", u"\u6c47\u603b\u5206\u6790", None)) self.label_7.setText(QCoreApplication.translate("MainWindow", u"\u5206\u6790\u7ed3\u679cExcel:", None)) self.label_8.setText(QCoreApplication.translate("MainWindow", u"\u5206\u6790\u62a5\u544aWord:", None)) self.lRes1.setText("") self.lRes2.setText("") self.bRes1.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00", None)) self.bRes2.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00", None)) + self.bBiao.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00\u5206\u6790\u6807\u51c6Excel", None)) + self.label_4.setText(QCoreApplication.translate("MainWindow", u"\u8bf7\u5728\u4fee\u6539\u540e\u4fdd\u5b58\u5e76\u5173\u95ed", None)) + self.bAna.setText(QCoreApplication.translate("MainWindow", u"\u5f00\u59cb\u5206\u6790", None)) self.label_9.setText(QCoreApplication.translate("MainWindow", u"\u4e2d\u56fd\u5efa\u6750\u603b\u9662\u5ba3\u4f20\u5de5\u4f5c\u4fe1\u606f\u5316\u7ba1\u7406\u5e73\u53f0", None)) - self.groupBox_6.setTitle(QCoreApplication.translate("MainWindow", u"\u65e5\u5fd7\u663e\u793a", None)) - self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow", u"2.\u786e\u8ba4\u9700\u8981\u6293\u53d6\u7684\u7f51\u7ad9", None)) + self.groupBox_6.setTitle(QCoreApplication.translate("MainWindow", u"\u64cd\u4f5c\u65e5\u5fd7\u663e\u793a", None)) + self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow", u"2.\u786e\u8ba4\u9700\u8981\u722c\u53d6\u7684\u5b98\u7f51", None)) self.bWebSite.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00\u7f51\u7ad9\u5217\u8868Excel", None)) self.label_2.setText(QCoreApplication.translate("MainWindow", u"\u8bf7\u5728\u4fee\u6539\u540e\u4fdd\u5b58\u5e76\u5173\u95ed", None)) self.label_6.setText(QCoreApplication.translate("MainWindow", u"\u5c0f\u4e8e", None)) self.label_3.setText(QCoreApplication.translate("MainWindow", u"KB-Chrome", None)) self.lSize.setText(QCoreApplication.translate("MainWindow", u"20", None)) - self.bStart.setText(QCoreApplication.translate("MainWindow", u"\u5f00\u59cb\u5de1\u67e5", None)) + self.bStart.setText(QCoreApplication.translate("MainWindow", u"\u5f00\u59cb\u722c\u53d6", None)) + self.groupBox_7.setTitle(QCoreApplication.translate("MainWindow", u"\u603b\u9662\u5b98\u5fae", None)) + self.label_10.setText(QCoreApplication.translate("MainWindow", u"\u6c47\u603b\u7ed3\u679cExcel:", None)) + self.label_11.setText(QCoreApplication.translate("MainWindow", u"\u6c47\u603b\u6253\u5206Excel:", None)) + self.lCalRes1.setText("") + self.lCalRes2.setText("") + self.bOpenCalRes1.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00", None)) + self.bOpenCalRes2.setText(QCoreApplication.translate("MainWindow", u"\u6253\u5f00", None)) + self.bCal.setText(QCoreApplication.translate("MainWindow", u"\u6c47\u603b\u6253\u5206", None)) # retranslateUi diff --git a/zcspider/middlewares.py b/zcspider/middlewares.py index 139f8ab..4551b5a 100644 --- a/zcspider/middlewares.py +++ b/zcspider/middlewares.py @@ -4,6 +4,7 @@ # https://docs.scrapy.org/en/latest/topics/spider-middleware.html from scrapy import signals +from scrapy.http import HtmlResponse # useful for handling different item types with a single interface from itemadapter import is_item, ItemAdapter @@ -101,3 +102,13 @@ class ZcspiderDownloaderMiddleware: def spider_opened(self, spider): spider.logger.info("Spider opened: %s" % spider.name) + + +class FilterHTMLMiddleware: + def process_response(self, request, response, spider): + if isinstance(response, HtmlResponse): + # 只接收HTML响应 + return response + else: + # 忽略其他类型的资源文件 + return request \ No newline at end of file diff --git a/zcspider/settings.py b/zcspider/settings.py index 6e4f619..1736130 100644 --- a/zcspider/settings.py +++ b/zcspider/settings.py @@ -105,4 +105,9 @@ ITEM_PIPELINES = { FEED_EXPORTERS = { # 'xlsx': 'scrapy_xlsx.XlsxItemExporter', +} + +DOWNLOADER_MIDDLEWARES = { + 'zcspider.middlewares.FilterHTMLMiddleware': 200, + # 其他下载中间件... } \ No newline at end of file diff --git a/zcspider/spiders/base.py b/zcspider/spiders/base.py index 18bd884..060c995 100644 --- a/zcspider/spiders/base.py +++ b/zcspider/spiders/base.py @@ -39,12 +39,14 @@ class BaseSpider(scrapy.Spider): def start_requests(self): for url in self.start_urls: url = self.fix_url_scheme(url) - r = scrapy.Request(url, dont_filter=True, headers=self.headers, callback=self.parse, errback=self.request2, meta={'download_timeout': 30}) + self.visited_urls.add(url) + r = scrapy.Request(url, dont_filter=True, headers=self.headers, callback=self.parse, meta={'download_timeout': 30}) yield r def is_file_url(self, url): - if f'.{url.split(".")[-1].lower()}' in self.ext: - return True + for item in self.ext: + if url.lower().endswith(item): + return True return False def is_file_res(self, res): @@ -82,42 +84,39 @@ class BaseSpider(scrapy.Spider): yield scrapy.Request(full_link, callback=self.parse, headers=self.headers, errback=self.request2, meta={'download_timeout': 30}) def parse(self, response): - try: - if response.status >= 500: - return - self.visited_urls.add(response.url) - if self.is_file_res(response): - return - h = html2text.HTML2Text() - h.ignore_links = True # 忽略所有链接 - # 提取纯文本内容 - # try: - text = h.handle(response.text) - # except: - # text = h.handle(response.body.decode(encoding='gb18030')) - if response.status < 400: - yield { - 'group': self.group, - 'name': self.name, - 'domain': self.domain, - 'url': response.url, - 'text': text, - } - links = re.findall(r'href=["\']?([^"\'>]+)', response.text) - for link in links: - full_link = response.urljoin(link) - if not full_link.startswith('http'): - continue - if full_link not in self.visited_urls and (self.is_file_url(full_link) is False): - if urlparse(full_link).netloc.replace('www.', '') == self.domain: - # try: - yield scrapy.Request(full_link, callback=self.parse, headers=self.headers, errback=self.request2, meta={'download_timeout': 30}) - # except ValueError: - # import traceback - # print(traceback.format_exc()) - # print(full_link) - except scrapy.exceptions.TimeoutError: - print(f'{response.url}-请求超时取消') + if response.status >= 500: + return + if self.is_file_res(response): + return + h = html2text.HTML2Text() + h.ignore_links = True # 忽略所有链接 + # 提取纯文本内容 + # try: + text = h.handle(response.text) + # except: + # text = h.handle(response.body.decode(encoding='gb18030')) + if response.status < 400: + yield { + 'group': self.group, + 'name': self.name, + 'domain': self.domain, + 'url': response.url, + 'text': text, + } + links = re.findall(r'href=["\']?([^"\'>]+)', response.text) + for link in links: + full_link = response.urljoin(link) + if not full_link.startswith('http'): + continue + if full_link not in self.visited_urls and (self.is_file_url(full_link) is False): + if urlparse(full_link).netloc.replace('www.', '') == self.domain: + self.visited_urls.add(response.url) + # try: + yield scrapy.Request(full_link, callback=self.parse, headers=self.headers, meta={'download_timeout': 30}) + # except ValueError: + # import traceback + # print(traceback.format_exc()) + # print(full_link) def closed(self, reason): # This method will be called when the Spider is about to close