This commit is contained in:
So
2025-11-21 10:42:37 +07:00
commit 3986e38b49
7 changed files with 1474 additions and 0 deletions

2
.env.example Normal file
View File

@@ -0,0 +1,2 @@
FB_USERNAME=
FB_PASSWORD=

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
.env
node_modules/
npm-debug.log*
.DS_Store
*.log
facebook_cookies.json

60
README.md Normal file
View File

@@ -0,0 +1,60 @@
# Facebook Post Crawler
## Purpose
This crawler automatically fetches the first post from a Facebook fanpage using Selenium WebDriver and saves the result to `facebook_first_post.json`.
## System Requirements
- Node.js >= 16
- Google Chrome browser
## Installation
1. Clone the repository:
```sh
git clone <repo-url>
cd Crawler-FB
```
2. Install required packages:
```sh
npm install selenium-webdriver chromedriver dotenv
```
## Environment Setup
Create a `.env` file in the project root with the following content:
```
FB_USERNAME=your_facebook_email_or_phone
FB_PASSWORD=your_facebook_password
```
> **Note:** Do not share your `.env` or `facebook_cookies.json` files in git to protect your credentials.
## Running the Crawler
Navigate to the script directory:
```sh
cd crawler-fb
```
Run the crawler:
```sh
node crawler-fb/crawler-post.js <fanpage_url>
```
Example:
```sh
node node crawler-fb/crawler-post.js "http://exmaple.com" (website yout want crawler)
```
- If no URL is provided, the script will crawl the default fanpage `logisticsarena.bacib.tdtu`.
- Username and password can be set via environment variables or passed as command-line arguments:
```sh
node crawler-post.js <fanpage_url> <unused> <unused> <username> <password>
```
## Output
- The first post will be saved to `facebook_first_post.json`.
- Login cookies will be saved to `facebook_cookies.json` for future sessions, so you do not need to log in every time.
## Security Notice
- Each user should log in and generate their own cookies; do not share cookie files between machines.
- Do not commit `.env` or `facebook_cookies.json` to git.
## Support
For issues or support, please contact the project administrator.

346
crawler-fb/crawler-post.js Normal file
View File

