不用写爬虫,不用处理验证码,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 或任何工具分析。
优化方向
这个脚本已经能用了,后续想加功能随时改:
- 处理验证码:如果遇到验证码,可以用 OCR 识别(Tesseract),或者接入打码平台,或者手动干预时暂停脚本等人工输入
- 多页面串联:有些系统需要好几步操作才能拿到最终数据,用
await page.click()和await page.fill()串行执行就行 - 并发执行:同时操作多个账号或多个时间范围,用 asyncio.gather() 并行跑
- 告警通知:操作失败时自动发微信/钉钉告警,用 requests 调 webhook
- 数据可视化:把导出的 CSV 用 pandas + matplotlib 生成图表,自动发邮件报告
- 无头模式切换:开发调试时把
headless=True改成False,直接在屏幕上看到浏览器操作过程
Playwright 最厉害的地方是不用写选择器。开发调试时打开 headless=False,用浏览器开发者工具直接复制 CSS 选择器,或者用 Playwright Codegen 工具自动生成脚本:
playwright codegen https://example-company.com/login
它会录制你的操作并生成对应的 Python 代码,直接复制过来改改就能用。
写一个自动化脚本,把每天重复的操作变成一键运行。省下来的时间,够你多喝几杯咖啡。
这篇文章对你有帮助吗?