LinkedIn Scraper & Email Enricher Pro manual
Set up the Python script, enter profile URLs, and generate a local CSV from the configured API responses.
Who it is for: It is intended for people who can edit a short list in a Python file and use a terminal. You need your own API keys and must handle contact data lawfully and responsibly.
Setup time: First setup: depends on installing Python and obtaining API access.
What it does
- Optionally loads variables from a .env file located in the same folder as the script.
- Reads profile URLs from the urls list defined in the main block of linkedin-scraper.py.
- For each URL, sends a request to the Proxycurl profile endpoint with personal_email, personal_contact_number, and extra set to include.
- From the profile response, collects name, headline, first company in experiences, city, first available email value, URL, and follower count when available.
- When a name and company are available, builds an estimated domain and uses Hunter.io's email finder endpoint to request an email address.
- Waits one second at the end of each URL iteration.
- If at least one result exists, writes a UTF-8 CSV named leads.csv and prints the result content as JSON in the terminal.
What it does not do
- It does not log in to LinkedIn and does not include browser automation or direct scraping of the LinkedIn website.
- It does not provide a graphical interface, command-line arguments, CSV URL import, or direct CRM delivery.
- It does not run the search_company_employees function during normal startup; that function is defined in the code but is not called from the main block.
- It does not check an email verification status in the script and does not validate the estimated company domain.
- It does not create accounts, API keys, contact consent, or a privacy notice for you.
Requirements
- Python 3: You need a working Python installation and terminal access. The package does not state a specific minimum Python version.
- Python dependencies: requirements.txt requires requests==2.31.0 and python-dotenv>=1.0.0.
- Proxycurl API key: Required for the profile request. The README states that a free plan is available; check the provider's price list for current availability, terms, and costs.
- Hunter.io API key: Required for email lookup. The README mentions 25 free searches per month; check the provider directly for current availability, terms, and costs.
- Internet connection: The script makes HTTP requests to the Proxycurl and Hunter.io APIs when it runs.
- Text editor and authorised URLs: You need a text editor to edit .env and the urls list, plus profile URLs that you may lawfully process.
Step-by-step setup
- Extract the ZIP and check the delivered files. Extract linkedin-scraper-email-enricher.zip into a working folder. The delivered files are README.md, README.en.md, linkedin-scraper.py, and requirements.txt. The README refers to .env.example, but that template is not in the archive, so you must create .env manually in step 6.
- Check Python. Open a terminal in the working folder and confirm that the Python command is available. If it is not, install Python using your operating system's standard process and reopen the terminal.
- Move into the extracted folder. Replace the placeholder path with the folder where you extracted the package.
- Create and activate a virtual environment. A virtual environment keeps this package's dependencies separate from other Python projects. The commands shown are for macOS- or Linux-compatible shells; on Windows, create the same environment and activate it using the command appropriate to your shell.
- Install the delivered dependencies. With the virtual environment active, install exactly the dependencies listed in requirements.txt.
- Create a .env file with your keys. In the same folder as linkedin-scraper.py, create a text file named .env. Add the two lines below, replacing the placeholders with your own keys. Do not paste or share real keys in chats, public documents, or repositories.
- Replace the example URL. Open linkedin-scraper.py. In the final block, replace the example URL in the urls list with one or more profile URLs that you may lawfully use. Keep each URL in quotation marks and separate items with a comma.
- Check data purpose and provider limits. Before running the script, make sure you have an appropriate lawful basis and the required notices for any personal data you may process. Respect applicable terms of use, API instructions, request limits, and provider policies; the one-second pause in the code does not replace those obligations.
- Run the script with valid keys. Run the command from the folder containing .env and linkedin-scraper.py. The script will send requests to external APIs. With a valid profile response, the terminal displays progress; at the end, the code reports in Italian how many profiles it saved and prints the JSON results.
- Open and review the generated CSV. If at least one profile produced a result, find leads.csv in the current folder and open it as a UTF-8 CSV. Manually review every row before moving it into a CRM or using it for contact; if no result is added, the code does not create the CSV file.
Daily use
Prepare a small, relevant list
Update urls with only profiles for which you have a lawful purpose and suitable basis. Start with a small number of URLs so you can check data quality and expected API consumption.
Run from the right folder
Activate the virtual environment, make sure .env is next to the script, and run python linkedin-scraper.py. Do not use placeholder keys or somebody else's keys.
Read terminal output rather than ignoring errors
The program prints a progress line for each URL and then a JSON list. Keep any error messages so you can determine whether an issue concerns Python, the network, a key, or a provider response.
Check every CSV column
In leads.csv, review name, title, company, location, email, linkedin, and followers. Values depend on API responses and may be empty, missing, or unsuitable for your purpose.
Review data before using it
Do not treat the domain constructed by the code or an email returned by it as certain. Verify data, apply your privacy procedures, and move contacts to a CRM only after the review you require.
Practical cases
Controlled preparation of B2B contacts
A small service business has an internal list of public URLs relating to potentially relevant contacts and wants to prepare a manual review within its sales process.
- Confirm that collection and contact are permitted for your purpose.
- Enter a small selection of URLs in urls.
- Run the script with your own API keys.
- Open leads.csv and check company, title, email, and URL before any use.
- Record the source and information needed for the contact in your process.
You obtain a local CSV for human review, without automatic CRM export or message sending.
Updating an already authorised list
A team already holds profile URLs that it may process and wants to compare API-returned fields with its internal records.
- Create a working copy of the authorised URL list.
- Replace the example list in the Python file.
- Run the script from the folder containing .env.
- Compare the CSV manually against internal records.
- Correct or exclude missing, ambiguous, or no-longer-needed data.
You obtain a comparison file containing the fields the code can extract, while the team retains the final decision about data.
Technical assessment in a test environment
A developer wants to understand the package's behaviour before considering it for an authorised internal procedure.
- Create the virtual environment and install requirements.txt.
- Read the scrape_profile, find_email, search_company_employees, and bulk_scrape methods.
- Configure authorised test keys and one URL that you may lawfully use.
- Run a single processing operation and inspect the terminal and CSV.
- Assess privacy, API limits, and any code changes separately.
You obtain practical understanding of the input format, intended calls, and local output of the script.
Tips
- Keep an unmodified copy of linkedin-scraper.py before changing the urls list.
- Start with one authorised URL to check that the environment, keys, and output format are configured correctly.
- Keep .env private and add it to your version-control exclusions if you use a repository.
- Replace the delivered example URL; it is not a ready-to-use contact list.
- Check the company field because the code uses the first returned experience to construct the estimated domain.
- Remember that the domain is created by lowercasing the company name, removing spaces, and adding .com; always review it manually.
- If leads.csv is not created, first check whether at least one profile produced a result, because the file is written only in that case.
- Check provider limits, terms, and possible costs before processing many rows; do not infer costs from the package beyond the notes in the README.
- For commercial activity, document purpose, lawful basis, data source, notice, and how you will handle data-subject requests.
Troubleshooting
The terminal says that python is not recognised.
Python is not installed, is not available in PATH, or the system uses a different command. Install or configure Python using your operating system's standard process, reopen the terminal, and check the version. Then run commands from the extracted folder.
An error refers to requests or dotenv.
Dependencies were not installed for the Python interpreter that is running the script. Activate the virtual environment created for the package and run python -m pip install -r requirements.txt again. Then run the script with that same environment active.
A key appears to be missing or a placeholder is used.
The .env file does not exist, is in the wrong folder, uses different names, or does not contain valid keys. Create .env manually next to linkedin-scraper.py and use exactly PROXYCURL_API_KEY and HUNTER_API_KEY. Do not use the default values YOUR_PROXYCURL_KEY or YOUR_HUNTER_KEY.
leads.csv does not appear after execution.
The code opens and writes the CSV only when the results list contains at least one profile. An unsuccessful or invalid Proxycurl profile response can leave results empty. Check the urls list, your authorised access, and the status of your keys with the providers. Also make sure you are looking for the file in the folder from which you launched the command.
The run stops during email lookup with a response or JSON error.
find_email directly reads Hunter.io's JSON response and does not include explicit handling for HTTP errors, network errors, or a non-JSON response. Check connection, key, and service status through the provider's channels. Follow their instructions and retry only once the issue is resolved; if you edit the code, do so in a working copy.
The email or domain in the CSV is not reliable for the intended use.
The code estimates the domain from the first company field, removes spaces, and adds .com. It does not compare that estimate with an official domain or check an email verification status. Do not use that data automatically. Manually verify company, domain, and the lawfulness of use before putting a record into your systems or contacting anyone.
Some CSV fields are blank.
The name, title, company, location, personal_emails, and follower_count fields depend on the profile response, and the code uses empty values or zero when some fields are unavailable. Treat blank fields as data that was not returned, not as confirmed information. Retain only data that is necessary and complete under your procedures.
A spreadsheet shows incorrect characters in the CSV.
The code writes the file using UTF-8, while some applications may open it using a different default encoding. Import or open leads.csv with UTF-8 explicitly selected and review columns before saving or transforming the file.
Limits to know
- The script works only on URLs manually entered in urls; it does not search for profiles or access LinkedIn through a browser.
- Information depends on Proxycurl and Hunter.io responses, valid keys, the network, and provider conditions.
- The .env.example file mentioned in the READMEs was not delivered in the archive; you must create .env manually.
- The CSV is created only when at least one result is added and the package has no CRM import or email-sending feature.
- Constructing a company domain is a technical simplification and can be wrong; the script does not certify the returned email.
- Profile and contact information may be personal data. You must comply with applicable terms, GDPR, notice, lawful basis, minimisation, retention, and data-subject requests.
- Do not use the script to bypass limits, terms of use, robot policies, or protective measures of the services involved.
Frequently asked questions
Is .env.example included?
No. Both READMEs mention it, but it is not present in the delivered archive. Create .env manually in the same folder as linkedin-scraper.py with the two variables shown in this manual.
Which package files are Italian and which are English?
README.md is Italian and README.en.md is English. linkedin-scraper.py contains Italian comments, description text, and terminal messages; requirements.txt contains no language-specific instructions.
Can I run the script without API keys?
It is not useful to do so. If environment variables are absent, the code uses placeholders and still attempts external API HTTP requests during normal startup.
Which columns are in leads.csv?
When results are produced, the columns are name, title, company, location, email, linkedin, and followers. The file is written in UTF-8.
Are CSV emails verified by the script?
No. The code calls Hunter.io's email finder endpoint and stores the returned email, or the profile's first personal_emails value as an alternative. It does not check a verification field.
Can I search a company's employees from this startup flow?
The code defines search_company_employees with a default role_filter of CEO, but the main block does not call that method. Using it would require editing the Python file and independently checking applicable terms and limits.
Where are support and the stated licence terms?
The delivered README directs you to the AI chatbot at digitalhub.autos and states unlimited personal and commercial use, with resale of the file prohibited. For current clarification, use the seller channel identified in the README.