Add archived/drissionpage-auto-login
This commit is contained in:
@@ -0,0 +1,164 @@
|
|||||||
|
---
|
||||||
|
name: drissionpage-auto-login
|
||||||
|
description: Automate login with DrissionPage — discover login pages, fill forms, solve CAPTCHAs with ddddocr, and verify success.
|
||||||
|
tags: [drissionpage, automation, login, captcha, ddddocr, web-scraping]
|
||||||
|
---
|
||||||
|
|
||||||
|
# DrissionPage Auto-Login with CAPTCHA Solving
|
||||||
|
|
||||||
|
Automate login to web applications using DrissionPage, with automatic CAPTCHA solving via `ddddocr`.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m venv /tmp/drission_env && source /tmp/drission_env/bin/activate
|
||||||
|
pip install DrissionPage ddddocr
|
||||||
|
```
|
||||||
|
|
||||||
|
## Browser Configuration
|
||||||
|
|
||||||
|
```python
|
||||||
|
from DrissionPage import ChromiumPage, ChromiumOptions
|
||||||
|
import ddddocr
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
co = ChromiumOptions()
|
||||||
|
co.set_browser_path('/home/ubuntu/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome')
|
||||||
|
co.set_argument('--no-sandbox')
|
||||||
|
co.set_argument('--disable-dev-shm-usage')
|
||||||
|
co.set_argument('--disable-gpu')
|
||||||
|
co.headless()
|
||||||
|
co.auto_port()
|
||||||
|
page = ChromiumPage(co)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Login Discovery Workflow
|
||||||
|
|
||||||
|
When the login URL is unknown:
|
||||||
|
|
||||||
|
1. **Visit the homepage** and scan for login links:
|
||||||
|
```python
|
||||||
|
page.get('https://www.example.com')
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
links = page.eles('tag:a')
|
||||||
|
for link in links:
|
||||||
|
href = link.attr('href') or ''
|
||||||
|
text = link.text.strip()
|
||||||
|
if 'login' in href.lower() or 'login' in text.lower() or '登录' in text:
|
||||||
|
print(f"Found: {text} -> {href}")
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Common login URL patterns** to try:
|
||||||
|
- `/login`, `/signin`, `/auth`
|
||||||
|
- `login.example.com`, `passport.example.com`, `account.example.com`
|
||||||
|
|
||||||
|
## Form Filling
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Find inputs by name, placeholder, or type
|
||||||
|
inputs = page.eles('css:input')
|
||||||
|
for inp in inputs:
|
||||||
|
itype = inp.attr('type') or 'text'
|
||||||
|
name = inp.attr('name') or ''
|
||||||
|
ph = inp.attr('placeholder') or ''
|
||||||
|
|
||||||
|
if itype in ['text', 'email']:
|
||||||
|
# Heuristic: match common username field indicators
|
||||||
|
if any(kw in (name + ph).lower() for kw in ['phone', 'email', 'account', 'user', 'mobile', 'login']):
|
||||||
|
inp.clear().input('your_username')
|
||||||
|
elif itype == 'password':
|
||||||
|
inp.clear().input('your_password')
|
||||||
|
```
|
||||||
|
|
||||||
|
## CAPTCHA Solving with ddddocr
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 1. Find the CAPTCHA image element
|
||||||
|
captcha_img = (page.ele('css:img.captcha')
|
||||||
|
or page.ele('css:.captcha-img')
|
||||||
|
or page.ele('xpath://img[contains(@src, "captcha")]'))
|
||||||
|
|
||||||
|
if not captcha_img:
|
||||||
|
captcha_input = page.ele('@name=captcha')
|
||||||
|
if captcha_input:
|
||||||
|
captcha_img = captcha_input.sibling('tag:img')
|
||||||
|
|
||||||
|
# 2. Save the image (PITFALL: use a simple filename, NOT a directory path)
|
||||||
|
# DrissionPage's save() may create a directory if the src URL looks like a path.
|
||||||
|
# Always use a clean local filename.
|
||||||
|
import shutil
|
||||||
|
captcha_path = '/tmp/captcha_solve.jpg'
|
||||||
|
if os.path.isdir(captcha_path):
|
||||||
|
shutil.rmtree(captcha_path)
|
||||||
|
|
||||||
|
# Use screenshot method instead of save() for reliability:
|
||||||
|
captcha_img.get_screenshot(path=captcha_path)
|
||||||
|
|
||||||
|
# 3. OCR recognition
|
||||||
|
ocr = ddddocr.DdddOcr()
|
||||||
|
with open(captcha_path, 'rb') as f:
|
||||||
|
img_bytes = f.read()
|
||||||
|
captcha_text = ocr.classification(img_bytes)
|
||||||
|
print(f"CAPTCHA: {captcha_text}")
|
||||||
|
|
||||||
|
# 4. Fill the captcha field
|
||||||
|
page.ele('@name=captcha').clear().input(captcha_text)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Submit and Verify
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Click login button
|
||||||
|
login_btn = page.ele('text:登录') or page.ele('text:Login') or page.ele('css:button[type=submit]')
|
||||||
|
if login_btn:
|
||||||
|
login_btn.click()
|
||||||
|
else:
|
||||||
|
page.press('Enter')
|
||||||
|
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
# Verify success
|
||||||
|
if 'dashboard' in page.url.lower() or 'main' in page.url.lower():
|
||||||
|
print("Login successful!")
|
||||||
|
else:
|
||||||
|
# Check for error messages
|
||||||
|
body = page('tag:body').text
|
||||||
|
if 'error' in body.lower() or '错误' in body:
|
||||||
|
print("Login failed — check credentials or captcha")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Retry with CAPTCHA Refresh
|
||||||
|
|
||||||
|
If the captcha is wrong, refresh and retry:
|
||||||
|
|
||||||
|
```python
|
||||||
|
for attempt in range(3):
|
||||||
|
# ... fill form and solve captcha ...
|
||||||
|
login_btn.click()
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
if 'error' not in page('tag:body').text.lower():
|
||||||
|
break
|
||||||
|
|
||||||
|
# Click captcha image to refresh
|
||||||
|
if captcha_img:
|
||||||
|
captcha_img.click()
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
page.refresh()
|
||||||
|
time.sleep(2)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pitfalls
|
||||||
|
|
||||||
|
- **`save()` creates directories**: DrissionPage's `element.save(path)` may create a *directory* if the source URL contains path-like segments (e.g., `captcha.jpg;jsessionid=...`). Always use a clean local filename and check `os.path.isdir()` first.
|
||||||
|
- **`get_screenshot()` is more reliable**: For single elements, `element.get_screenshot(path=...)` is more reliable than `save()`.
|
||||||
|
- **uv-managed Python**: Use a temp venv to install packages.
|
||||||
|
- **Headless + sandbox flags**: Always use `--no-sandbox --disable-dev-shm-usage --disable-gpu` and `co.headless()`.
|
||||||
|
- **Auto port**: Use `co.auto_port()` to avoid conflicts.
|
||||||
|
- **Wait times**: Add `time.sleep(2-5)` after page loads and form submissions for JS-rendered content.
|
||||||
|
- **Iframe logins**: If inputs are inside iframes, switch context: `page = page.eles('tag:iframe')[0].child()`.
|
||||||
|
- **Multiple hidden inputs**: Sites may have many hidden inputs. Filter by `type` and visible attributes.
|
||||||
|
- **CAPTCHA case sensitivity**: Some sites require uppercase/lowercase matching. Try `captcha_text.upper()` or `.lower()` if login fails.
|
||||||
Reference in New Issue
Block a user