482 lines
17 KiB
Markdown
482 lines
17 KiB
Markdown
# Factors.AI — Account Export Automation
|
|
### Automatic daily email alerts when new companies visit your website
|
|
|
|
---
|
|
|
|
## What does this tool do?
|
|
|
|
Every time you run it, this tool does **four things automatically** — no clicking, no manual work:
|
|
|
|
```
|
|
1. LOGS IN → Opens Factors.AI in the background and signs in with your credentials
|
|
2. DOWNLOADS → Goes to Account Profiles, clicks the export button, downloads the CSV
|
|
3. COMPARES → Checks: are there any new company domains that weren't in the last export?
|
|
4. EMAILS → If yes, sends a formatted HTML email to everyone on your list
|
|
If no new entries → does nothing (no email sent)
|
|
```
|
|
|
|
After every run, the fresh CSV is saved as `data/last_export.csv` — that becomes the baseline for the next comparison.
|
|
|
|
---
|
|
|
|
## What the email looks like
|
|
|
|
**Subject line examples:**
|
|
|
|
| Situation | Subject |
|
|
|---|---|
|
|
| Very first run ever | `[Factors.AI] First Run — 483 Accounts Exported (2026-07-01)` |
|
|
| New companies found | `[Factors.AI] 7 New Accounts Detected (2026-07-01)` |
|
|
| Nothing new | *(no email sent at all)* |
|
|
|
|
**Email body:** A styled HTML table with one row per new company, showing:
|
|
|
|
| Account Domain | Company Name | Company Industry | Company Employee Range | Company Annual Revenue | Last Activity |
|
|
|---|---|---|---|---|---|
|
|
| dell.com | Dell | Internet Software & Services | 100K+ | $102,300,000,000 | 2026-07-01 04:48:32 |
|
|
| adobe.com | Adobe | Internet Software & Services | 10K-50K | $19,409,000,000 | 2026-06-18 11:29:45 |
|
|
|
|
---
|
|
|
|
## How "new entry" is decided
|
|
|
|
The tool uses **Account Domain** (the website address, e.g. `dell.com`) as the unique identifier for each company.
|
|
|
|
- A company is **new** if its domain appears in today's export but was **not** in `data/last_export.csv`
|
|
- The comparison is case-insensitive (`Dell.com` = `dell.com`)
|
|
- Only `data/last_export.csv` is kept — no growing archive, no extra storage
|
|
|
|
---
|
|
|
|
## Files in this folder
|
|
|
|
```
|
|
factors_automation/
|
|
│
|
|
├── main.py ← The only file you ever run ("python main.py")
|
|
├── scraper.py ← Controls the Chrome browser (login, navigate, download)
|
|
├── comparator.py ← Compares today's CSV with last_export.csv
|
|
├── mailer.py ← Builds the HTML email and sends it via SMTP
|
|
├── config.py ← All your settings live here (reads from .env)
|
|
│
|
|
├── requirements.txt ← List of Python packages the tool needs
|
|
├── .env.example ← Template — copy this to .env and fill in your details
|
|
├── .env ← YOUR private settings (create this yourself — never share it)
|
|
│
|
|
├── data/
|
|
│ └── last_export.csv ← Auto-created after first run. This is the comparison baseline.
|
|
│
|
|
├── tmp_download/ ← Temporary staging folder. Chrome downloads here first.
|
|
│ Cleaned automatically before each run.
|
|
│ Error screenshots are saved here if something goes wrong.
|
|
│
|
|
└── automation.log ← Full log of every run (auto-created). Check this if anything fails.
|
|
```
|
|
|
|
> **Do not delete** `data/last_export.csv` — it is the memory of the tool.
|
|
> If you delete it, the next run will treat every account as new and email the full list.
|
|
|
|
---
|
|
|
|
## Prerequisites — what you need before setup
|
|
|
|
You need **three things** installed on the computer that will run this:
|
|
|
|
### 1. Python 3.10 or newer
|
|
Check your version by opening a terminal and typing:
|
|
```
|
|
python --version
|
|
```
|
|
If it shows `Python 3.10.x` or higher, you're good.
|
|
If not, download from: https://www.python.org/downloads/
|
|
|
|
### 2. Google Chrome browser
|
|
The tool controls Chrome in the background. Download from: https://www.google.com/chrome/
|
|
|
|
> The matching ChromeDriver (what lets Python control Chrome) is downloaded **automatically** the first time you run the tool. You do not need to install it yourself.
|
|
|
|
### 3. A Gmail account to send from (recommended)
|
|
Any Gmail account works. You will need to generate an **App Password** for it (explained in the setup below). You cannot use your regular Gmail password.
|
|
|
|
---
|
|
|
|
## Setup — step by step
|
|
|
|
### Step 1 — Download and unzip the project
|
|
|
|
Unzip `factors_automation.zip` somewhere on your computer, for example:
|
|
- **Mac/Linux:** `~/factors_automation/`
|
|
- **Windows:** `C:\factors_automation\`
|
|
|
|
### Step 2 — Open a terminal in that folder
|
|
|
|
- **Mac:** Right-click the folder → "New Terminal at Folder"
|
|
- **Windows:** Open the folder in File Explorer → click the address bar → type `cmd` → press Enter
|
|
|
|
### Step 3 — Create a virtual environment
|
|
|
|
A virtual environment keeps this tool's packages separate from everything else on your computer.
|
|
|
|
```bash
|
|
python -m venv venv
|
|
```
|
|
|
|
Then activate it:
|
|
|
|
```bash
|
|
# Mac / Linux:
|
|
source venv/bin/activate
|
|
|
|
# Windows:
|
|
venv\Scripts\activate
|
|
```
|
|
|
|
You will see `(venv)` appear at the start of your terminal prompt. This means it is active.
|
|
|
|
### Step 4 — Install the required packages
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
This downloads and installs four packages:
|
|
- **selenium** — controls the Chrome browser
|
|
- **webdriver-manager** — automatically downloads the right ChromeDriver
|
|
- **pandas** — reads and compares CSV files
|
|
- **python-dotenv** — reads your settings from the `.env` file
|
|
|
|
### Step 5 — Create your `.env` settings file
|
|
|
|
Copy the template:
|
|
|
|
```bash
|
|
# Mac / Linux:
|
|
cp .env.example .env
|
|
|
|
# Windows:
|
|
copy .env.example .env
|
|
```
|
|
|
|
Now open the `.env` file in any text editor (Notepad, TextEdit, VS Code, etc.) and fill in your real values. Here is what each line means:
|
|
|
|
```
|
|
FACTORS_EMAIL=natesh.krishnan@yourcompany.io
|
|
```
|
|
The email address used to log in to app.factors.ai.
|
|
|
|
```
|
|
FACTORS_PASSWORD=YourActualPassword
|
|
```
|
|
The password for that Factors.AI account.
|
|
|
|
```
|
|
SMTP_HOST=smtp.gmail.com
|
|
```
|
|
Leave this as-is if you are using Gmail. Change only if you use a different email provider (Outlook = `smtp.office365.com`, etc.).
|
|
|
|
```
|
|
SMTP_PORT=587
|
|
```
|
|
Leave this as-is. Port 587 is the standard secure email port (STARTTLS). Works with all major email providers.
|
|
|
|
```
|
|
SENDER_EMAIL=your_sender@gmail.com
|
|
```
|
|
The Gmail address the alerts will be sent **from**.
|
|
|
|
```
|
|
SENDER_PASSWORD=xxxx xxxx xxxx xxxx
|
|
```
|
|
**This is NOT your regular Gmail password.** You must generate an **App Password** — see the section below.
|
|
|
|
```
|
|
RECIPIENT_EMAILS=person1@company.com,person2@company.com
|
|
```
|
|
Everyone who should receive the alert emails. Separate multiple addresses with commas. No spaces around the commas.
|
|
|
|
```
|
|
HEADLESS=true
|
|
```
|
|
`true` means Chrome runs invisibly in the background (recommended for scheduled/daily runs).
|
|
`false` means you can watch Chrome open and do its work on screen (useful when testing or debugging).
|
|
|
|
---
|
|
|
|
### How to generate a Gmail App Password
|
|
|
|
Gmail does not allow scripts to log in with your regular password. You must create a special one-time App Password.
|
|
|
|
1. Go to your Google Account: https://myaccount.google.com/
|
|
2. Click **Security** in the left sidebar
|
|
3. Under "How you sign in to Google", click **2-Step Verification** and enable it if not already on
|
|
4. Go back to Security → scroll down → click **App Passwords**
|
|
5. Under "Select app" choose **Mail** → under "Select device" choose **Other** → type `FactorsAI Bot`
|
|
6. Click **Generate**
|
|
7. Google shows a 16-character code like `abcd efgh ijkl mnop`
|
|
8. Copy it (including spaces) into your `.env` file as `SENDER_PASSWORD`
|
|
|
|
> This App Password only lets the script send emails. It cannot access your Gmail inbox or change your account.
|
|
|
|
---
|
|
|
|
## Choosing which columns to export
|
|
|
|
By default (`FIELDS_TO_SELECT = None` in `config.py`), the tool keeps whichever columns are **already checked** in the Factors.AI export modal — which is the default 5:
|
|
|
|
- Company Name
|
|
- Company Industry
|
|
- Company Employee Range
|
|
- Company Annual Revenue
|
|
- Last Activity
|
|
|
|
The downloaded CSV will also always include **Account Domain** as the first column (this is always exported by Factors.AI and is used as the unique comparison key).
|
|
|
|
### To change which columns are exported
|
|
|
|
Open `config.py` in a text editor. Find this section near the bottom:
|
|
|
|
```python
|
|
FIELDS_TO_SELECT: list[str] | None = None # None = use defaults
|
|
```
|
|
|
|
Change it to a list of the fields you want. For example, to export only Company Name, Industry, and Last Activity:
|
|
|
|
```python
|
|
FIELDS_TO_SELECT = [
|
|
"$6Signal_name",
|
|
"$6Signal_industry",
|
|
"last_activity",
|
|
]
|
|
```
|
|
|
|
**Full list of available field codes:**
|
|
|
|
| Code | Column name in CSV |
|
|
|---|---|
|
|
| `"$6Signal_name"` | Company Name |
|
|
| `"$6Signal_industry"` | Company Industry |
|
|
| `"$6Signal_employee_range"` | Company Employee Range |
|
|
| `"$6Signal_annual_revenue"` | Company Annual Revenue |
|
|
| `"last_activity"` | Last Activity |
|
|
| `"$tag_hidden"` | Tags Hidden |
|
|
| `"$latest_source"` | Account Latest Source |
|
|
| `"$latest_campaign"` | Account Latest Campaign |
|
|
| `"$initial_campaign"` | Account First Campaign |
|
|
| `"$account_activity_url"` | Account Activity URL |
|
|
| `"$domain_name"` | Company ID |
|
|
| `"$latest_page_url"` | Account Latest Page URL |
|
|
|
|
When you set `FIELDS_TO_SELECT` to a list, the tool first clicks "Clear All" in the modal, then checks exactly the fields you listed. Setting it back to `None` restores the default behaviour.
|
|
|
|
---
|
|
|
|
## Running the tool
|
|
|
|
Make sure `(venv)` is active in your terminal before running.
|
|
|
|
### Normal run (invisible browser, sends real email)
|
|
```bash
|
|
python main.py
|
|
```
|
|
|
|
### Watch mode — opens real Chrome window (good for testing)
|
|
```bash
|
|
python main.py --visible
|
|
```
|
|
Use this the first time you run it to verify everything works correctly.
|
|
|
|
### Dry run — downloads and compares, but does NOT send any email
|
|
```bash
|
|
python main.py --dry-run
|
|
```
|
|
The new entries are printed to the terminal instead. Useful for checking what would have been emailed.
|
|
|
|
### Combine both flags
|
|
```bash
|
|
python main.py --visible --dry-run
|
|
```
|
|
|
|
---
|
|
|
|
## What happens during a run (step by step)
|
|
|
|
When you run `python main.py`, here is exactly what happens internally:
|
|
|
|
**Step 1 — Download CSV**
|
|
- Chrome launches (invisibly unless `--visible`)
|
|
- Opens `https://app.factors.ai/`
|
|
- Enters email and password from your `.env`
|
|
- Waits up to 30 seconds for login to complete
|
|
- Finds and clicks the Account Profiles page in the sidebar navigation. If that fails, it tries five known URL patterns (`/accounts`, `/account-profiles`, `/accounts/profiles`, `/analytics/accounts`, `/v2/accounts`)
|
|
- Clicks the download (↓) toolbar icon
|
|
- The export modal appears — columns are selected (or kept as default)
|
|
- Clicks "Export CSV"
|
|
- Waits up to 90 seconds for the file to appear in `tmp_download/`
|
|
- Chrome closes
|
|
|
|
**Step 2 — Compare**
|
|
- Loads `tmp_download/<downloaded>.csv` and `data/last_export.csv`
|
|
- Compares every row's **Account Domain** (first column)
|
|
- Identifies domains in the new file that were not in the old file
|
|
- If `data/last_export.csv` does not exist → all rows are treated as new (first run)
|
|
|
|
**Step 3 — Email** *(skipped if zero new entries and not first run)*
|
|
- Builds an HTML email with a table of new rows
|
|
- Connects to `smtp.gmail.com:587` via STARTTLS
|
|
- Logs in with `SENDER_EMAIL` and `SENDER_PASSWORD`
|
|
- Sends the email to all `RECIPIENT_EMAILS`
|
|
|
|
**Step 4 — Save**
|
|
- Copies the downloaded CSV to `data/last_export.csv`, replacing the previous one
|
|
- This becomes the new baseline for the next run
|
|
|
|
Everything is logged to `automation.log` in real time.
|
|
|
|
---
|
|
|
|
## Scheduling — run automatically every day
|
|
|
|
### Mac / Linux (using cron)
|
|
|
|
Open the cron editor:
|
|
```bash
|
|
crontab -e
|
|
```
|
|
|
|
This runs every day at 01:30 UTC, which is 07:00 IST. (adjust the paths to match your actual folder):
|
|
```
|
|
30 1 * * * /full/path/to/factors_automation/venv/bin/python /full/path/to/factors_automation/main.py
|
|
```
|
|
|
|
To find your full path, run this command inside the project folder:
|
|
```bash
|
|
pwd
|
|
```
|
|
|
|
Example result: `/home/natesh/factors_automation`
|
|
|
|
So the cron line would be:
|
|
```
|
|
0 8 * * * /home/natesh/factors_automation/venv/bin/python /home/natesh/factors_automation/main.py
|
|
```
|
|
|
|
### Windows (using Task Scheduler)
|
|
|
|
1. Open **Task Scheduler** (search for it in the Start menu)
|
|
2. Click **Create Basic Task** on the right
|
|
3. Name: `Factors.AI Export`
|
|
4. Trigger: **Daily** at your preferred time
|
|
5. Action: **Start a program**
|
|
6. Program: `C:\factors_automation\venv\Scripts\python.exe`
|
|
7. Arguments: `C:\factors_automation\main.py`
|
|
8. Click **Finish**
|
|
|
|
---
|
|
|
|
## Checking if a run succeeded
|
|
|
|
Open `automation.log` in any text editor. A successful run looks like this:
|
|
|
|
```
|
|
2026-07-01 08:00:01 [INFO ] __main__ — =================================================================
|
|
2026-07-01 08:00:01 [INFO ] __main__ — Factors.AI Account Export Automation — START
|
|
2026-07-01 08:00:01 [INFO ] __main__ — headless=True dry_run=False
|
|
2026-07-01 08:00:01 [INFO ] __main__ — =================================================================
|
|
2026-07-01 08:00:01 [INFO ] __main__ — STEP 1: Downloading CSV …
|
|
2026-07-01 08:00:04 [INFO ] scraper — Opening https://app.factors.ai/ …
|
|
2026-07-01 08:00:09 [INFO ] scraper — Email entered.
|
|
2026-07-01 08:00:10 [INFO ] scraper — Password entered.
|
|
2026-07-01 08:00:11 [INFO ] scraper — Login form submitted.
|
|
2026-07-01 08:00:14 [INFO ] scraper — Logged in successfully. URL: https://app.factors.ai/accounts
|
|
2026-07-01 08:00:18 [INFO ] scraper — Download button clicked.
|
|
2026-07-01 08:00:21 [INFO ] scraper — 'Export CSV' button clicked.
|
|
2026-07-01 08:00:24 [INFO ] scraper — Download complete → tmp_download/accounts.csv
|
|
2026-07-01 08:00:24 [INFO ] scraper — Browser closed.
|
|
2026-07-01 08:00:24 [INFO ] __main__ — STEP 2: Comparing with previous export …
|
|
2026-07-01 08:00:24 [INFO ] comparator — Comparison complete: 7 new / 490 total (previous had 483 rows)
|
|
2026-07-01 08:00:24 [INFO ] __main__ — ✓ New entries detected (7 new)
|
|
2026-07-01 08:00:24 [INFO ] __main__ — STEP 3: Sending alert email …
|
|
2026-07-01 08:00:26 [INFO ] mailer — Email sent to: ['you@company.com'] | subject: [Factors.AI] 7 New Accounts Detected (2026-07-01)
|
|
2026-07-01 08:00:26 [INFO ] __main__ — STEP 4: Saving export as last_export.csv
|
|
2026-07-01 08:00:26 [INFO ] __main__ — =================================================================
|
|
2026-07-01 08:00:26 [INFO ] __main__ — Automation complete ✓
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### "Could not find email input on the login page"
|
|
The tool took a screenshot. Open `tmp_download/login_page_not_found.png` to see what the browser was looking at.
|
|
|
|
Possible causes:
|
|
- Factors.AI is down or showing a maintenance page
|
|
- Your internet connection is slow (increase `_PAGE_LOAD_TIMEOUT` in `scraper.py` from `30` to `60`)
|
|
- The login page layout changed (contact whoever maintains this tool)
|
|
|
|
### "Still on login page after submission — check credentials"
|
|
Your `FACTORS_EMAIL` or `FACTORS_PASSWORD` in `.env` is wrong. Check and correct them.
|
|
Screenshot saved as `tmp_download/post_login_timeout.png`.
|
|
|
|
### "Could not navigate to the Account Profiles page"
|
|
The tool could not find the Accounts section. Screenshot saved as `tmp_download/accounts_not_found.png`.
|
|
|
|
Try running with `--visible` to watch what happens:
|
|
```bash
|
|
python main.py --visible --dry-run
|
|
```
|
|
|
|
### "CSV download did not complete within 90 seconds"
|
|
The download took too long. Possible causes:
|
|
- Very large export (many thousands of rows)
|
|
- Slow internet
|
|
|
|
Open `scraper.py`, find the line `_DOWNLOAD_TIMEOUT = 90` near the top, and change `90` to `180`.
|
|
|
|
### Gmail error: "Username and Password not accepted"
|
|
You used your regular Gmail password instead of an App Password.
|
|
Follow the **"How to generate a Gmail App Password"** steps above.
|
|
|
|
### Gmail error: "SMTPAuthenticationError"
|
|
Same as above, or 2-Step Verification is not enabled on the Gmail account.
|
|
|
|
### `SyntaxError` or `python: command not found`
|
|
Your Python version is older than 3.10. Check with `python --version` and upgrade at https://www.python.org/downloads/
|
|
|
|
### The `(venv)` prefix disappeared from my terminal
|
|
Your virtual environment is no longer active. Reactivate it:
|
|
```bash
|
|
# Mac / Linux:
|
|
source venv/bin/activate
|
|
|
|
# Windows:
|
|
venv\Scripts\activate
|
|
```
|
|
|
|
---
|
|
|
|
## Security notes
|
|
|
|
- Your `.env` file contains passwords. **Never share it, email it, or commit it to Git.**
|
|
- The `.env.example` file contains only placeholder text and is safe to share.
|
|
- The Gmail App Password only allows the script to send email. It cannot read your inbox, delete messages, or change your Google account settings.
|
|
- `data/last_export.csv` contains company names and domains from Factors.AI. Treat it with the same care as any customer data.
|
|
|
|
---
|
|
|
|
## Quick-reference card
|
|
|
|
| Task | Command |
|
|
|---|---|
|
|
| Normal run (background, sends email) | `python main.py` |
|
|
| Watch browser work on screen | `python main.py --visible` |
|
|
| Test without sending email | `python main.py --dry-run` |
|
|
| Watch + test, no email | `python main.py --visible --dry-run` |
|
|
|
|
| File | Purpose |
|
|
|---|---|
|
|
| `.env` | Your private credentials and settings |
|
|
| `config.py` | Export field selection and advanced settings |
|
|
| `data/last_export.csv` | Comparison baseline — do not delete |
|
|
| `automation.log` | Full run history — check when something fails |
|
|
| `tmp_download/*.png` | Error screenshots — check when a step fails | |