用 Python + Playwright 实现网页内容巡检:从单次脚本到定时任务

举报
yd_278449686 发表于 2026/10/22 22:56:28 2026/10/22
【摘要】 用 Playwright 编写网页内容巡检脚本:动态渲染等待、基线比对、差异报告、定时执行与邮件告警,附完整可复用代码。

一、为什么需要网页巡检

日常运维中,除了接口可用性,很多关键信息只出现在页面上:产品公告、价格表、帮助文档目录、控制台公告位。接口监控覆盖不到这些场景,人工每天刷新又容易遗漏。本文用 Python + Playwright 写一个可复用的网页内容巡检脚本:定时打开目标页面,提取指定区域的文本,与基线比对,有变化时输出差异并发送告警。

适用边界:仅巡检自有或已获得授权的页面,保持低频访问,遵守目标站点的 robots 协议与使用条款。

二、技术选型

  • requests + BeautifulSoup:轻量,但拿不到 JS 渲染后的内容。
  • Playwright:真实浏览器内核,能等待异步渲染,适合 SPA 和需要登录态的页面。

巡检场景通常页面结构复杂、内容异步加载,因此选择 Playwright。

三、环境准备

python -m pip install playwright
python -m playwright install chromium

如果目标页面需要登录,建议先手动登录一次并保存 storage_state,后续复用登录态,避免在脚本里硬编码账号密码。

四、核心脚本

下面脚本做四件事:打开页面、等待目标区域出现、提取文本、与基线比对。

import json
import pathlib
from datetime import datetime

from playwright.sync_api import sync_playwright

TARGET_URL = "https://example.com/notice"
SELECTOR = "main .notice-list"
BASELINE_FILE = pathlib.Path("baseline.json")


def fetch_text() -> str:
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=30_000)
        page.wait_for_selector(SELECTOR, timeout=15_000)
        text = page.locator(SELECTOR).inner_text()
        browser.close()
    return "\n".join(line.strip() for line in text.splitlines() if line.strip())


def main() -> None:
    current = fetch_text()
    if not BASELINE_FILE.exists():
        BASELINE_FILE.write_text(json.dumps({"text": current}, ensure_ascii=False, indent=2), encoding="utf-8")
        print("已写入基线")
        return

    baseline = json.loads(BASELINE_FILE.read_text(encoding="utf-8"))["text"]
    if current == baseline:
        print(f"[{datetime.now():%F %T}] 无变化")
        return

    print(f"[{datetime.now():%F %T}] 检测到变化")
    print("--- 旧内容 ---")
    print(baseline)
    print("--- 新内容 ---")
    print(current)


if __name__ == "__main__":
    main()

几个细节:

  1. wait_until="domcontentloaded" 只保证文档结构就绪,真正的内容要靠 wait_for_selector 等待。
  2. inner_text() 返回渲染后的可见文本,比 text_content() 更接近用户看到的内容。
  3. 基线单独存文件,首次运行只建基线,不告警。

五、生成可读的差异

内容较长时,直接打印两段文本很难定位变化。可以用 difflib 生成逐行差异:

import difflib

diff = difflib.unified_diff(
    baseline.splitlines(),
    current.splitlines(),
    fromfile="baseline",
    tofile="current",
    lineterm="",
)
for line in diff:
    print(line)

只输出 + / - 开头的行,就能快速定位新增和删除内容。

六、定时执行

  • Linux:用 cron,例如每 30 分钟执行一次:*/30 * * * * cd /opt/page-watch && /usr/bin/python3 watch.py >> run.log 2>&1
  • Windows:用任务计划程序创建基本任务,触发器设为每天并重复每 30 分钟,操作指向 python.exe 与脚本路径。

定时任务要固定工作目录,否则基线文件可能写到意料之外的位置。

七、变化告警

最直接的方式是邮件。把上面的差异拼进正文,用 smtplib 发送即可:

import smtplib
from email.mime.text import MIMEText

def send_mail(subject: str, body: str) -> None:
    msg = MIMEText(body, "plain", "utf-8")
    msg["Subject"] = subject
    msg["From"] = "watch@example.com"
    msg["To"] = "ops@example.com"
    with smtplib.SMTP_SSL("smtp.example.com", 465) as server:
        server.login("watch@example.com", "授权码")
        server.send_message(msg)

生产环境不建议把口令写在代码里,改用环境变量或密钥管理服务。

八、工程化建议

  • 把 URL、选择器和频率放进配置文件,一个脚本巡检多个页面。
  • 告警加静默窗口,避免页面局部抖动造成告警风暴。
  • 记录每次运行的时间和结果,便于回溯。
  • 对登录态设置有效期,过期后及时提醒人工更新。

九、总结

网页巡检的核心不是抓取,而是稳定地拿到目标内容并识别变化。Playwright 解决了渲染与等待问题,基线加 diff 解决了变化判断,定时任务与告警把它变成一套可持续运行的轻量监控。先跑通单页面,再逐步扩展到多页面和多站点,成本可控,收益直接。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。