🎯 一款可定制、具备反检测功能的云浏览器,由自主研发的 Chromium驱动,专为网页爬虫AI 代理设计。👉立即试用
返回博客

机械汤:在Python中自动化表单驱动的抓取

Alex Johnson
Alex Johnson

Senior Web Scraping Engineer

29-Jun-2026

TL;DR:

  • MechanicalSoup通过将requests与BeautifulSoup配对,自动化表单驱动的网站。 一个StatefulBrowser对象打开一个页面,选择一个表单,填写字段,提交并解析响应——无需浏览器进程和JavaScript引擎。
  • 浏览器会在请求之间为您保持cookie和会话状态。 登录或Set-Cookie后,同一个StatefulBrowser会在每个后续请求中发送存储的cookie,从而使多步骤流程表现得像一个真实会话。
  • select_form加上字典式字段赋值是整个API表面。 通过CSS选择器定位表单,设置browser["fieldname"] = value,然后调用submit_selected() —— 库会处理编码和重定向。
  • MechanicalSoup仅读取服务器返回的HTML——它不执行JavaScript。 一些在客户端构建其内容的页面返回为空,因为在HTTP响应和BeautifulSoup之间没有DOM渲染步骤。
  • 当页面需要渲染或遭遇机器人挑战时,将获取请求交给Scrapeless Scraping Browser,并继续使用BeautifulSoup进行解析。 Scrapeless SDK创建一个云会话,Playwright通过CDP驱动它执行JavaScript,渲染的HTML会直接流回相同的soup.select(...)选择器中。
  • 免费开始。 新的Scrapeless帐户包括免费的Scraping Browser运行时——在app.scrapeless.com注册。

引言:表单仍然是大多数抓取工作隐藏的地方

大量有用数据隐藏在表单后面——搜索框、登录、过滤面板、多页向导。MechanicalSoup正是为了这种类型的网站而存在。它将requests HTTP库和BeautifulSoup封装成一个单一的状态浏览器对象:它获取一个页面,让您在其上填写和提交HTML表单,跟随重定向,并解析返回的内容。没有Selenium,没有Chromium,没有驱动程序二进制文件。

简约使其保持快速,同时它也对库可访问的范围划定了明确的界限。MechanicalSoup讲述HTTP语义并解析HTML。它从不运行页面的JavaScript,因此任何在客户端渲染的内容——无限滚动的动态内容、React结果列表、通过XHR获取结果的搜索框——都将以服务器首次发送的空壳返回。它在服务器渲染的表单上保持快速,而在客户端渲染的表单上则变得无能为力。

本指南将逐步介绍一个真实的MechanicalSoup工作流程——安装、打开页面、填写和提交表单、在会话中保持cookie,并抓取结果——然后展示诚实的限制。当目标在浏览器中渲染或面临活跃的反机器人挑战时,获取请求将转移到Scrapeless Scraping Browser通过Chrome DevTools协议进行,而您的BeautifulSoup解析代码保持不变。


您可以用它做什么

  • 提交登录表单并保持身份验证。 填写用户名和密码字段,提交,StatefulBrowser会为之后每个页面保留会话cookies
  • 驱动搜索和过滤表单。 设置查询字段,提交,并解析服务器返回的结果行——经典的搜索和抓取循环。
  • 处理多页流程。 在一个浏览器对象中跟随链接并提交连续的表单,cookie罐和引荐来源自动携带。
  • 读取服务器渲染的表格和列表。 所有在原始HTML中存在的内容——定价表、列表、目录页面——相距一个soup.select()的距离。
  • 脚本化重复提交。 使用不同的字段值重新运行相同的表单,清理一系列查询而无需触碰真实浏览器。

为什么选择Scrapeless Scraping Browser