@@ -0,0 +1,346 @@
require("dotenv").config();
const { Builder, By, until } = require("selenium-webdriver");
const chrome = require("selenium-webdriver/chrome");
const fs = require("fs");
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function initializeDriver() {
const options = new chrome.Options();
options.addArguments("--start-maximized");
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage");
options.addArguments("--disable-blink-features=AutomationControlled");
options.addArguments(
"--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"
);
return new Builder().forBrowser("chrome").setChromeOptions(options).build();
}
async function safeFindElement(element, by) {
try {
return await element.findElement(by);
} catch (error) {
return null;
}
}
async function loginFacebook(driver, username, password, cookieFilePath) {
await driver.get("https://www.facebook.com/login");
try {
const emailInput = await driver.wait(
until.elementLocated(By.name("email")),
10000
);
await emailInput.clear();
await emailInput.sendKeys(username);
const passInput = await driver.wait(
until.elementLocated(By.name("pass")),
10000
);
await passInput.clear();
await passInput.sendKeys(password);
const loginBtn = await driver.wait(
until.elementLocated(By.name("login")),
10000
);
await loginBtn.click();
await sleep(5000);
const currentUrl = await driver.getCurrentUrl();
if (currentUrl.includes("login") || currentUrl.includes("checkpoint")) {
throw new Error("Login failed!");
}
await saveCookies(driver, cookieFilePath);
console.log("Auto login successful!");
return true;
} catch (e) {
console.log("Auto login error:", e.message);
return false;
}
}
async function loadCookies(driver, cookieFilePath) {
try {
if (fs.existsSync(cookieFilePath)) {
const cookies = JSON.parse(fs.readFileSync(cookieFilePath, "utf8"));
await driver.get("https://www.facebook.com");
await sleep(2000);
for (const cookie of cookies) {
try {
await driver.manage().addCookie(cookie);
} catch (error) {
console.log(`Could not add cookie: ${cookie.name}`);
}
}
console.log("Cookies loaded successfully!");
await driver.navigate().refresh();
await sleep(3000);
return true;
}
} catch (error) {
console.log("Error loading cookies:", error.message);
}
return false;
}
async function saveCookies(driver, cookieFilePath) {
try {
const cookies = await driver.manage().getCookies();
fs.writeFileSync(cookieFilePath, JSON.stringify(cookies, null, 2));
console.log("Cookies saved successfully!");
return true;
} catch (error) {
console.log("Error saving cookies:", error.message);
return false;
}
}
async function getFirstPostBySelector(driver) {
const postSelectors = [
'[data-pagelet*="FeedUnit"]',
'[role="article"]',
'[data-testid="fbfeed_story"]',
".userContentWrapper",
"[data-ft]",
'div[data-pagelet="ProfileTimeline"]',
'[data-pagelet="ProfileTimeline"] > div > div',
'div[data-ad-preview="message"]',
];
let firstPost = null;
let usedSelector = "";
for (const selector of postSelectors) {
try {
const posts = await driver.findElements(By.css(selector));
if (posts.length > 0) {
firstPost = posts[0];
usedSelector = selector;
break;
}
} catch (error) {
continue;
}
}
if (!firstPost) {
console.log("No post found!");
return null;
}
try {
for (let i = 0; i < 3; i++) {
await driver.executeScript(
`
var post = arguments[0];
var btns = post.querySelectorAll('div[role="button"], button, span');
for (var j=0; j<btns.length; j++) {
if (btns[j].innerText && (btns[j].innerText.trim() === 'See more' || btns[j].innerText.trim() === 'Xem thêm')) {
btns[j].click();
}
}
`,
firstPost
);
await sleep(1200);
const innerHTML = await firstPost.getAttribute("innerHTML");
if (!innerHTML.includes("See more") && !innerHTML.includes("Xem thêm")) {
break;
}
}
} catch (e) {}
return { firstPost, usedSelector };
}
(async function main() {
let driver = await initializeDriver();
const cookieFilePath = "facebook_cookies.json";
const targetUrl =
process.argv[2] || "https://www.facebook.com/logisticsarena.bacib.tdtu";
const username = process.argv[4] || process.env.FB_USERNAME || "";
const password = process.argv[5] || process.env.FB_PASSWORD || "";
// const timeRetry = 5 * 60 * 1000; // 5 minutes
const timeRetry = 20 * 1000;
if (!username || !password) {
console.log(
"Missing username or password! Pass via argv or set FB_USERNAME, FB_PASSWORD environment variables."
);
process.exit(1);
}
let postSet = new Set();
let contentSet = new Set();
if (fs.existsSync("facebook_first_post.json")) {
try {
const oldData = JSON.parse(
fs.readFileSync("facebook_first_post.json", "utf8")
);
if (Array.isArray(oldData)) {
oldData.forEach((item) => {
if (item.postLink) postSet.add(item.postLink.split("?")[0]);
if (item.content) contentSet.add(item.content.trim());
});
} else {
if (oldData.postLink) postSet.add(oldData.postLink.split("?")[0]);
if (oldData.content) contentSet.add(oldData.content.trim());
}
} catch (e) {}
}
try {
let cookiesLoaded = await loadCookies(driver, cookieFilePath);
let isLoggedIn = false;
if (cookiesLoaded) {
try {
const currentUrl = await driver.getCurrentUrl();
if (
!currentUrl.includes("login") &&
!currentUrl.includes("checkpoint")
) {
isLoggedIn = true;
}
} catch (e) {}
}
if (!isLoggedIn) {
let loginSuccess = await loginFacebook(
driver,
username,
password,
cookieFilePath
);
if (!loginSuccess) {
process.exit(1);
}
}
while (true) {
await driver.get(targetUrl);
await sleep(5000);
const postResult = await getFirstPostBySelector(driver);
if (!postResult) {
console.log("No post found!");
} else {
const { firstPost, usedSelector } = postResult;
let content = "";
let contentElement = await safeFindElement(
firstPost,
By.css('div[data-ad-preview="message"]')
);
if (contentElement) content = await contentElement.getText();
if (!content) {
contentElement = await safeFindElement(
firstPost,
By.css(".userContent")
);
if (contentElement) content = await contentElement.getText();
}
if (!content) {
contentElement = await safeFindElement(
firstPost,
By.css('div[role="article"]')
);
if (contentElement) content = await contentElement.getText();
}
if (!content) {
contentElement = await safeFindElement(
firstPost,
By.css('div[data-testid="post_message"]')
);
if (contentElement) content = await contentElement.getText();
}
if (!content) {
content = await firstPost.getText();
}
if (!content) content = "None content";
let time = "";
try {
let timeElement = await safeFindElement(
firstPost,
By.css('a[aria-label][href*="/posts/"]')
);
time = timeElement ? await timeElement.getText() : "";
} catch (e) {
time = "";
}
let postLink = "";
try {
let linkElements = await firstPost.findElements(By.css("a"));
for (const el of linkElements) {
const href = await el.getAttribute("href");
if (
href &&
(href.includes("/posts/") ||
href.includes("/permalink/") ||
href.includes("fbid="))
) {
postLink = href;
break;
}
}
} catch (e) {}
let postLinkKey = postLink ? postLink.split("?")[0] : "";
let images = [];
try {
let imageElements = await firstPost.findElements(By.css("img"));
for (const img of imageElements) {
const src = await img.getAttribute("src");
if (
src &&
src.startsWith("http") &&
!src.includes("data:image") &&
!src.includes("static.xx")
) {
images.push(src);
}
}
} catch (e) {}
if (
(postLinkKey && postSet.has(postLinkKey)) ||
(content && contentSet.has(content.trim()))
) {
console.log("Post already fetched or content duplicated, skipping!");
} else {
let newPost = {
url: targetUrl,
selector_used: usedSelector,
content: content,
postLink: postLink,
images: images,
timestamp: new Date().toISOString(),
time: time,
};
let postsArr = [];
if (fs.existsSync("facebook_first_post.json")) {
try {
const oldData = JSON.parse(
fs.readFileSync("facebook_first_post.json", "utf8")
);
if (Array.isArray(oldData)) {
postsArr = oldData;
} else {
postsArr = [oldData];
}
} catch (e) {}
}
postsArr.push(newPost);
fs.writeFileSync(
"facebook_first_post.json",
JSON.stringify(postsArr, null, 2)
);
postSet.add(postLinkKey);
contentSet.add(content.trim());
console.log("Saved latest post to facebook_first_post.json");
}
}
await sleep(timeRetry);
}
} catch (error) {
console.error("Error:", error.message);
} finally {
setTimeout(async () => {
await driver.quit();
console.log("Browser closed");
}, 10000);
}
})();

