1. 2scraper
  2. Social media & video
  3. Facebook
Open source · MITRuns with no key, proxy or account

Facebook Scraper

Public Facebook Pages — contacts, followers, owner and latest posts with exact engagement — read logged out.

  • Playwright
  • Selenium
  • Puppeteer
  • Scraping Browser API
  • Scraper API
  • JSON
  • CSV
facebook-pages-scraper
# Page profile
$ python3 playwright_scraper.py --url nike
✓ 4 sample rows · 41 columns in sample_output.json
0accounts, cookies or keys needed
10Pages + 30 posts in 50 s, residential IP (Oct 2026)
3latest posts per Page a logged-out visitor gets
4ways to run: 3 browser engines + Scraper API
Available Facebook scrapers

What the Facebook scraper collects

Give it a Page URL, username or numeric id (or a file of them) and get one row per Page: name, category, verified badge, followers, website, phone, e-mail, address, hours and the legal owner Meta confirmed. With --posts it adds the Page's latest posts with exact reaction, comment, share and video-view counts, as JSON or CSV.

Page profile

Input: A Page URL, username or numeric id

One row per Page with category, description, verified badge, rounded follower count, contacts, hours, rating and owner.

Page + latest posts

Input: A list of Pages in a text file

Each Page row plus up to three post rows with full text, time and exact reactions, comments, shares and video views.

Exact like count

Input: A Page that has run ads

Adds likes_exact, the Page's exact like count read from Meta's Ad Library, at the cost of one more page load per Page.

No local browser

Input: A Page, plus TWOCAPTCHA_KEY in .env

Fetches each Page through 2Captcha's Scraper API: the full Page row and its first post.

Quick start

From zero to Facebook data in 3 steps

  1. Install

    Clone the repository and install one browser engine. Python 3.9+.

    $ git clone https://github.com/2scraper/facebook-pages-scraper.git && cd facebook-pages-scraper
    $ python3 -m venv .venv && source .venv/bin/activate
    $ pip install -r requirements-playwright.txt
    $ playwright install chromium
    $ python3 playwright_scraper.py --url nike --posts 3
  2. Run a scraper

    Pick what you need and run it. Every flag is documented in the README.

    $ python3 playwright_scraper.py --url nike
  3. Get structured data

    Rows land in JSON or CSV (--format), with a .meta.json sidecar recording status, pages fetched and why the run stopped.

Output

Facebook data fields

41 columns per row in a predictable schema. The most useful ones:

FieldWhat it holds
titlePage name, or a post's first line
page_idThe Page id — the same id Meta's Ad Library uses
usernameThe Page's address name
page_categoryCategory as the Page shows it
is_verifiedWhether the Page has the blue badge
followersFollower count, as rounded by Facebook
likes_exactExact like count from the Ad Library (with --exact-likes)
websiteWebsite from the intro card, unwrapped from Facebook's redirect
phonePhone number from the intro card
emailE-mail from the intro card
addressStreet address from the intro card
ownerThe legal owner Meta confirmed for the Page
posted_atPost time in UTC
reactionsExact reaction count of a post
commentsExact comment count of a post
video_viewsExact video-view count of a post
[
  {
    "sku": "facebook-page-15087023444",
    "source": "facebook.com",
    "category": "page",
    "title": "Nike",
    "brand": null,
    "price": null,
    "currency": null,
    "price_source": null,
    "product_url": "https://www.facebook.com/nike",
    "image_url": "https://scontent.fakx3-1.fna.fbcdn.net/v/t39.30808-1/284964043_10159903868513445_769635…",
    "scraped_at": "2026-10-06T12:44:31Z",
    "page_id": "15087023444",
    "profile_id": "100044541544829",
    "username": "nike",
    "page_category": "Sportswear Store",
    "description": "Just Do It.",
    "is_verified": true,
    "followers": 39000000,
    "followers_text": "39M followers",
    "following": 24,
    "likes": null,
    "likes_exact": 39506247,
    "website": "http://nike.com/",
    "phone": "+972 54-292-7777",
    "email": null,
    "address": null,
    "hours": null,
    "price_range": null,
    "recommend_pct": null,
    "review_count": null,
    "owner": "NIKE, Inc.",
    "other_accounts_json": null,
    "cover_url": "https://scontent.fakx3-1.fna.fbcdn.net/v/t39.30808-6/285211224_10159903868008445_547733…",
    "post_id": null,
    "posted_at": null,
    "text": null,
    "reactions": null,
    "comments": null,
    "shares": null,
    "video_views": null
  },
  {
    "sku": "facebook-post-1393461115481927",
    "source": "facebook.com",
    "category": "post",
    "title": "Leave your limits at the surface. #JustDoIt",
    "brand": null,
    "price": null,
    "currency": null,
    "price_source": null,
    "product_url": "https://www.facebook.com/reel/2166091230582141/",
    "image_url": null,
    "scraped_at": "2026-10-06T12:44:31Z",
    "page_id": "15087023444",
    "profile_id": null,
    "username": "nike",
    "page_category": null,
    "description": null,
    "is_verified": null,
    "followers": null,
    "followers_text": null,
    "following": null,
    "likes": null,
    "likes_exact": null,
    "website": null,
    "phone": null,
    "email": null,
    "address": null,
    "hours": null,
    "price_range": null,
    "recommend_pct": null,
    "review_count": null,
    "owner": null,
    "other_accounts_json": null,
    "cover_url": null,
    "post_id": "1393461115481927",
    "posted_at": "2025-09-15T16:01:59Z",
    "text": "Leave your limits at the surface. #JustDoIt",
    "reactions": 8200,
    "comments": 2644,
    "shares": 1157,
    "video_views": 496072
  }
]

