身体在工位,灵魂已放假。摸的不是鱼,是心跳,是暂时逃离KPI的方舟。
学了这么久了爬虫,却一直没有在实际生活中使用过,正好上班闲得无聊,咱们来研究下如何利用爬虫“安全”地摸鱼。

首先确定我们要爬取的目标网站,这里以爬取小说《剑来》的内容为例。
工具准备:
1. Python3.10
2. PyCharm
3. request、bs4、textwrap、pyQt5等相关库
第一步,实现咱们的爬虫功能(核心!!!先看看爬取效果怎么样,如果先封装界面再实现爬虫功能,不是很方便查看爬取效果。)
打开咱们的PyCharm新建一个.py文件,名称自拟。
学过爬虫的都知道,接下来当然是引入咱们的爬虫库了(没学过的也别慌,因为这压根不是一个知识点啊🤡)
import requests # 爬虫库
from bs4 import BeautifulSoup # 解析页面
import textwrap # 处理文本
核心代码我直接端上来了,非常简单,即便是没有开深度思考的ds也能轻松实现。(注意后续完成界面封装后该部分还需要修改的。)
def auto_wrap_text(text, width=60):
return textwrap.fill(
text,
width=width,
break_long_words=True,
break_on_hyphens=True,
replace_whitespace=True
)
url = '目标网站'
headers = {
'User-Agent': '目标网站请求头'
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.encoding = response.apparent_encoding
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
# 定位目标div元素
content_div = soup.find('div', {'id': 'content', 'class': 'showtxt'})
if content_div:
# 保留原始换行符(处理<br>标签)
text_content = (((content_div.decode_contents(formatter="html").replace('<br/>', '')
.replace('<br>', '')
.replace("”", "")
.replace('“', '')
.replace('\t', '')
.replace('———— ', '')
.replace("。", "。\n")
.replace('?', '\n'))))
text_content = text_content.strip()
text_content = auto_wrap_text(text_content)
# 输出结果
print(text_content)
else:
print(f"请求失败,状态码:{response.status_code}")
except Exception as e:
print(f"发生错误:{str(e)}")
不知道怎么获取请求头?请看【VCR】⬇
访问目标网站后按【F12】,之后岸图中顺序依次点击


通过调整达到自己预期的爬取效果后咱们进入下一步。
第二步,封装界面
右键咱们的项目目录,选择【外部工具】➡【qtdesigner】

如果你没有这些工具,请参考:python-在PyCharm中使用PyQt5_pycharm pyqt5-CSDN博客
然后就可以根据自己的需要创建界面了。

使用PyUIC工具将.ui文件转成.py文件。

在生成的.py中加上下面的代码就可以显示界面了。
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(widget)
widget.show()
sys.exit(app.exec_())

接下来咱们对界面进行调整,直接展示调整后的页面和源码。
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'showtext.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class TransparentWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.ui = Ui_Form()
self.ui.setupUi(self)
# 设置窗口属性
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.setWindowFlags(
QtCore.Qt.FramelessWindowHint |
QtCore.Qt.WindowStaysOnTopHint
)
def showEvent(self, event):
# 窗口显示时定位到右下角
screen_geometry = QtWidgets.QApplication.desktop().availableGeometry()
self.move(
screen_geometry.right() - self.width(),
screen_geometry.bottom() - self.height()
)
super().showEvent(event)
def keyPressEvent(self, event):
# 按ESC键退出应用
if event.key() == QtCore.Qt.Key_Escape:
self.close()
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
# 设置窗口初始尺寸
Form.resize(550, 45)
# 使用垂直布局
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setContentsMargins(10, 10, 10, 10)
self.verticalLayout.setObjectName("verticalLayout")
# 创建文本框
self.plainTextEdit = QtWidgets.QPlainTextEdit(Form)
self.plainTextEdit.setObjectName("plainTextEdit")
# 设置文本框样式
self.plainTextEdit.setStyleSheet("""
QPlainTextEdit {
background-color: transparent; /* 完全透明背景 */
color: #FFFFFF; /* 纯白文字,完全不透明 */
font-size: 14px;
border: none;
padding: 0px;
}
QScrollBar {
background: transparent;
width: 0px;
height: 0px;
}
""")
# 设置字体
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(10)
self.plainTextEdit.setFont(font)
# 设置文本框为只读
self.plainTextEdit.setReadOnly(True)
# 设置示例文本
text = """这是一段测试文本,
用来测试文本框的显示效果。
"""
self.plainTextEdit.setPlainText(text)
# 添加布局
self.verticalLayout.addWidget(self.plainTextEdit)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "摸个大鱼"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
widget = TransparentWidget()
widget.show()
sys.exit(app.exec_())

是不是十分隐蔽?

接下来只要把咱们爬取到的内容绑定到这个文本框就行了!!!
创建一个新的界面用于输入目标网址和请求标头:

将爬虫部分的代码封装成一个线程类:
class CrawlerWorker(QObject):
data_ready = pyqtSignal(str) # 成功时发送数据
error_occurred = pyqtSignal(str) # 失败时发送错误信息
def __init__(self, url, user_agent):
super().__init__()
self.url = url
self.user_agent = user_agent
def process(self):
headers = {
'User-Agent': self.user_agent
}
try:
response = requests.get(self.url, headers=headers, timeout=10)
response.encoding = response.apparent_encoding
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
content_div = soup.find('div', {'id': 'content', 'class': 'showtxt'})
if content_div:
raw_text = content_div.decode_contents(formatter="html")
processed_text = (
raw_text
.replace('<br/>', '')
.replace('<br>', '')
.replace("”", "")
.replace('“', '')
.replace('\t', '')
.replace('———— ', '')
.replace("。", "。\n")
.replace('?', '?\n')
.strip()
)
wrapped_text = auto_wrap_text(processed_text)
print(wrapped_text)
self.data_ready.emit(wrapped_text)
else:
self.error_occurred.emit("未找到目标内容 <div>")
else:
self.error_occurred.emit(f"请求失败,状态码:{response.status_code}")
except Exception as e:
self.error_occurred.emit(f"发生错误:{str(e)}")
在主窗口中将【出发】按钮绑定到启动线程函数:
self.ui.pushButton.clicked.connect(self.start_fishing)
def start_fishing(self):
url = self.ui.ipaddress.text()
ua = self.ui.user_agent.text()
self.worker = CrawlerWorker(url, ua)
self.thread = QThread()
self.worker.moveToThread(self.thread)
self.worker.data_ready.connect(self.update_text)
self.worker.error_occurred.connect(self.show_error)
self.thread.started.connect(self.worker.process)
self.worker.data_ready.connect(self.thread.quit)
self.worker.error_occurred.connect(self.thread.quit)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.start()
将爬取到的文本更新到文本框并隐藏主窗口、显示文本窗口:
def update_text(self, text):
self.second_window.ui.plainTextEdit.setPlainText(text)
self.hide()
self.second_window.show()
接下来看看效果:
输入网址和请求头后点击【出发】

隐藏主窗口、显示文本框

可以开始摸鱼了!!!

还有一些细节上的东西文中没提到,后续会慢慢优化(毕竟我自己要用啊!)
源码在这:https://github.com/victory-fcs/request.git
不过咱这种“有手就行”的玩意儿,应该没人感兴趣和需要吧

771

被折叠的 条评论
为什么被折叠?