31
facebook_first_post.json Normal file
View File

@@ -0,0 +1,31 @@
[
{
"url": "https://www.facebook.com/logisticsarena.bacib.tdtu",
"selector_used": "[data-pagelet*=\"FeedUnit\"]",
"content": "[𝐋𝐀𝐂 𝟐𝟎𝟐𝟒]TRI ÂN ĐẠI SỨ TRUYỀN THÔNG CUỘC THI LOGISTIC ARENA COMPETITION 2024\n Khi sự gắn kết tạo nên sức mạnh lan tỏa \nCuộc thi Logistic Arena Competition 2024 không chỉ là hành trình tìm kiếm những tài năng xuất sắc trong lĩnh vực Logistics mà còn là câu chuyện về sự đồng hành, cống hiến và truyền cảm hứng. Thành công của cuộc thi không thể thiếu sự đóng góp to lớn từ những \"người đặc biệt\" - Đại sứ Truyền thông.\n Cầu nối lan tỏa thông điệp\nNhững Đại sứ Truyền thông không chỉ mang đến sức trẻ, sự sáng tạo mà còn đóng vai trò là chiếc cầu nối gắn kết cuộc thi với cộng đồng. Qua từng bài viết, từng hình ảnh và video, họ đã thổi hồn vào Logistic Arena Competition 2024, giúp cuộc thi không chỉ được biết đến mà còn được yêu mến bởi đông đảo bạn trẻ khắp cả nước.\n Hành trình của sự cống hiến\nChúng ta cảm nhận được sự tâm huyết trong từng hoạt động từ các Đại sứ. Dù bận rộn với học tập và công việc, họ vẫn không ngừng nỗ lực lan tỏa thông điệp của cuộc thi đến gần hơn với cộng đồng yêu Logistics. Mỗi bài viết, mỗi lần chia sẻ hay mỗi sự kiện đồng hành là một minh chứng rõ nét cho tinh thần trách nhiệm và sự sáng tạo đáng trân trọng.\n Lời tri ân sâu sắc\nBan Tổ chức Logistic Arena Competition 2024 xin gửi lời cảm ơn chân thành và sâu sắc nhất đến các Đại sứ Truyền thông - những \"ngọn đuốc\" đã thắp sáng hành trình của cuộc thi. Thành công của Logistic Arena Competition năm nay chính là kết quả từ sự đồng hành tuyệt vời của các bạn.\n Cảm ơn vì đã là một phần không thể thiếu trong câu chuyện Logistic Arena Competition 2024!\nHãy cùng tiếp tục lan tỏa ngọn lửa đam mê và nhiệt huyết, để Logistics không chỉ là ngành học mà còn là một hành trình đầy cảm hứng.\n#LAC2024\n#LogisticsInnovations \n#TouchtoConnectGoworldwide \n#BACIB\n----------------------------\n𝐋𝐀𝐂𝟐𝟎𝟐𝟒 | 𝐋𝐨𝐠𝐢𝐬𝐭𝐢𝐜𝐬 𝐀𝐫𝐞𝐧𝐚 𝐂𝐨𝐦𝐩𝐞𝐭𝐢𝐭𝐢𝐨𝐧 𝟐𝟎𝟐𝟒 - Cuộc thi Đấu Trường Logistics là sự kiện nổi bật hàng năm, do bộ môn Kinh doanh quốc tế cùng Câu lạc bộ BAC - International Business, Trường Đại học Tôn Đức Thắng tổ chức. Sau 9 mùa thi thành công rực rỡ, chương trình đã khẳng định mình không chỉ là nơi nâng cao kiến thức và kỹ năng về Logistics và Quản lý Chuỗi Cung Ứng, mà còn là cơ hội vàng để sinh viên kết nối, giao lưu với các doanh nghiệp hàng đầu trong ngành. Đây là sân chơi tuyệt vời cho những ai muốn thử thách bản thân, trải nghiệm thực tế, và bước vào tương lai với hành trang vững chắc từ cuộc thi.\n----------------------------\nTHÔNG TIN CHI TIẾT:\nFanpage: Logistics Arena Competition\nGroup chung: Logistics Arena Competition Community\nEmail: btc.logisticsarena@gmail.com\nHotline: Trưởng ban Đối ngoại: 0913 542 303 (Ms. Lan Nhi) \n----------------------------\nHãy theo dõi Fanpage để cập nhật thêm thông tin chi tiết!",
"postLink": "https://www.facebook.com/logisticsarena.bacib.tdtu/posts/pfbid02anu2RHZjLdDgRW7EZzV6TWxHZHYziW9Cc7o71QJ7Ed1YkNkE9hFAg695Vp5fP99ql?__cft__[0]=AZW063FSJPG-l1MOLBURSZi9okQMVnSHCvLvkNv2hGX4_p41XrXz5q_mnoIGCUvUt1nDkJS_4D_DGIGbnXb95RA0q6rsr5jvCqFgXKo3BSsQdfRLjuIaZ0zU4WlHlAC8_XAqj3ZREWXAtcVI2SCmtC5HOtb9oUo39wPqLHHBHNIR7QIjnynFZHS1QViQSdi7n1Y&__tn__=%2CO%2CP-R",
"images": [
"https://scontent.fsgn5-10.fna.fbcdn.net/v/t39.30808-6/493999836_1256271559834524_1003126056507624328_n.jpg?_nc_cat=110&ccb=1-7&_nc_sid=127cfc&_nc_ohc=Jk7PYZqqZ9EQ7kNvwEkwbp9&_nc_oc=AdnDuadNtttcwkk7je8XcSZXf8o_JAf9uQ_83xQebrltg61EYitSaLVnpRhY8jblckY&_nc_zt=23&_nc_ht=scontent.fsgn5-10.fna&_nc_gid=TWdijQgnlDM9c4IWYZiifQ&oh=00_AfjaU5cCzxNFJwoPgC-RXVjFxV5SbruSS7tH29c4-bUkAA&oe=6925C92A",
"https://scontent.fsgn5-5.fna.fbcdn.net/v/t39.30808-6/494627539_1256271986501148_642800077477981456_n.jpg?_nc_cat=108&ccb=1-7&_nc_sid=127cfc&_nc_ohc=8eTlKyEvkwQQ7kNvwHMBUgQ&_nc_oc=AdmopQbTUnbRmEhdETmFrnLFS0Ws337Oylicr30hTHv7y2FYrCmFES9a5WufwUavB78&_nc_zt=23&_nc_ht=scontent.fsgn5-5.fna&_nc_gid=TWdijQgnlDM9c4IWYZiifQ&oh=00_AfidB5ZMe2lduuSDa2g8ytt2SX1SAZ9vMJAHN-VpoCdW1Q&oe=6925B30A",
"https://scontent.fsgn5-15.fna.fbcdn.net/v/t39.30808-6/493855957_1256271643167849_9065622582583944131_n.jpg?_nc_cat=111&ccb=1-7&_nc_sid=127cfc&_nc_ohc=I0M3UrqMrQwQ7kNvwFDKRvJ&_nc_oc=AdlTP8hCqm6LAhV84szdH_OYvdgPulWoHsYdA6w3CXJG2pRvLpnHcwZ0xMSNmIiXLmg&_nc_zt=23&_nc_ht=scontent.fsgn5-15.fna&_nc_gid=TWdijQgnlDM9c4IWYZiifQ&oh=00_AfhM083h4beS0zPFTgkM9weWBZTgFIzHddp-jFhrjGCGPQ&oe=692592A8",
"https://scontent.fsgn5-8.fna.fbcdn.net/v/t39.30808-6/494884943_1256271556501191_8298268670848136976_n.jpg?_nc_cat=109&ccb=1-7&_nc_sid=127cfc&_nc_ohc=O14CWd3nUM4Q7kNvwH4IOqy&_nc_oc=Adn5REa9ndNCO5NaGY9qc00wue03HZyvd5_kQ8Hrc5qe2E8EYD1s3b3rvvzbt50SDWc&_nc_zt=23&_nc_ht=scontent.fsgn5-8.fna&_nc_gid=TWdijQgnlDM9c4IWYZiifQ&oh=00_AfjAk-hfrd95GQ-0_0zaHvGmsLo1ileA5cWhnTtlKMOZVQ&oe=6925AEDB",
"https://scontent.fsgn5-5.fna.fbcdn.net/v/t39.30808-6/493968773_1256271666501180_7014901109322993661_n.jpg?_nc_cat=100&ccb=1-7&_nc_sid=127cfc&_nc_ohc=DBd6W3dpsAUQ7kNvwG9ndfs&_nc_oc=Adl29LKfXRe5ezQG6n0iVrscapatFedTRr2Z8BKgoYM85u9Wu8V36GuPK2c8ug3Dhbo&_nc_zt=23&_nc_ht=scontent.fsgn5-5.fna&_nc_gid=TWdijQgnlDM9c4IWYZiifQ&oh=00_AfgMXpcGepwRm-ZYCYZHn2bPmtTtpwLfZUc5vJtVmFyBWQ&oe=6925BBFB"
],
"timestamp": "2025-11-21T03:26:33.127Z",
"time": "27 November 2024"
},
{
"url": "https://www.facebook.com/profile.php?id=61550678589270",
"selector_used": "[data-pagelet*=\"FeedUnit\"]",
"content": "PACKING LIST - CHỨNG TỪ BẮT BUỘC TRONG XUẤT NHẬP KHẨU \nPacking List - Phiếu đóng gói hàng hóa hay Bảng kê khai danh mục hàng hóa là một trong số các loại chứng từ bắt buộc. \nPacking List cho biết trọng lượng tịnh, trọng lượng bao gồm cả bao bì, phương thức đóng gói của hàng hóa, loại hàng hóa, số lượng, quy cách đóng gói và không bao gồm giá trị của lô hàng. \nTìm hiểu chi tiết về Packing List tại: https://www.tdimex.edu.vn/packing-list\n---------------------\nThông tin liên hệ: \nTDimex Logistics Training Center\nHotline: 038 539 0088\nEmail: db1@tdimex.edu.vn\nFacebook: https://www.facebook.com/tdimextrainingcenter\nWebsite: https://www.tdimex.edu.vn/\nĐịa điểm: 13, Đường số 7, KDC Cityland Center Hills, Phường 7, Gò Vấp, TPHCM\n#TDimexLogisticsTrainingCenter\n#packinglist #phieudonggoi #xuatnhapkhau #logistics",
"postLink": "https://www.facebook.com/permalink.php?story_fbid=pfbid0cEfQVxM2q15cC3hSSts81F6fhhaS5GRinQQ6cQdgecCZm4GQV9X1f3jLUxsaZPXDl&id=61550678589270&__cft__[0]=AZXN0vfEKKJcG09lsSdVDu1bRcAC0FEQScZGItGWcBtotdKH11NGo1b4dUlYampeJZfqxrH7-A6ZKZZNzf_cUpVmyvDBRDBBQcAC51ve8Z03DedGAqwYCDm67nwxZby2Ys76Ezx8arpluS75O0EibjamgzBrgxYwipM2Bp3ZeoTPyLYC1L273zC_Bv2xAntq90zHK5M8SY0_sw1Jg-bBc5N0ekIY284dbpKrkWYGl_I3uA&__tn__=%2CO%2CP-R",
"images": [
"https://scontent.fsgn5-10.fna.fbcdn.net/v/t39.30808-6/481765297_666114822608330_3843986559162663014_n.jpg?_nc_cat=110&ccb=1-7&_nc_sid=127cfc&_nc_ohc=34gX4uQ0xQoQ7kNvwHYbehn&_nc_oc=AdngomjPzweMjKHWIgb4EjiTBsVdOAtLgB2EuUOQiAOaKP4-AJD1QVJpvrOk-k6h7uM&_nc_zt=23&_nc_ht=scontent.fsgn5-10.fna&_nc_gid=3vH0rWfeo3qiIcmgpN0B1A&oh=00_AfhMurwK7fVUn-Odc8gH-drzDAl1R_IGnvrVorT8fSUVZA&oe=6925AECD",
"https://scontent.fsgn5-14.fna.fbcdn.net/v/t39.30808-6/482030108_666114772608335_1114175215837990493_n.jpg?_nc_cat=101&ccb=1-7&_nc_sid=127cfc&_nc_ohc=fxgBw8XSl34Q7kNvwETLxp3&_nc_oc=Adl1k7a7qfQENcpcU4qNt6TqOpD_vS14Bw4WSOmZwe0cj_WylVk6j5U4drrz-zpu2ak&_nc_zt=23&_nc_ht=scontent.fsgn5-14.fna&_nc_gid=3vH0rWfeo3qiIcmgpN0B1A&oh=00_AfgUcu3ilN4PICUBcg3gh72V6ZCy-47Xg0B5CEgiReZUzQ&oe=6925C148",
"https://scontent.fsgn5-5.fna.fbcdn.net/v/t39.30808-6/482199404_666114839274995_6589359877475762674_n.jpg?_nc_cat=108&ccb=1-7&_nc_sid=127cfc&_nc_ohc=NIu9s95_3FoQ7kNvwFUAh6R&_nc_oc=Adk9tz6Y3B1m0xljnW-MFquH9VPciMVxFLdNkWnGYu3JDcemvyyR5R5mqeomedip4Po&_nc_zt=23&_nc_ht=scontent.fsgn5-5.fna&_nc_gid=3vH0rWfeo3qiIcmgpN0B1A&oh=00_AfhDik9y9TbRh2BCtc9VK-1WYiGmDa7n8LwbejvVp5xjfg&oe=6925BE0A",
"https://scontent.fsgn5-10.fna.fbcdn.net/v/t39.30808-6/481282762_666114789275000_3827430822341407703_n.jpg?_nc_cat=107&ccb=1-7&_nc_sid=127cfc&_nc_ohc=g3DQlUblPI4Q7kNvwGKq5X7&_nc_oc=AdlKGv72_9-HQH5Er0zRlTmb61AL2GQIlPAO2bqxeCLZCbIyZ0qa5gYOFjNqjWe3Iqk&_nc_zt=23&_nc_ht=scontent.fsgn5-10.fna&_nc_gid=3vH0rWfeo3qiIcmgpN0B1A&oh=00_AfhEigBLrRdPH-mjOVi7-wv2U5LRlSuKatti0fls_BbdVw&oe=692594FA"
],
"timestamp": "2025-11-21T03:34:16.126Z",
"time": "19 September 2023"
}
]

1007
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

17
package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "crawler-fb",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"chromedriver": "^142.0.3",
"dotenv": "^17.2.3",
"selenium-webdriver": "^4.38.0"
}
}