Scrapeless Scraping Browser是一款可定制的,反检测的云浏览器,专为网络爬虫和人工智能代理设计。对于MechanicalSoup无法独自到达的页面,它提供:

  • 云端JavaScript渲染 —— 页面脚本在远程浏览器上运行,因此客户端构建的内容在您解析时已经存在于HTML中。
  • 覆盖195多个国家的住宅代理 —— 通过proxy_country固定出口,以便地理限制的页面和区域锁定的表单向当地访客提供内容。
  • 反检测指纹识别 —— 会话表现得像一个真实的浏览器,因此表单或结果页面渲染,而不是返回一个挑战的中介页面。
  • 会话持久性 —— cookies和身份验证状态在一个会话内的导航中保持不变,这正是MechanicalSoup在本地提供给您的属性。
  • 标准 CDP 端点browser_ws_endpoint 是一个普通的 WebSocket URL,因此 Playwright(或任何 CDP 客户端)只需一次调用即可连接,您的解析代码保持不变。

在免费计划中获取您的 API 密钥,网址为 app.scrapeless.com


前提条件

  • Python 3.10 或更高版本
  • 一个 Scrapeless 账户和 API 密钥 — 在 app.scrapeless.com 注册(仅在使用云浏览器部分时需要)
  • 对 CSS 选择器和终端的基本熟悉

安装

MechanicalSoup 是一个单一的包,它将 requestsbeautifulsoup4 作为依赖项拉取:

bash Copy
pip install mechanicalsoup

确认安装和版本:

bash Copy
python -c "import mechanicalsoup; print(mechanicalsoup.__version__)"
# 1.4.0

配置:使用 StatefulBrowser 打开页面

MechanicalSoup 中的一切都通过 StatefulBrowser 运行。它保存当前页面、会话和 cookie 杂烩。在构造时设置用户代理,以便请求携带合理的身份:

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser(
    user_agent="Mozilla/5.0 (compatible; data-collector)"
)

browser.open("https://httpbingo.org/forms/post")
# browser.page 现在是一个您可以直接查询的 BeautifulSoup 对象

browser.open() 返回 requests 响应;browser.page 是您刚加载的页面的解析 BeautifulSoup 树。


基本实现:填写并提交表单

核心循环是三个调用 — 选择表单、分配字段、提交。select_form 接受一个 CSS 选择器;字段分配采用字典风格在浏览器上;submit_selected() 提交表单并跟随重定向。

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser(
    user_agent="Mozilla/5.0 (compatible; data-collector)"
)
browser.open("https://httpbingo.org/forms/post")

# 通过其 action 定位表单,然后按名称填写字段
browser.select_form('form[action="/post"]')
browser["custname"] = "Ada Lovelace"
browser["custtel"] = "555-0100"
browser["custemail"] = "ada@example.com"
browser["size"] = "medium"             # 单选按钮
browser["topping"] = ["bacon", "cheese"]  # 多值复选框
browser["comments"] = "Leave at door"

response = browser.submit_selected()
print(response.status_code)
data = response.json()
print(data["url"])
print(data["form"])

httpbin 端点回显解析后的表单主体,这确认了 MechanicalSoup 发送的确切内容:

json Copy
{
  "url": "https://httpbingo.org/post",
  "form": {
    "comments": "Leave at door",
    "custemail": "ada@example.com",
    "custname": "Ada Lovelace",
    "custtel": "555-0100",
    "delivery": "",
    "size": "medium",
    "topping": ["bacon", "cheese"]
  }
}
// 值反映真实提交;空的 "delivery" 是表单中的未设置字段。

单选按钮接受单个字符串,复选框组接受列表,任何未设置的字段将发送为空 — 这与浏览器产生的编码相同。


高级模式

跨会话携带 cookies

StatefulBrowser 重用一个 requests.Session,因此服务器设置的任何 cookie 会在后续请求中自动保留。这使登录和多步骤流程得以顺利进行:

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser()

# 服务器在此请求上设置一个 cookie
browser.open("https://httpbingo.org/cookies/set?session_id=abc123")
print(browser.session.cookies.get_dict())
# {'session_id': 'abc123'}

# 在同一浏览器上后续请求会发送存储的 cookie
echo = browser.open("https://httpbingo.org/cookies")
print(echo.json())
# {'cookies': {'session_id': 'abc123'}}

对于真实登录,首先提交登录表单,然后继续使用相同的 browser 对象 — 身份验证 cookie 会随每个后续页面一起传递。

