-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsend.js
More file actions
140 lines (116 loc) · 4.89 KB
/
send.js
File metadata and controls
140 lines (116 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// send.js
require('dotenv').config();
const puppeteer = require('puppeteer');
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const KEYWORDS = [
'platform', 'dashboard', 'membership', 'saas', 'web app',
'wordpress', 'Webflow', 'wix', 'shopify', 'shopify theme',
'shopify development', 'shopify development agency', 'shopify development company',
'shopify development team', 'shopify development services', 'woocommerce', 'Mandarin',
'web development', 'web developer', 'seo', 'automation', '3d website', 'chatbot'
];
const HISTORY_FILE = path.join(__dirname, 'sent_projects.json');
let sentLinks = [];
try {
if (fs.existsSync(HISTORY_FILE)) {
sentLinks = JSON.parse(fs.readFileSync(HISTORY_FILE));
console.log(`📁 Loaded history with ${sentLinks.length} sent projects.`);
} else {
console.log("📁 No history file found, starting fresh.");
}
} catch (e) {
console.warn("⚠️ Failed to load history. Starting fresh.");
}
(async () => {
const WEBHOOK_URL = process.env.WEBHOOK_URL;
if (!WEBHOOK_URL) {
console.error("❌ Missing WEBHOOK_URL in .env");
process.exit(1);
}
const browser = await puppeteer.launch({
headless: 'new',
defaultViewport: null,
});
const page = await browser.newPage();
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
);
console.log("🔍 Navigating to Freelancer jobs page...");
await page.goto('https://www.freelancer.com/jobs/?q=platform', {
waitUntil: 'domcontentloaded',
timeout: 60000
});
console.log("📦 Extracting project data...");
const projects = await page.evaluate((KEYWORDS) => {
const cards = Array.from(document.querySelectorAll('.JobSearchCard-item'));
console.log(`🧾 Found ${cards.length} job cards`);
return cards.slice(0, 20).map((card, idx) => {
const titleEl = card.querySelector('.JobSearchCard-primary-heading-link');
const descEl = card.querySelector('.JobSearchCard-primary-description');
const budgetEl = card.querySelector('.JobSearchCard-secondary-price');
const tagsEl = card.querySelectorAll('.JobSearchCard-primary-tagsLink');
const tags = Array.from(tagsEl).map(tag => tag.innerText.trim());
const title = titleEl?.innerText.trim() || '';
const description = descEl?.innerText.trim() || '';
const combined = `${title} ${description}`.toLowerCase();
console.log(`🔍 [${idx}] Title: ${title}`);
console.log(` → Description: ${description}`);
const matched = KEYWORDS.some(keyword => combined.includes(keyword));
console.log(` → Keyword matched? ${matched}`);
if (!matched) {
console.log(` ❌ Skipped: No keyword matched.`);
return null;
}
const link = titleEl ? `https://www.freelancer.com${titleEl.getAttribute('href')}` : '';
if (!link) {
console.log(` ❌ Skipped: No link found.`);
return null;
}
const budgetText = budgetEl?.innerText.trim() || '';
console.log(` → Budget raw: ${budgetText}`);
const budgetLower = budgetText.toLowerCase();
if (budgetLower.includes('hour') || budgetLower.includes('/hr') || budgetLower.includes('hourly')) {
console.log(` ❌ Skipped: Hourly job.`);
return null;
}
const budgetValues = (budgetText.match(/\d{2,5}/g) || []).map(n => parseInt(n));
const budgetLow = budgetValues.length > 0 ? Math.min(...budgetValues) : null;
console.log(` → Parsed lowest budget: ${budgetLow}`);
if (budgetLow !== null && budgetLow < 300) {
console.log(` ❌ Skipped: Budget too low.`);
return null;
}
console.log(` ✅ Included: ${title}`);
return {
title,
description,
budget: budgetText,
tags,
posted_time: card.querySelector('.JobSearchCard-primary-heading-days')?.innerText.trim() || '',
link
};
}).filter(Boolean);
}, KEYWORDS);
await browser.close();
console.log(`🔍 Total matching projects after filter: ${projects.length}`);
const newProjects = projects.filter(p => !sentLinks.includes(p.link));
console.log(`🆕 New (unsent) projects: ${newProjects.length}`);
if (!newProjects.length) {
console.log("🟡 No new matching projects found.");
return;
}
console.log(`🚀 Sending ${newProjects.length} new project(s) to Power Automate...`);
for (const project of newProjects) {
try {
const res = await axios.post(WEBHOOK_URL, project);
console.log(`✅ Sent: ${project.title} | Status: ${res.status}`);
sentLinks.push(project.link);
} catch (err) {
console.error(`❌ Failed to send: ${project.title}`, err.response?.data || err.message);
}
}
fs.writeFileSync(HISTORY_FILE, JSON.stringify(sentLinks, null, 2));
console.log("✅ All done. History updated.");
})();