se cambia el uso de google chrome por firefox para que se pueda utlizar en macpro late 2013
This commit is contained in:
1 parent
1c39f6f45f
commit
99a587c4da
10 files changed
+48
-40
No files matched your search
+1
-1
@@ -59,7 +59,7 @@ def get_headers(token):
|
|||||||
return {
|
return {
|
||||||
"Authorization": f"Bearer {token}",
|
"Authorization": f"Bearer {token}",
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0",
|
||||||
"Origin": "https://e-factura.sunat.gob.pe",
|
"Origin": "https://e-factura.sunat.gob.pe",
|
||||||
"Referer": "https://e-factura.sunat.gob.pe/",
|
"Referer": "https://e-factura.sunat.gob.pe/",
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -3,7 +3,7 @@
|
|||||||
## systemd (Linux)
|
## systemd (Linux)
|
||||||
|
|
||||||
### Requisitos adicionales
|
### Requisitos adicionales
|
||||||
- **Google Chrome** instalado (para `get_token_headless.py`)
|
- **Mozilla Firefox** instalado (para `get_token_headless.py`)
|
||||||
- **rsync** y **cifs-utils** (para montar SMB y sincronizar)
|
- **rsync** y **cifs-utils** (para montar SMB y sincronizar)
|
||||||
|
|
||||||
### Servicio
|
### Servicio
|
||||||
@@ -34,7 +34,7 @@ sudo systemctl start sunat-cpe
|
|||||||
## NSSM (Windows)
|
## NSSM (Windows)
|
||||||
|
|
||||||
### Requisitos
|
### Requisitos
|
||||||
- **Google Chrome** instalado (cualquier versión) — necesario para `get_token_headless.py`
|
- **Mozilla Firefox** instalado (cualquier versión) — necesario para `get_token_headless.py`
|
||||||
- Python 3.12+ con dependencias instaladas
|
- Python 3.12+ con dependencias instaladas
|
||||||
- **Unidad de red mapeable** (SMB) para sincronizar descargas
|
- **Unidad de red mapeable** (SMB) para sincronizar descargas
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ nssm start SUNAT-CPE
|
|||||||
NSSM redirige stdout/stderr a `C:\ruta\descarga_xml_sunat\logs\` por defecto (el logger del daemon también escribe allí).
|
NSSM redirige stdout/stderr a `C:\ruta\descarga_xml_sunat\logs\` por defecto (el logger del daemon también escribe allí).
|
||||||
|
|
||||||
### Renovación de token
|
### Renovación de token
|
||||||
Como servicio, el daemon usa `get_token_headless()` (headless, Chrome real) para renovar el token automáticamente sin intervención. Si Chrome no está instalado, el daemon lo detecta y usa `get_token.py headless=False` como respaldo (requiere escritorio). Para renovar manualmente:
|
Como servicio, el daemon usa `get_token_headless()` (headless, Firefox real) para renovar el token automáticamente sin intervención. Si Firefox no está instalado, el daemon lo detecta y usa `get_token.py headless=False` como respaldo (requiere escritorio). Para renovar manualmente:
|
||||||
|
|
||||||
```cmd
|
```cmd
|
||||||
C:\ruta\descarga_xml_sunat\sunat-env\Scripts\python get_token.py
|
C:\ruta\descarga_xml_sunat\sunat-env\Scripts\python get_token.py
|
||||||
@@ -77,7 +77,7 @@ nssm start SUNAT-CPE
|
|||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM python:3.12-slim
|
FROM python:3.12-slim
|
||||||
RUN pip install -r requirements.txt && playwright install chromium
|
RUN pip install -r requirements.txt && playwright install firefox
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
CMD ["python", "main.py"]
|
CMD ["python", "main.py"]
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ flowchart TD
|
|||||||
B -->|No| C["Esperar"]
|
B -->|No| C["Esperar"]
|
||||||
C --> B
|
C --> B
|
||||||
B -->|Sí| D["Token válido?"]
|
B -->|Sí| D["Token válido?"]
|
||||||
D -->|No| E["get_token_headless()<br>channel=chrome headless=True<br>→ get_token.py headless=False"]
|
D -->|No| E["get_token_headless()<br>headless=True<br>→ get_token.py headless=False"]
|
||||||
E --> F["token.json"]
|
E --> F["token.json"]
|
||||||
D -->|Sí| F
|
D -->|Sí| F
|
||||||
end
|
end
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
| Archivo | Función |
|
| Archivo | Función |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `main.py` | Daemon orquestador. Bucle infinito con horarios configurables, obtiene token, consulta HANA, procesa pendientes (nuevos + reintentos). |
|
| `main.py` | Daemon orquestador. Bucle infinito con horarios configurables, obtiene token, consulta HANA, procesa pendientes (nuevos + reintentos). |
|
||||||
| `get_token_headless.py` | Login headless via Chrome real (`channel="chrome"`). Sin ventana visible. |
|
| `get_token_headless.py` | Login headless via Firefox real. Sin ventana visible. |
|
||||||
| `get_token.py` | Login SOL via Playwright (headless=False). Navega menú → extrae JWT de `sessionStorage['SUNAT.token']`. |
|
| `get_token.py` | Login SOL via Playwright (headless=False). Navega menú → extrae JWT de `sessionStorage['SUNAT.token']`. |
|
||||||
| `consulta_cpe.py` | Consulta API REST `api-cpe.sunat.gob.pe`. Retorna `(data, status_code)`. Lanza `TokenExpiredError` en 401. |
|
| `consulta_cpe.py` | Consulta API REST `api-cpe.sunat.gob.pe`. Retorna `(data, status_code)`. Lanza `TokenExpiredError` en 401. |
|
||||||
| `hana_manager.py` | Conexión HANA vía `hdbcli`. Consulta pendientes en `OPCH`, actualiza flags de descarga. |
|
| `hana_manager.py` | Conexión HANA vía `hdbcli`. Consulta pendientes en `OPCH`, actualiza flags de descarga. |
|
||||||
|
|||||||
+4
-4
@@ -3,9 +3,9 @@
|
|||||||
## Requisitos
|
## Requisitos
|
||||||
|
|
||||||
- Python 3.10+
|
- Python 3.10+
|
||||||
- Playwright (chromium)
|
- Playwright (firefox)
|
||||||
- Acceso a HANA (hdbcli)
|
- Acceso a HANA (hdbcli)
|
||||||
- **Google Chrome** (para `get_token_headless.py`)
|
- **Mozilla Firefox** (para `get_token_headless.py`)
|
||||||
- **rsync** (Mac/Linux) o **net use** (Windows) para SMB
|
- **rsync** (Mac/Linux) o **net use** (Windows) para SMB
|
||||||
|
|
||||||
## Instalación
|
## Instalación
|
||||||
@@ -17,7 +17,7 @@ source sunat-env/bin/activate
|
|||||||
|
|
||||||
# Instalar dependencias
|
# Instalar dependencias
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
playwright install chromium
|
playwright install firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
## Variables de Entorno (`.env`)
|
## Variables de Entorno (`.env`)
|
||||||
@@ -55,7 +55,7 @@ source sunat-env/bin/activate
|
|||||||
# Obtener token manualmente (con navegador visible)
|
# Obtener token manualmente (con navegador visible)
|
||||||
python get_token.py
|
python get_token.py
|
||||||
|
|
||||||
# Obtener token headless (sin ventana, requiere Chrome real)
|
# Obtener token headless (sin ventana, requiere Firefox real)
|
||||||
python get_token_headless.py
|
python get_token_headless.py
|
||||||
|
|
||||||
# Daemon completo (automático)
|
# Daemon completo (automático)
|
||||||
|
|||||||
+1
-2
@@ -28,9 +28,8 @@ def save_screenshot(page, name):
|
|||||||
def get_token(headless=False, timeout=60000):
|
def get_token(headless=False, timeout=60000):
|
||||||
print("🚀 Iniciando navegador...")
|
print("🚀 Iniciando navegador...")
|
||||||
with sync_playwright() as p:
|
with sync_playwright() as p:
|
||||||
browser = p.chromium.launch(
|
browser = p.firefox.launch(
|
||||||
headless=headless,
|
headless=headless,
|
||||||
args=["--disable-blink-features=AutomationControlled"],
|
|
||||||
)
|
)
|
||||||
context = browser.new_context(
|
context = browser.new_context(
|
||||||
viewport={"width": 1280, "height": 800},
|
viewport={"width": 1280, "height": 800},
|
||||||
|
|||||||
+9
-17
@@ -12,39 +12,31 @@ from get_token import (
|
|||||||
)
|
)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
USER_AGENT = (
|
USER_AGENT = (
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) "
|
||||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
"Gecko/20100101 Firefox/121.0"
|
||||||
"Chrome/120.0.0.0 Safari/537.36"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
def chrome_instalado():
|
def firefox_instalado():
|
||||||
sistema = platform.system().lower()
|
sistema = platform.system().lower()
|
||||||
if sistema == "windows":
|
if sistema == "windows":
|
||||||
return bool(shutil.which("chrome")) or any(
|
return bool(shutil.which("firefox")) or any(
|
||||||
os.path.exists(p) for p in [
|
os.path.exists(p) for p in [
|
||||||
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
"C:\\Program Files\\Mozilla Firefox\\firefox.exe",
|
||||||
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
elif sistema == "darwin":
|
elif sistema == "darwin":
|
||||||
return os.path.exists("/Applications/Google Chrome.app")
|
return os.path.exists("/Applications/Firefox.app")
|
||||||
elif sistema == "linux":
|
elif sistema == "linux":
|
||||||
return bool(shutil.which("google-chrome") or shutil.which("google-chrome-stable"))
|
return bool(shutil.which("firefox") or shutil.which("firefox-esr"))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
def get_token_headless(timeout=90000):
|
def get_token_headless(timeout=90000):
|
||||||
with sync_playwright() as p:
|
with sync_playwright() as p:
|
||||||
browser = p.chromium.launch(
|
browser = p.firefox.launch(
|
||||||
channel="chrome",
|
|
||||||
headless=True,
|
headless=True,
|
||||||
args=[
|
|
||||||
"--disable-blink-features=AutomationControlled",
|
|
||||||
"--disable-popup-blocking",
|
|
||||||
"--no-sandbox",
|
|
||||||
"--window-size=1280,800",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
context = browser.new_context(
|
context = browser.new_context(
|
||||||
viewport={"width": 1280, "height": 800},
|
viewport={"width": 1280, "height": 800},
|
||||||
|
|||||||
+2
-2
@@ -67,7 +67,7 @@ def try_password_grant():
|
|||||||
"client_id": CLIENT_ID,
|
"client_id": CLIENT_ID,
|
||||||
}
|
}
|
||||||
headers = {
|
headers = {
|
||||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ def try_auth_code_flow():
|
|||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
session.verify = False
|
session.verify = False
|
||||||
session.headers.update({
|
session.headers.update({
|
||||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0",
|
||||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ def obtener_token():
|
|||||||
|
|
||||||
print("\n🔑 Token no disponible o expirado. Obteniendo nuevo...")
|
print("\n🔑 Token no disponible o expirado. Obteniendo nuevo...")
|
||||||
|
|
||||||
from get_token_headless import get_token_headless as obtener_headless, chrome_instalado
|
from get_token_headless import get_token_headless as obtener_headless, firefox_instalado
|
||||||
if not chrome_instalado():
|
if not firefox_instalado():
|
||||||
print(" ⚠️ Google Chrome no instalado. Saltando headless...")
|
print(" ⚠️ Firefox no instalado. Saltando headless...")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
if obtener_headless():
|
if obtener_headless():
|
||||||
|
|||||||
+22
-5
@@ -1,5 +1,22 @@
|
|||||||
playwright
|
certifi==2026.6.17
|
||||||
python-dotenv
|
charset-normalizer==3.4.9
|
||||||
requests
|
contourpy==1.3.3
|
||||||
hdbcli
|
cycler==0.12.1
|
||||||
matplotlib
|
fonttools==4.63.0
|
||||||
|
greenlet==3.5.3
|
||||||
|
hdbcli==2.29.25
|
||||||
|
idna==3.18
|
||||||
|
kiwisolver==1.5.0
|
||||||
|
matplotlib==3.11.0
|
||||||
|
numpy==2.5.1
|
||||||
|
packaging==26.2
|
||||||
|
pillow==12.3.0
|
||||||
|
playwright==1.61.0
|
||||||
|
pyee==13.0.1
|
||||||
|
pyparsing==3.3.2
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
python-dotenv==1.2.2
|
||||||
|
requests==2.34.2
|
||||||
|
six==1.17.0
|
||||||
|
typing_extensions==4.16.0
|
||||||
|
urllib3==2.7.0
|
||||||
Reference in new issue
Block a user