杰瑞科技汇

Python QtWebKit爬虫还能用吗?

QtWebKit 已经被废弃了,它最后一次重要的更新是在 Qt 5.5 版本中,之后就被更现代、性能更好的 QtWebEngine 所取代。

Python QtWebKit爬虫还能用吗?-图1
(图片来源网络,侵删)

我强烈建议你直接学习和使用 QtWebEngine,而不是 QtWebKit,QtWebEngine 基于 Chromium,支持最新的网页标准、JavaScript 和 CSS,性能更好,也更稳定。

为了满足你的问题,我会先解释为什么 QtWebKit 不再是首选,然后提供一个使用 PyQt5/PySide2 和 QtWebEngine 的现代、可行的爬虫方案,并附上详细代码和解释。


为什么不推荐使用 QtWebKit?

  1. 已废弃:Qt 官方已经停止维护,不会再修复安全漏洞或兼容性问题。
  2. 兼容性差:无法渲染现代网页,很多网站会显示不正常或功能缺失。
  3. 性能低下:基于老旧的 WebKit 内核,远不如基于 Chromium 的 QtWebEngine。
  4. 依赖问题:旧版本的 Python 绑定(如 PyQt4)安装和使用都比较麻烦。

推荐方案:Python + PyQt5/PySide2 + QtWebEngine

这个组合是目前进行自动化网页交互、爬取动态内容的最佳选择之一,它能够模拟一个真实的浏览器,执行 JavaScript,并获取渲染后的页面内容。

核心组件

  • Python: 编程语言。
  • PyQt5 或 PySide2: Python 的 Qt 绑定库,我们使用它们来创建窗口、控件,并与 Qt 的 Web 引擎交互。
    • PyQt5 是商业公司维护,有商业版和社区版。
    • PySide2 是 Qt 官方维护,完全开源免费,两者用法几乎完全相同,这里我们以 PyQt5 为例。
  • QtWebEngine: Qt 的现代化 Web 引擎,用于加载和显示网页。
  • QWebEngineView: 一个可以嵌入到 PyQt 窗口中的浏览器控件。
  • QWebEnginePage: 代表一个网页,提供更底层的控制,如执行 JavaScript、获取页面标题等。
  • Selenium: 一个非常流行的 Web 自动化测试工具,好消息是,Selenium 4+ 已经原生支持基于 Chromium/Edge/Firefox 的浏览器,不再需要 WebDriver,使用起来非常简单,对于绝大多数爬虫场景,Selenium + driver.get() 是更简单、更强大的选择。

下面,我将展示两种方法:

Python QtWebKit爬虫还能用吗?-图2
(图片来源网络,侵删)
  1. 原生 PyQt5 方法:适合需要深度集成 Qt 应用,或者学习 Qt Web 引擎内部工作原理的场景。
  2. Selenium 方法更推荐,更简单,功能更强大,是业界标准。

原生 PyQt5 + QtWebEngine 爬虫

这种方法让你完全控制浏览器的生命周期和窗口显示。

安装依赖

你需要安装 PyQt5,由于它包含了 Qt 的所有模块,体积较大。

pip install PyQt5

示例代码:爬取动态加载的图片链接

这个例子会打开一个浏览器窗口,访问一个动态加载内容的网站(Bing 每日壁纸),等待页面加载完成后,打印页面的标题和所有图片链接。