First 2 of 4 rows from a real run — sample_output.json. Long values shortened here.

Built for Facebook

Handles what breaks naive Facebook scrapers

Intro-card items read by type

Each intro-card entry carries its own type (website, phone, address…), so a phone number is never mistaken for a company name and the website is taken out of Facebook's l.php redirect.

Exact engagement, not rounded labels

Post reactions, comments, shares and views are the exact numbers Facebook sends, checked against the displayed count on all 67 captured posts. For likes, --exact-likes reads the exact figure from the Ad Library.

Missing Pages are not blocks

A misspelt or removed Page answers HTTP 200 with "This content isn't available"; it is listed as not found, never retried and never reported as a block.

Private persons skipped

An address that leads to a personal profile is reported as not_a_page and nothing about it is written. Nothing about people who comment or react is collected — only the counts.

Everything built in

Scraping infrastructure included

The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.

CAPTCHA handling

Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.

Proxy rotation

Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.

Fingerprints

Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.

Scraping Browser API

Point --cdp-endpoint at a managed Chromium with its own exit country — no browser infrastructure to run yourself.

Honest run metadata

Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.

Diff two runs

diff_runs.py compares two complete Facebook snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with Facebook data

Lead generation

Turn a list of business Pages into websites, phone numbers, e-mails, addresses and opening hours.

Brand and competitor tracking

Follow follower counts and the engagement on each brand's latest posts, and diff runs to see what changed.

Contact-data hygiene

Re-check a Page list on a schedule; diff_runs.py --fail-on-change flags changed websites or phone numbers for cron or CI.

Ad-research joins

page_id is the same id Meta's Ad Library uses, so Page rows join directly with the companion facebook-ads-scraper.

Access & pricing

Free to run. Pay only for what the site requires.

Runs with no key, proxy or account

No account, cookies, key or proxy: measured live on 2026-10-06 from an ordinary residential IP, 10 Pages and their 30 posts in 50 seconds. A datacentre address has not been measured yet. Residential proxies help for long lists or a specific exit country, the 2Captcha Scraper API runs it with no browser on your machine, and the Scraping Browser API can be attached over CDP.

Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.

Good to know

  • Three posts per Page; no comments, reviews, photos tab or events.
  • Follower counts are rounded by Facebook; no exact follower count is available.
  • Groups, events and personal profiles are out of scope.

2scraper vs. hosted scraper APIs

2scraperTypical hosted API
CodeOpen source, MIT — read and patch itClosed
CostFree; optional services billed only when usedSubscription or per request / per result
Runs onYour machine, server or CIThe vendor's infrastructure
OutputJSON/CSV files + run metadataAPI responses
When the site changesFix it yourself or open an issue / PRWait for the vendor
FAQ

Facebook scraper FAQ

Do I need to log in to Facebook?

No. It reads what Facebook shows any logged-out visitor — the data a Page embeds in its own page.

How many posts can it get per Page?

Up to three (--posts 0-3). That is all a logged-out visitor gets; scrolling brought no more.

Why are follower counts round numbers?

Facebook shows logged-out visitors a rounded figure such as "39M followers"; followers_text keeps the original. --exact-likes gets the exact like count for Pages that have run ads.

Is there a captcha?

None in the live runs of 2026-10-05 and 2026-10-06 across all engines and the Scraper API. Detection stays on, so a real one would be reported as blocked rather than read as data.

What output does it produce?

JSON or CSV, one row per Page and per post, plus a .meta.json sidecar with the status and per-address results. A run that finds nothing never overwrites your previous file.

Is this allowed?

It reads only public Pages, logged out, and skips personal profiles. Facebook's robots.txt and Meta's terms restrict automated collection, so check your jurisdiction and purpose; follow the site's terms and the law.