提交搜索表单并抓取结果

GET 搜索表单采用相同模式:设置查询字段,提交,从 browser.page 解析结果行。

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser(
    user_agent="Mozilla/5.0 (compatible; data-collector)"
)
browser.open("https://www.scrapethissite.com/pages/forms/")

browser.select_form('form[action="/pages/forms/"]')
browser["q"] = "boston"
browser.submit_selected()
print(browser.url)  # https://www.scrapethissite.com/pages/forms/?q=boston

rows = browser.page.select("table.table tr.team")
print(f"{len(rows)} rows")
for row in rows[:3]:
    name = row.select_one(".name").get_text(strip=True)
    year = row.select_one(".year").get_text(strip=True)
    wins = row.select_one(".wins").get_text(strip=True)
    print(name, year, "wins:", wins)

由于结果页面是服务器渲染的,行信息已经在 HTML 中,MechanicalSoup 已经持有 — 不需要第二次获取。
获取您的免费计划 API 密钥:app.scrapeless.com


MechanicalSoup 的局限性:在浏览器中渲染的页面

MechanicalSoup 只是将服务器通过 HTTP 返回的内容传递给 BeautifulSoup — 没有更多。当页面使用客户端 JavaScript 构建其内容时,该原始 HTML 只是一个空壳,选择器找不到任何内容:

python Copy
import mechanicalsoup

browser = mechanicalsoup.StatefulBrowser()
browser.open("https://quotes.toscrape.com/js/")
quotes = browser.page.select(".quote .text")
print("MechanicalSoup 找到的引用数量:", len(quotes))
# MechanicalSoup 找到的引用数量: 0

为零。该页面的 /js/ 变体在加载后通过 JavaScript 注入其引用,因此在服务器的 HTML 中没有任何内容供 BeautifulSoup 匹配。对于需要通过反机器人挑战或仅对居民 IP 提供内容的页面,同样的壁垒会出现 — HTTP-only 客户端无法突破这些限制。

修复保持您已经编写的所有内容。让 Scrapeless Scraping Browser 负责渲染:SDK 创建一个云会话,Playwright 通过 CDP 附加到它并运行页面的 JavaScript,然后您将渲染后的 HTML 直接传递到相同的 BeautifulSoup 选择器中。

安装 SDK 和 Playwright 客户端,然后获取 Playwright 驱动的浏览器二进制文件:

bash Copy
pip install scrapeless playwright beautifulsoup4
python -m playwright install chromium

在环境中设置您的密钥 — 永远不要硬编码:

bash Copy
export SCRAPELESS_API_KEY="your_api_token_here"

现在在云端渲染页面并在本地解析结果:

python Copy
import os
from scrapeless import Scrapeless
from scrapeless.types import ICreateBrowser
from playwright.sync_api import sync_playwright
from bs4 import BeautifulSoup

client = Scrapeless()  # 从环境中读取 SCRAPELESS_API_KEY

# 创建云会话;为地理绑定页面锁定美国居民出口
session = client.browser.create(ICreateBrowser(
    session_name="mechanicalsoup-guide",
    session_ttl=180,
    proxy_country="US",
))

with sync_playwright() as p:
    # browser_ws_endpoint 是标准的 wss:// CDP URL
    browser = p.chromium.connect_over_cdp(session.browser_ws_endpoint)
    page = browser.contexts[0].pages[0]
    page.goto("https://quotes.toscrape.com/js/", wait_until="domcontentloaded")
    page.wait_for_selector(".quote .text")
    html = page.content()
    browser.close()

# 与使用 MechanicalSoup 时相同的 BeautifulSoup 解析
soup = BeautifulSoup(html, "html.parser")
quotes = soup.select(".quote .text")
print("Scrapeless + BeautifulSoup 找到的引用数量:", len(quotes))
print(quotes[0].get_text())
# Scrapeless + BeautifulSoup 找到的引用数量: 10
# “我们所创造的世界是我们思维的过程……”

返回 0 行的页面通过云浏览器返回 10 行,因为 JavaScript 实际上在读取 HTML 之前运行。渲染和出口移到云端;解析层 — soup.select(...) — 是相同的。对于库原生采取相同升级的方法,Scrapling 云浏览器指南 通过相同的 browser_ws_endpoint 路由自适应选择器获取器。


