🚀

用 Python + Playwright 做网页自动化:自动登录、填表、抓数据,一次搞定

不用写爬虫,不用处理验证码,Playwright 能模拟真人操作浏览器。教你用 Python 写一个自动登录后台并抓取数据的脚本,10 分钟上手。

👁️ - 次阅读

你有没有这种场景:每天要登录某个后台系统,填一份表格,导出一份数据。重复操作做几十遍,手指都累了。

手动点太慢,写爬虫又搞不定需要登录的页面。

Playwright 是微软开源的浏览器自动化工具,能模拟真人操作浏览器——点击、填表、截图、抓取数据,全都能做。比 Selenium 更快,比 Puppeteer 更稳定,而且支持所有主流浏览器。

今天教你用 Python + Playwright 写一个自动登录并抓取数据的脚本,全程可运行,你改改 URL 和选择器就能用在自己的工作流里。

项目背景

假设你的工作流是这样的:

  • 每天早上登录公司内部的数据后台
  • 填写查询条件(日期范围、部门筛选)
  • 点击查询按钮
  • 导出结果数据为 CSV
  • 保存到本地并按日期命名

手动操作大概 10 分钟,一天一次。用 Playwright 自动化后,一杯咖啡的时间就能跑完。

这个思路可以套用到任何需要重复操作网页的场景:自动填表、批量上传、定时截图、监控页面变化等。

技术选型

组件选型理由
语言Python 3.10+脚本友好,生态完整
浏览器自动化Playwright微软出品,速度快,支持所有主流浏览器
数据保存CSV + JSON简单通用,方便后续处理
配置管理.env 文件安全存储账号密码,不硬编码

不需要数据库,不需要前端框架。一个脚本搞定所有操作。

实现步骤

第一步:安装 Playwright

pip install playwright
playwright install chromium

第一次安装会自动下载 Chromium 浏览器,大概 150MB,等它下完就行。之后每次运行都不需要再装。

如果你只想用 Chromium(不用 Firefox/WebKit),只装这一个就够了。

第二步:创建项目结构

mkdir -p playwright-demo
cd playwright-demo
touch .env config.py main.py

.env 文件放账号密码,config.py 放配置参数,main.py 是主脚本。

第三步:写配置和账号管理

# config.py
import os
from dotenv import load_dotenv

load_dotenv()

# ============ 目标网站配置 ============
LOGIN_URL = "https://example-company.com/login"
DASHBOARD_URL = "https://example-company.com/dashboard"

# 页面元素选择器(根据实际网站修改)
SELECTORS = {
    "username_input": "#username",
    "password_input": "#password",
    "login_btn": "#login-button",
    "date_from": "#date-from",
    "date_to": "#date-to",
    "search_btn": ".search-button",
    "export_btn": ".export-btn",
}

# 导出文件保存路径
EXPORT_DIR = "./exports"
# =====================================

def get_credentials():
    return {
        "username": os.getenv("USERNAME", ""),
        "password": os.getenv("PASSWORD", ""),
    }

.env 文件这样写:

USERNAME=your_username
PASSWORD=your_password

注意:把 .env 加入 .gitignore,别让密码提交到代码仓库。

第四步:写主脚本

# main.py
import asyncio
import os
import csv
import json
from datetime import datetime
from playwright.async_api import async_playwright
from config import (
    LOGIN_URL, DASHBOARD_URL, SELECTORS, EXPORT_DIR, get_credentials
)

async def auto_login_and_export():
    """自动登录并导出数据"""
    creds = get_credentials()
    if not creds["username"] or not creds["password"]:
        print("❌ 请先在 .env 文件中配置 USERNAME 和 PASSWORD")
        return

    os.makedirs(EXPORT_DIR, exist_ok=True)
    today = datetime.now().strftime("%Y%m%d")

    async with async_playwright() as p:
        # 启动浏览器(headless=False 可以看操作过程,False 则后台运行)
        browser = await p.chromium.launch(headless=True)
        context = await browser.new_context(
            viewport={"width": 1280, "height": 800},
            user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                       "AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36"
        )
        page = await context.new_page()

        try:
            # 1. 打开登录页
            print(f"🌐 正在打开登录页: {LOGIN_URL}")
            await page.goto(LOGIN_URL, wait_until="networkidle")

            # 2. 填写账号密码
            print("📝 正在填写登录信息...")
            await page.fill(SELECTORS["username_input"], creds["username"])
            await page.fill(SELECTORS["password_input"], creds["password"])

            # 3. 点击登录按钮
            print("🔑 正在点击登录...")
            await page.click(SELECTORS["login_btn"])

            # 4. 等待跳转到后台页面
            await page.wait_for_url(DASHBOARD_URL, timeout=30000)
            print("✅ 登录成功,已进入后台")

            # 5. 设置查询条件(日期范围)
            print("📅 正在设置查询条件...")
            today_str = datetime.now().strftime("%Y-%m-%d")
            last_week = (datetime.now() - __import__('datetime').timedelta(days=7)).strftime("%Y-%m-%d")
            await page.fill(SELECTORS["date_from"], last_week)
            await page.fill(SELECTORS["date_to"], today_str)

            # 6. 点击查询
            print("🔍 正在执行查询...")
            await page.click(SELECTORS["search_btn"])
            await page.wait_for_load_state("networkidle")

            # 7. 等待数据加载完成
            print("⏳ 等待数据加载...")
            await page.wait_for_timeout(3000)  # 简单等待,也可以用更精确的选择器

            # 8. 截图记录当前状态
            screenshot_path = f"{EXPORT_DIR}/screenshot_{today}.png"
            await page.screenshot(path=screenshot_path)
            print(f"📸 截图已保存: {screenshot_path}")

            # 9. 点击导出按钮
            print("📥 正在导出数据...")
            await page.click(SELECTORS["export_btn"])
            await page.wait_for_timeout(5000)

            # 10. 下载文件(Playwright 自动处理下载)
            download = await page.expect_download(timeout=30000)
            filename = f"export_{today}.csv"
            filepath = f"{EXPORT_DIR}/{filename}"
            await download.save_as(filepath)
            print(f"✅ 数据已保存到: {filepath}")

            # 11. 获取页面数据(可选:直接抓取表格数据)
            rows = await page.query_selector_all("table tbody tr")
            if rows:
                data = []
                for row in rows:
                    cells = await row.query_selector_all("td")
                    if cells:
                        data.append([await cell.inner_text() for cell in cells])
                if data:
                    json_path = f"{EXPORT_DIR}/data_{today}.json"
                    with open(json_path, "w", encoding="utf-8") as f:
                        json.dump(data, f, ensure_ascii=False, indent=2)
                    print(f"📊 表格数据已保存到: {json_path}")

        except Exception as e:
            print(f"❌ 操作失败: {e}")
            # 出错时截图,方便排查
            error_screenshot = f"{EXPORT_DIR}/error_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
            await page.screenshot(path=error_screenshot)
            print(f"📸 错误截图已保存: {error_screenshot}")
            raise
        finally:
            await browser.close()
            print("🏁 浏览器已关闭")

