Pydoll: Automate the Web, Naturally
📖 Documentation • 🚀 Getting Started • ⚡ Advanced Features • 🤝 Contributing • 💖 Support My Work
想象一下以下场景:您需要在浏览器中自动执行任务。也许它是测试 Web 应用程序、从站点收集数据,甚至自动化重复过程。通常,这涉及使用外部驱动程序、复杂的配置和许多兼容性问题。
Pydoll 就是为了解决这些问题而诞生的。
Pydoll 采用不同的理念从头开始构建,直接连接到 Chrome DevTools 协议 (CDP),无需外部驱动程序。这种干净的实现以及单击、导航和与元素交互的逼真方式使其与真实用户几乎没有区别。
We believe that powerful automation shouldn’t require you to become an expert in configuration or constantly fight with bot protection systems. With Pydoll, you can focus 上what really matters: your automation logic, not the underlying complexity or protection systems.
做一个好人。给它一个星 ⭐
没有星星,没有修复错误。开个玩笑(也许)🌟 是什么让 Pydoll 与众不同?
- 零 Webdrivers:告别 webdriver 兼容性问题
- 类人交互引擎:能够传递行为验证码,如 reCAPTCHA v3 或 Turnstile,具体取决于 IP 信誉和交互模式
- 异步性能:用于高速自动化和多个同时任务
- 人性化互动:模**实用户行为
- 单纯:使用 Pydoll,您只需安装即可实现自动化。
最新消息
通过 WebSocket 进行远程连接 — 从任何地方控制任何 Chrome!
你要求它,我们交付了。您现在可以通过其 WebSocket 地址远程连接到已经运行的浏览器,并立即使用完整的 Pydoll API。
123456789 from pydoll.browser.chromium import Chrome chrome = Chrome() # Full power unlocked: navigation, element automation, requests, events…title = await tab.execute_script('return document.title')print(title)
这使得在远程/CI 浏览器、容器或共享调试目标上运行 Pydoll 变得毫不费力——无需本地启动。只需指向 WS 端点并自动执行。
像专业人士一样浏览 DOM:get_children_elements() 和 get_siblings_elements()
两个令人愉快的帮手,可以有目的地穿越复杂的布局:
123456789101112 # Grab direct children of a containercontainer = await tab.find(id='cards')cards = await container.get_children_elements(max_depth=1) # Want to go deeper? This will return children of children (and so on)elements = await container.get_children_elements(max_depth=2) # Walk horizontal lists without re-querying the DOMactive = await tab.find(class_name='item-active')siblings = await active.get_siblings_elements() print(len(cards), len(siblings))
使用它们来切割样板、表达意图并保持抓取/自动化逻辑干净易读——尤其是在***格、列表和菜单中。
WebElement:状态等待和新的公共 API
- 新
wait_until(...)onWebElement要用最少的代码等待元素状态:
12345 # Wait until it becomes visible OR the timeout expiresawait element.wait_until(is_visible=True, timeout=5) # Wait until it becomes interactable (visible, on top, receiving pointer events)await element.wait_until(is_interactable=True, timeout=10)
- 方法现已公开
WebElement:is_visible()- Checks that the element has a visible area (> 0), isn’t hidden by CSS and is in the viewport (after
scroll_into_view()需要时)。交互前有用的预检查。
- Checks that the element has a visible area (> 0), isn’t hidden by CSS and is in the viewport (after
is_interactable()- “点击就绪”状态:结合可见性、启用度和指针事件命中测试。非常适合避免丢失点击的稳健流程。
is_on_top()- 验证元素是否是预期点击点的顶部命中测试目标,避免叠加。
execute_script(script: str, return_by_value: bool = False)- 在元素自己的上下文中执行 JavaScript(其中
this是元素)。非常适合微调和快速检查。
- 在元素自己的上下文中执行 JavaScript(其中
1234567 # Visually outline the element via JSawait element.execute_script("this.style.outline='2px solid #22d3ee'") # Confirm statesvisible = await element.is_visible()interactable = await element.is_interactable()on_top = await element.is_on_top()
这些新增功能简化了单击/键入之前的等待和状态验证,减少了不稳定并使自动化更具可预测性。
📦 安装
1 pip install pydoll-python
就是这样!只需安装并开始自动化。
🚀 开始
您的第一个自动化
让我们从一个真实的例子开始:执行 Google 搜索并点击第一个结果的自动化。通过此示例,我们可以看到库的工作原理以及如何开始自动化任务。
1234567891011121314151617181920 import asyncio from pydoll.browser import Chromefrom pydoll.constants import Key async def google_search(query: str): async with Chrome() as browser: tab = await browser.start() search_box = await tab.find(tag_name='textarea', name='q') await search_box.insert_text(query) await search_box.press_keyboard_key(Key.ENTER) await (await tab.find( tag_name='h3', text='autoscrape-labs/pydoll', timeout=10, )).click() await tab.find(id='repository-container-header', timeout=10) asyncio.run(google_search('pydoll python'))
无需配置,只需一个简单的脚本,我们就可以进行完整的谷歌搜索!
好的,现在让我们看看如何使用相同的上一个示例从页面中提取数据。
让我们在下面的代码中考虑一下我们已经在 Pydoll 页面上。我们想要提取以下信息:
- 项目描述
- 星数
- 叉子数量
- 问题数
- 拉取请求数
让我们开始吧!为了获取项目描述,我们将使用 xpath 查询。您可以查看有关如何构建自己的查询的文档。
1234 description = await (await tab.query( '//h2[contains(text(), "About")]/following-sibling::p', timeout=10,)).text
就是这样!让我们了解一下这个查询的作用:
//h2[contains(text(), "About")]- 选择第一个包含“关于”/following-sibling::p- Selects the first在
现在让我们获取其余数据:
12345678910111213141516171819202122 number_of_stars = await (await tab.find( id='repo-stars-counter-star')).text number_of_forks = await (await tab.find( id='repo-network-counter')).textnumber_of_issues = await (await tab.find( id='issues-repo-tab-count',)).textnumber_of_pull_requests = await (await tab.find( id='pull-requests-repo-tab-count',)).text data = { 'description': description, 'number_of_stars': number_of_stars, 'number_of_forks': number_of_forks, 'number_of_issues': number_of_issues, 'number_of_pull_requests': number_of_pull_requests,}print(data)
我们设法提取了所有必要的数据!
自定义配置
有时我们需要对浏览器进行更多控制。Pydoll 提供了一种灵活的方法来做到这一点。让我们看看下面的例子:
123456789101112131415161718 from pydoll.browser import Chromefrom pydoll.browser.options import ChromiumOptions as Options async def custom_automation(): # Configure browser options options = Options() options.add_argument('--proxy-server=username:password@ip:port') options.add_argument('--window-size=1920,1080') options.binary_location = '/path/to/your/browser' options.start_timeout = 20 async with Chrome(options=options) as browser: tab = await browser.start() # Your automation code here # The browser is now using your custom settings asyncio.run(custom_automation())
在此示例中,我们将浏览器配置为使用代理和 1920x1080 窗口,以及 Chrome 二进制文件的自定义路径,以防您的安装位置与常见默认值不同。
⚡ 高级功能
Pydoll 提供一系列高级功能,即使是最能满足
要求苛刻的用户。
高级元素搜索
我们有多种方法可以在页面上查找元素。无论您喜欢如何,我们都有一种对您有意义的方法:
12345678910111213141516171819202122232425262728293031323334 import asynciofrom pydoll.browser import Chrome async def element_finding_examples(): async with Chrome() as browser: tab = await browser.start() # Find by attributes (most intuitive) submit_btn = await tab.find( tag_name='button', class_name='btn-primary', text='Submit' ) # Find by ID username_field = await tab.find(id='username') # Find multiple elements all_links = await tab.find(tag_name='a', find_all=True) # CSS selectors and XPath nav_menu = await tab.query('nav.main-menu') specific_item = await tab.query('//div[@data-testid="item-123"]') # With timeout and error handling delayed_element = await tab.find( class_name='dynamic-content', timeout=10, raise_exc=False # Returns None if not found ) # Advanced: Custom attributes custom_element = await tab.find( data_testid='submit-button', aria_label='Submit form' ) asyncio.run(element_finding_examples())
这 find 方法更人性化。我们可以按常见属性(如 id、tag_name、class_name 等)进行搜索,直至自定义属性(例如data-testid).
如果这还不够,我们可以使用 query 使用 CSS 选择器、XPath 查询等搜索元素的方法。Pydoll 会自动识别我们正在使用的查询类型。
浏览器上下文 HTTP 请求 - 混合自动化的游戏规则改变者!
您是否曾经希望发出自动继承浏览器所有会话状态的 HTTP 请求? 现在你可以了!
The tab.request 物业给你一个美丽的requests-like 接口,直接在浏览器的 JavaScript 上下文中执行 HTTP 调用。这意味着每个请求都会自动获取 cookie、身份验证标头、CORS 策略和会话状态,就像浏览器自己发出请求一样。
混合自动化的完美选择:
1234567891011121314151617181920212223242526272829303132 # Navigate to a site and login normally with PyDollawait (await tab.find(id='username')).type_text('user@example.com')await (await tab.find(id='password')).type_text('password')await (await tab.find(id='login-btn')).click() # Now make API calls that inherit the logged-in session!user_data = response.json() # POST data while staying authenticatedresponse = await tab.request.post( json={'theme': 'dark', 'notifications': True}) # Access response content in different formatsraw_data = response.contenttext_data = response.textjson_data = response.json() # Check cookies that were setfor cookie in response.cookies: print(f"Cookie: {cookie['name']} = {cookie['value']}") # Add custom headers to your requestsheaders = [ {'name': 'X-Custom-Header', 'value': 'my-value'}, {'name': 'X-API-Version', 'value': '2.0'}]
为什么这很棒:
- 不再需要杂耍会话 - 请求自动继承浏览器 cookie
- CORS 可以正常工作 - 请求遵守浏览器安全策略
- 非常适合现代水疗中心 - 将 UI 自动化与 API 调用无缝混合
- 身份验证变得简单 - 通过 UI 登录一次,然后锤击 API
- 混合工作流 - 为每个步骤使用最佳工具(UI 或 API)
这为需要浏览器交互和 API 效率的自动化场景开辟了令人难以置信的可能性!
新的 expect_download() 上下文管理器 — 强大的文件下载变得简单!
厌倦了与不稳定的下载流程、丢失的文件或活泼的事件***作斗争?遇 tab.expect_download(),一种令人愉快、可靠的文件下载处理方式。
- 自动设置浏览器的下载行为
- 适用于您自己的目录或临时文件夹(自动清理!
- 等待超时完成(这样您的测试就不会挂起)
- 为您提供一个方便的句柄来读取字节/base64 或检查
file_path
有效的小例子:
123456789101112131415161718 import asynciofrom pathlib import Pathfrom pydoll.browser import Chrome async def download_report(): async with Chrome() as browser: tab = await browser.start() target_dir = Path('/tmp/my-downloads') async with tab.expect_download(keep_file_at=target_dir, timeout=10) as download: # Trigger the download in the page (button/link/etc.) await (await tab.find(text='Download latest report')).click() # Wait until finished and read the content data = await download.read_bytes() print(f"Downloaded {len(data)} bytes to: {download.file_path}") asyncio.run(download_report())
想要零麻烦的清理吗?省略 keep_file_at 我们将创建一个临时文件夹,并在上下文退出后自动将其删除。非常适合测试。
具有自定义首选项的全面浏览器控制!(感谢 @LucasAlvws)
想要完全自定义 Chrome 的行为方式? 现在你可以控制一切了!
新的 browser_preferences 系统使您可以访问数百个以前无法通过编程方式更改的内部 Chrome 设置。我们谈论的是远远超出命令行标志的深度浏览器定制!
可能性是无限的:
1234567891011121314151617181920212223242526272829303132333435 options = ChromiumOptions() # Create the perfect automation environmentoptions.browser_preferences = { 'download': { 'default_directory': '/tmp/downloads', 'prompt_for_download': False, 'directory_upgrade': True, 'extensions_to_open': '' # Don't auto-open any downloads }, 'profile': { 'default_content_setting_values': { 'notifications': 2, # Block all notifications 'geolocation': 2, # Block location requests 'media_stream_camera': 2, # Block camera access 'media_stream_mic': 2, # Block microphone access 'popups': 1 # Allow popups (useful for automation) }, 'password_manager_enabled': False, # Disable password prompts 'exit_type': 'Normal' # Always exit cleanly }, 'intl': { 'accept_languages': 'en-US,en', 'charset_default': 'UTF-8' }, 'browser': { 'check_default_browser': False, # Don't ask about default browser 'show_update_promotion_infobar': False }} # Or use the convenient helper methodsoptions.set_default_download_directory('/tmp/downloads')options.set_accept_languages('en-US,en,pt-BR') options.prompt_for_download = False
真实世界的电源示例:
- 静默下载 - 没有提示,没有对话框,只有自动下载
- 阻止所有干扰 - 通知、弹出窗口、相机请求,凡是你能想到的
- 非常适合 CI/CD - 禁用更新检查、默认浏览器提示、崩溃报告
- 多区域测试 - 立即更改语言、时区和区域设置
- 安全强化 - 锁定权限并禁用不必要的功能
- 先进的指纹控制 - 修改浏览器安装日期、参与历史记录和行为模式
用于隐身自动化的指纹定制:
12345678910111213141516171819202122 import time # Simulate a browser that's been around for monthsfake_engagement_time = int(time.time()) - (7 * 24 * 60 * 60) # 7 days ago options.browser_preferences = { 'settings': { 'touchpad': { 'natural_scroll': True, } }, 'profile': { 'last_engagement_time': fake_engagement_time, 'exit_type': 'Normal', 'exited_cleanly': True }, 'session': { 'restore_on_startup': 1, # Restore last session }}
这种级别的控制以前仅适用于 Chrome 扩展程序开发人员 - 现在它在您的自动化工具包中!
检查一下 documentation 了解更多详情。
并发自动化
Pydoll 的一大优势是由于其异步实现,能够同时处理多个任务。我们可以自动化多个选项卡
同时!让我们看一个例子:
1234567891011121314151617181920212223242526 import asynciofrom pydoll.browser import Chrome async def scrape_page(url, tab): await tab.go_to(url) title = await tab.execute_script('return document.title') links = await tab.find(tag_name='a', find_all=True) return { 'url': url, 'title': title, 'link_count': len(links) } async def concurrent_scraping(): browser = Chrome() tab_google = await browser.start() tab_duckduckgo = await browser.new_tab() tasks = [ ] results = await asyncio.gather(*tasks) print(results) await browser.stop() asyncio.run(concurrent_scraping())
我们设法同时从两个页面中提取数据!
还有很多很多!用于反应式自动化、请求拦截和修改等的事件系统。看看文档,你不会
后悔吧!
🔧 快速故障排除
找不到浏览器?
123456 from pydoll.browser import Chromefrom pydoll.browser.options import ChromiumOptions options = ChromiumOptions()options.binary_location = '/path/to/your/chrome'browser = Chrome(options=options)
浏览器在 FailedToStartBrowser 错误后启动?
1234567 from pydoll.browser import Chromefrom pydoll.browser.options import ChromiumOptions options = ChromiumOptions()options.start_timeout = 20 # default is 10 seconds browser = Chrome(options=options)
需要代理吗?
1 options.add_argument('--proxy-server=your-proxy:port')
在 Docker 中运行?
12 options.add_argument('--no-sandbox')options.add_argument('--disable-dev-shm-usage')
📚 文档
如需完整的文档、详细示例和对所有 Pydoll 功能的深入研究,请访问我们的 official documentation.
文档包括:
- 入门指南 - 分步教程
- API 参考 - 完整的方法文档
- 先进技术 - 网络拦截、事件处理、性能优化
The chinese version of this README is here.
🤝 贡献
我们希望您的帮助让 Pydoll 变得更好!查看我们的 contribution guidelines 开始。无论是修复错误、添加功能还是改进文档 - 欢迎所有贡献!
请确保:
- 编写新功能或错误修复的测试
- 遵循代码样式和约定
- 对拉取请求使用常规提交
- 在提交之前运行 lint 检查和测试
💖 支持我的工作
如果您发现 Pydoll 有用,请考虑 supporting me on GitHub.
您将获得独家福利,例如优先支持、自定义功能等等!
现在不能赞助?没问题,你仍然可以通过以下方式提供很多帮助:
- 为存储库加星标
- 在社交媒体上分享
- 撰写帖子或教程
- 提供反馈或报告问题
每一点支持都会产生影响/
💬 传播信息
如果 Pydoll 节省了您的时间、心理健康或键盘免于被砸碎,请给它一个 ⭐ ,分享它,或者告诉你奇怪的开发朋友。
📄 许可证
Pydoll 在 MIT License.
Pydoll — 让浏览器自动化变得神奇!
免责声明 © 2025 - 虚宝阁
本站部分源码来源于网络,版权归属原开发者,用户仅获得使用权。依据《计算机软件保护条例》第十六条,禁止:
- 逆向工程破解技术保护措施
- 未经许可的分发行为
- 去除源码中的原始版权标识
※ 本站源码仅用于学习和研究,禁止用于商业用途。如有侵权, 请及时联系我们进行处理。