故障排除

症状 原因 修复
LinkNotFoundErrorselect_form CSS 选择器在页面上没有匹配的表单 打印 browser.page.select("form") 并定位真实的 action/属性
结果选择器返回空列表 页面使用 JavaScript 渲染其内容 使用 Scraping Browser 在云端渲染,然后解析返回的 HTML
提交忽略某字段 字段是需要字符串或列表的单选/复选框,而不是裸值 为单选框分配单个字符串,为复选框组分配列表
登录页面表现为未登录 每一步使用新的 StatefulBrowser(新的 cookie jar) 重用一个 browser 对象以便会话 cookie 保持
页面返回挑战而不是内容 活跃的反机器人或在 HTTP-only 客户端上的区域检查 锁定 proxy_country 并让云浏览器的指纹渲染真实页面

结论:保留解析器,替换获取方法

MechanicalSoup 是适用于大量仍然是普通 HTML 和表单的网站的正确工具:打开一个页面,select_form,分配字段,submit_selected(),并从 BeautifulSoup 中读取行。cookie 罐使登录和多步骤流程可以在没有额外代码的情况下工作。它唯一的硬边界是 JavaScript——它读取 HTML,而不对其进行渲染。当目标在浏览器中自行构建或在反机器人墙后进行限制时,最简洁的解决方案是仅更改抓取:创建一个 Scrapeless 会话,通过 CDP 渲染页面,并将结果 HTML 传递给相同的选择器。当页面需要一个完整的无头浏览器并具有自己的代理出口时,Puppeteer 代理指南 介绍了相同的云侧模式,而 Scraping Browser 文档 则记录了完整的 CDP 接口。为地理绑定页面固定美国出口,在步骤之间重用一个会话,并将缺少的字段视为可为空。


准备好构建你的 AI 驱动的数据管道了吗?

加入我们的社区以领取免费计划,并与构建表单自动化和渲染管道的开发者联系:Discord · Telegram

app.scrapeless.com 注册以获取免费的 Scraping Browser 运行时,并将上述模式应用于您的工作流程所需的表单、登录和渲染页面。请查看 定价 以获取规模信息。


常见问题

问:MechanicalSoup 能运行 JavaScript 吗?
不能。MechanicalSoup 封装了 requests 和 BeautifulSoup,因此它只能看到服务器返回的 HTML。当内容在客户端构建时,页面会返回空;通过云浏览器进行渲染,并使用相同的 BeautifulSoup 选择器解析结果 HTML。

问:MechanicalSoup 如何处理登录和会话?
单个 StatefulBrowser 重用了一个 requests.Session,因此服务器设置的任何 cookie 都会自动保留到后续的每个请求中。登录表单提交一次,然后继续使用同一个浏览器对象,授权 cookie 也随之保持。

问:我如何选择页面上的特定表单?
将 CSS 选择器传递给 select_form,例如 browser.select_form('form[action="/post"]')。如果没有表单匹配,您将收到 LinkNotFoundError——打印 browser.page.select("form") 以查看实际属性并以其中一个为目标。

问:使用 MechanicalSoup 抓取网站是否合法?
抓取公开可见的数据通常是允许的,但规则因管辖区和网站服务条款而异。请查看目标的服务条款,尊重机器人指令,避免个人或受限数据,并咨询律师处理任何模糊情况。

问:使用 MechanicalSoup 需要代理吗?
对于开放的服务器渲染页面,通常不需要。对于因地域限制或仅向住宅 IP 提供内容的页面,通过 Scrapeless Scraping Browser 进行抓取,并固定 proxy_country,以便请求从网站信任的 IP 进行出口。

问:当我迁移到云浏览器时,我可以保留我的 BeautifulSoup 代码吗?
可以。云浏览器仅替换抓取步骤——它返回渲染后的 HTML,您可以使用与 MechanicalSoup 相同的 soup.select(...) 调用来解析。解析层不会改变。

在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。

最受欢迎的文章

目录