import sys
import time
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
class BrowserCrawler(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PyQt5 WebEngine Crawler")
        self.setGeometry(100, 100, 1024, 768)
        # 创建浏览器控件
        self.browser = QWebEngineView()
        # 创建一个垂直布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        layout.addWidget(self.browser)
        # 创建一个按钮,用于触发爬取动作
        self.crawl_button = QPushButton("爬取当前页面信息")
        self.crawl_button.clicked.connect(self.start_crawling)
        layout.addWidget(self.crawl_button)
        # 连接页面加载信号
        # self.browser.page().loadFinished.connect(self.page_loaded) # 方式1:页面加载完成即触发
        self.browser.page().loadFinished.connect(self.on_load_finished)
        # 加载一个需要JavaScript渲染的网站
        # self.browser.setUrl(QUrl("https://www.bing.com"))
        self.browser.setUrl(QUrl("https://quotes.toscrape.com/js/")) # 一个专门用来测试爬虫的网站
    def on_load_finished(self, ok):
        """页面加载完成后的回调"""
        if ok:
            print("页面加载成功!")
            # 可以在这里执行JavaScript,获取内容
            # self.get_page_links()
            # 为了演示,我们延迟一下,确保所有JS都执行完了
            self.browser.page().runJavaScript("window.setTimeout(() => { console.log('All dynamic content loaded'); }, 2000);")
            # 方式2:等待一段时间再爬取,简单但不可靠
            # QApplication.processEvents()
            # time.sleep(3)
            # self.get_page_links()
    def start_crawling(self):
        """通过按钮触发爬取"""
        print("开始爬取页面内容...")
        self.get_page_links()
    def get_page_links(self):
        """执行JavaScript获取所有图片链接"""
        js_code = """
            // 获取页面上的所有 <img> 标签
            var images = document.getElementsByTagName('img');
            var links = [];
            for (var i = 0; i < images.length; i++) {
                links.push(images[i].src);
            }
            // 返回链接数组
            links;
        """
        # 执行JS代码,并将结果传递给回调函数
        self.browser.page().runJavaScript(js_code, self.handle_js_result)
    def handle_js_result(self, result):
        """处理JavaScript执行返回的结果"""
        print("\n--- 获取到的图片链接 ---")
        if result:
            for link in result:
                print(link)
        else:
            print("未找到图片链接。")
        print("------------------------\n")
    def closeEvent(self, event):
        """窗口关闭时的事件"""
        print("爬虫窗口已关闭。")
        event.accept()
if __name__ == '__main__':
    app = QApplication(sys.argv)
    crawler = BrowserCrawler()
    crawler.show()
    sys.exit(app.exec_())

代码解释:

Python QtWebKit爬虫还能用吗?-图3
(图片来源网络,侵删)
  1. QWebEngineView: 这是浏览器窗口的核心。
  2. loadFinished 信号: 当页面(包括所有资源如图片、CSS、JS)加载完成时,会发射这个信号,这是我们开始执行爬取逻辑的绝佳时机。
  3. runJavaScript(code, callback): 这是关键方法,它可以在当前页面执行任意 JavaScript 代码,并将执行结果通过 callback 函数返回给 Python,这使得我们可以获取由 JavaScript 动态生成的内容。
  4. JavaScript 代码: 我们写的 JS 代码和浏览器开发者工具里写的一样,用来操作 DOM(文档对象模型)并提取我们需要的数据。
  5. handle_js_result: 这是一个回调函数,runJavaScript 执行完毕后,会把结果传给它,我们在这里处理最终数据。

使用 Selenium(更推荐)

Selenium 封装了浏览器驱动的复杂性,提供了更高级、更易用的 API,对于爬虫来说,这通常是首选。

安装依赖

pip install selenium

示例代码:爬取动态加载的引用

我们爬取 https://quotes.toscrape.com/js/ 这个网站上的所有引用(quotes)。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# --- 配置 Chrome 浏览器 ---
chrome_options = Options()
# 如果你不想看到浏览器窗口,可以取消下面这行的注释
# chrome_options.add_argument("--headless") 
chrome_options.add_argument("--start-maximized") # 最大化窗口
# 指定 ChromeDriver 的路径
# 如果你已经将 chromedriver 放在了 PATH 环境变量中,可以省略 Service
# service = Service(executable_path='path/to/your/chromedriver')
# driver = webdriver.Chrome(service=service, options=chrome_options)
# 如果你没有 chromedriver 或者不想配置路径,Selenium 4+ 会自动帮你管理
driver = webdriver.Chrome(options=chrome_options)
try:
    # 1. 打开目标网页
    print("正在打开网页...")
    driver.get("https://quotes.toscrape.com/js/")
    # 2. 等待元素出现
    # 使用显式等待,比 time.sleep() 更可靠
    # 等待至少一个 class 为 'quote' 的 div 元素出现
    print("等待页面加载和渲染...")
    wait = WebDriverWait(driver, 10) # 最多等待10秒
    quotes = wait.until(
        EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.quote"))
    )
    print(f"页面加载完成,找到 {len(quotes)} 条引用。")
    # 3. 提取数据
    all_quotes_data = []
    for quote in quotes:
        text = quote.find_element(By.CSS_SELECTOR, "span.text").text
        author = quote.find_element(By.CSS_SELECTOR, "small.author").text
        tags = [tag.text for tag in quote.find_elements(By.CSS_SELECTOR, "div.tags a.tag")]
        quote_data = {
            "text": text,
            "author": author,
            "tags": tags
        }
        all_quotes_data.append(quote_data)
        print(f"引用: {text[:30]}... by {author}")
    # 4. (可选)处理分页
    # 这个网站没有分页,但如果有,你可以在这里找到下一页按钮并点击
    # next_button = driver.find_element(By.CSS_SELECTOR, "li.next a")
    # if next_button:
    #     next_button.click()
    #     time.sleep(2) # 等待新页面加载
    #     # 然后重复步骤 2 和 3
finally:
    # 5. 关闭浏览器
    print("\n爬取完成,关闭浏览器。")
    driver.quit()
# 打印所有结果
# import json
# print("\n--- 所有引用数据 ---")
# print(json.dumps(all_quotes_data, indent=2))

代码解释:

  1. webdriver.Chrome(): 启动一个 Chrome 浏览器实例。
  2. driver.get(url): 导航到指定的 URL。
  3. WebDriverWaitEC (Expected Conditions): 这是 Selenium 的核心功能之一——显式等待,它会等待某个条件(比如元素出现、可点击)成立后再继续执行,而不是像 time.sleep() 那样盲目等待,这使得脚本更稳定、更高效。
  4. driver.find_element(...)find_elements(...): 通过 CSS 选择器、XPath 等方式定位页面上的元素。find_element 返回单个元素,find_elements 返回一个元素列表。
  5. 数据提取: 一旦定位到元素,就可以像操作普通 Python 对象一样获取其文本(.text)、属性(.get_attribute('href'))等。
  6. driver.quit(): 非常重要! 关闭浏览器并释放所有资源,一定要放在 finally 块中,确保即使脚本出错,浏览器也会被关闭。

总结与对比

特性 PyQt5 + QtWebEngine Selenium
易用性 较低,需要理解 Qt 信号/槽机制和 JS 交互 非常高,API 直观,封装了底层细节
功能 功能强大,适合深度定制浏览器行为 功能极其强大,支持所有主流浏览器,有丰富的元素定位和等待策略
学习曲线 陡峭,需要学习 Qt 框架 平缓,文档丰富,社区庞大
适用场景 需要将爬虫功能嵌入到桌面 GUI 应用中。
需要精确控制浏览器进程和窗口。
学习 Qt Web 引擎。
绝大多数爬虫场景,尤其是爬取动态内容。
Web 自动化测试。
快速原型开发。
推荐度 ⭐⭐ ⭐⭐⭐⭐⭐

最终建议:

如果你要编写一个纯粹的爬虫,请毫不犹豫地选择 Selenium,它能让你用最少的代码完成最多的工作,并且是行业内的标准解决方案。

只有当你正在开发一个桌面应用程序,并且需要在应用程序内嵌一个带有爬虫功能的浏览器窗口时,才考虑使用 PyQt5/PySide2 + QtWebEngine 的原生方法。

分享:
扫描分享到社交APP
上一篇
下一篇