| |
| import streamlit as st |
| import requests |
| import json |
| from datetime import datetime |
| import time |
| from docx import Document |
| import tempfile |
| import pandas as pd |
| import zipfile |
| import os |
|
|
| |
| def process_dataset(api_token, input_url, email_id, phone_number): |
| """ |
| Triggers a dataset and fetches the snapshot from BrightData API, saving the result to a DOCx file. |
| |
| Parameters: |
| api_token (str): The authorization token for API access. |
| input_url (str): The LinkedIn URL to be processed. |
| email_id (str): The email ID to be added to the profile data. |
| phone_number (str): The phone number to be added to the profile data. |
| |
| Returns: |
| str: Path to the DOCx file. |
| """ |
| print("Starting process_dataset") |
| print(f"API Token: {api_token[:5]}***") |
| print(f"Input URL: {input_url}") |
| print(f"Email ID: {email_id}, Phone Number: {phone_number}") |
|
|
| headers = { |
| "Authorization": f"Bearer {api_token}", |
| "Content-Type": "application/json" |
| } |
|
|
| |
| trigger_url = "https://api.brightdata.com/datasets/v3/trigger" |
| trigger_payload = [{"url": input_url}] |
| trigger_params = {"dataset_id": "gd_l1viktl72bvl7bjuj0", "include_errors": "true"} |
|
|
| try: |
| print("Triggering BrightData API...") |
| trigger_response = requests.post(trigger_url, json=trigger_payload, headers=headers, params=trigger_params) |
| print(f"Trigger Response Status Code: {trigger_response.status_code}") |
| if trigger_response.status_code == 200: |
| trigger_data = trigger_response.json() |
| print(f"Trigger Response Data: {trigger_data}") |
| snapshot_id = trigger_data.get('snapshot_id', None) |
| if not snapshot_id: |
| print("Snapshot ID not found in response.") |
| return "Error: Snapshot ID not found in the response" |
| else: |
| print("Failed to trigger dataset.") |
| return f"Error: Failed to trigger dataset with status code {trigger_response.status_code}" |
| except Exception as e: |
| print(f"Exception during API trigger: {e}") |
| return f"Error: {str(e)}" |
|
|
| |
| snapshot_url = f"https://api.brightdata.com/datasets/v3/snapshot/{snapshot_id}" |
| snapshot_params = {"format": "json"} |
|
|
| attempts = 0 |
| max_retries = 10 |
| retry_interval = 10 |
| snapshot_data = None |
|
|
| while attempts < max_retries: |
| try: |
| print(f"Fetching snapshot (Attempt {attempts + 1})...") |
| snapshot_response = requests.get(snapshot_url, headers=headers, params=snapshot_params) |
| print(f"Snapshot Response Status Code: {snapshot_response.status_code}") |
| if snapshot_response.status_code == 200: |
| snapshot_data = snapshot_response.json() |
| print("Snapshot data retrieved successfully.") |
| break |
| elif snapshot_response.status_code == 202: |
| print("Snapshot not ready yet. Retrying...") |
| time.sleep(retry_interval) |
| attempts += 1 |
| else: |
| print("Failed to fetch snapshot.") |
| return f"Error: Failed to fetch snapshot with status code {snapshot_response.status_code}" |
| except Exception as e: |
| print(f"Exception during snapshot fetch: {e}") |
| return f"Error: {str(e)}" |
|
|
| if not snapshot_data: |
| print("Snapshot data could not be retrieved after retries.") |
| return "Error: Snapshot data could not be retrieved after multiple retries" |
|
|
| if isinstance(snapshot_data, list) and len(snapshot_data) > 0: |
| profile_data = snapshot_data[0] |
| print(f"Profile Data: {profile_data}") |
| else: |
| print("No data found in snapshot.") |
| return "Error: No data found in snapshot" |
|
|
| profile_data['Email_ID'] = email_id |
| profile_data['Phone_Number'] = phone_number |
|
|
| |
| print("Generating DOCx file...") |
| doc = Document() |
| doc.add_heading('LinkedIn Profile Data', 0) |
|
|
| def add_json_to_word(data, parent=None): |
| if isinstance(data, dict): |
| for key, value in data.items(): |
| parent.add_paragraph(f"{key}:") |
| add_json_to_word(value, parent=parent) |
| elif isinstance(data, list): |
| for item in data: |
| add_json_to_word(item, parent=parent) |
| else: |
| parent.add_paragraph(f"{data}") |
|
|
| add_json_to_word(profile_data, parent=doc) |
|
|
| temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".docx") |
| doc.save(temp_file.name) |
|
|
| print(f"DOCx file saved at {temp_file.name}") |
| return temp_file |
|
|
| |
| def create_streamlit_interface(): |
| st.title("LinkedIn Profile Scraper Using BrightData") |
|
|
| api_token = st.text_input("BrightData Token", placeholder="Enter BrightData Token", type="password") |
| uploaded_file = st.file_uploader("Upload CSV File", type=["csv"]) |
|
|
| if uploaded_file and api_token: |
| print("CSV file and API token received.") |
| df = pd.read_csv(uploaded_file) |
| valid_rows = df[df['LinkedIn Link'].notna()] |
| print(f"Number of valid rows: {len(valid_rows)}") |
|
|
| temp_files = [] |
|
|
| for index, row in valid_rows.iterrows(): |
| try: |
| email = row['Email Address'] if pd.notna(row['Email Address']) else "None" |
| phone = row['Mobile Number'] if pd.notna(row['Mobile Number']) else "None" |
| linkedin = row['LinkedIn Link'] |
|
|
| print(f"Processing LinkedIn Profile: {linkedin}") |
| result_file = process_dataset(api_token, linkedin, email, phone) |
|
|
| if isinstance(result_file, str) and result_file.startswith("Error"): |
| print(f"Error for {linkedin}: {result_file}") |
| st.error(f"Error for {linkedin}: {result_file}") |
| continue |
|
|
| temp_files.append(result_file.name) |
| print(f"Successfully processed {linkedin}") |
|
|
| with open(result_file.name, "rb") as f: |
| st.download_button( |
| label=f"Download Resume for {row.get('Applicant Name', 'Unknown')}", |
| data=f, |
| file_name=f"Resume_{row.get('Applicant Name', 'Unknown')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.docx", |
| mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document" |
| ) |
| except Exception as e: |
| print(f"Unexpected error for {row['LinkedIn Link']}: {e}") |
| st.error(f"Unexpected error for {row['LinkedIn Link']}: {str(e)}") |
|
|
| if temp_files: |
| print("Creating ZIP file for all resumes...") |
| zip_file_path = tempfile.NamedTemporaryFile(delete=False, suffix=".zip").name |
| with zipfile.ZipFile(zip_file_path, 'w') as zipf: |
| for file_path in temp_files: |
| arcname = os.path.basename(file_path) |
| zipf.write(file_path, arcname=arcname) |
| print(f"ZIP file created at {zip_file_path}") |
|
|
| |
| with open(zip_file_path, "rb") as f: |
| st.download_button( |
| label="Download All Resumes as ZIP", |
| data=f, |
| file_name=f"All_Resumes_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip", |
| mime="application/zip" |
| ) |
| elif not api_token: |
| print("API token not provided.") |
| st.warning("Please enter your BrightData API Token.") |
| elif not uploaded_file: |
| print("CSV file not uploaded.") |
| st.warning("Please upload a CSV file.") |
|
|
| |
| if __name__ == "__main__": |
| print("Starting Streamlit application...") |
| create_streamlit_interface() |