if __name__ == "__main__":
    asyncio.run(auto_login_and_export())

核心流程就 6 步:打开页面 → 填表登录 → 设置条件 → 点击查询 → 导出数据 → 关闭浏览器。

几个关键点:

  • wait_for_url() 是登录成功的关键,它等待页面跳转到后台地址,比硬等时间更可靠
  • expect_download() 专门用来处理文件下载,Playwright 会自动把文件存到本地
  • query_selector_all() 可以直接抓取页面表格数据,比导出文件更快
  • 错误时自动截图,方便排查哪里出了问题

第五步:添加定时任务

写个简单的 wrapper 脚本方便 cron 调用:

# run_daily.py
import subprocess
import sys

result = subprocess.run(
    [sys.executable, "main.py"],
    capture_output=True, text=True
)
print(result.stdout)
if result.returncode != 0:
    print(result.stderr)
    sys.exit(result.returncode)

然后用 crontab 设置每天定时执行:

crontab -e

添加:

# 每天早上 8 点自动登录导出数据
0 8 * * * cd ~/playwright-demo && /usr/bin/python3 run_daily.py >> ~/playwright-demo/cron.log 2>&1

不想用 cron 的话,也可以用 APScheduler 在 Python 内部调度:

from apscheduler.schedulers.asyncio import AsyncIOScheduler

scheduler = AsyncIOScheduler()
scheduler.add_job(auto_login_and_export, 'cron', hour=8, minute=0)
scheduler.start()
asyncio.run(asyncio.sleep(86400 * 365))  # 跑一年

运行效果

跑起来之后,你会看到终端输出:

🌐 正在打开登录页: https://example-company.com/login
📝 正在填写登录信息...
🔑 正在点击登录...
✅ 登录成功,已进入后台
📅 正在设置查询条件...
🔍 正在执行查询...
⏳ 等待数据加载...
📸 截图已保存: ./exports/screenshot_20260814.png
📥 正在导出数据...
✅ 数据已保存到: ./exports/export_20260814.csv
📊 表格数据已保存到: ./exports/data_20260814.json
🏁 浏览器已关闭

exports/ 目录下会有三样东西:截图、CSV 导出文件、JSON 数据文件。直接打开 CSV 就能用 Excel 或任何工具分析。

优化方向

这个脚本已经能用了,后续想加功能随时改:

  1. 处理验证码:如果遇到验证码,可以用 OCR 识别(Tesseract),或者接入打码平台,或者手动干预时暂停脚本等人工输入
  2. 多页面串联:有些系统需要好几步操作才能拿到最终数据,用 await page.click() 和 await page.fill() 串行执行就行
  3. 并发执行:同时操作多个账号或多个时间范围,用 asyncio.gather() 并行跑
  4. 告警通知:操作失败时自动发微信/钉钉告警,用 requests 调 webhook
  5. 数据可视化:把导出的 CSV 用 pandas + matplotlib 生成图表,自动发邮件报告
  6. 无头模式切换:开发调试时把 headless=True 改成 False,直接在屏幕上看到浏览器操作过程

Playwright 最厉害的地方是不用写选择器。开发调试时打开 headless=False,用浏览器开发者工具直接复制 CSS 选择器,或者用 Playwright Codegen 工具自动生成脚本:

playwright codegen https://example-company.com/login

它会录制你的操作并生成对应的 Python 代码,直接复制过来改改就能用。

写一个自动化脚本,把每天重复的操作变成一键运行。省下来的时间,够你多喝几杯咖啡。

这篇文章对你有帮助吗?