⚡ Quick start
pip install facebook-page-info-scraper
from facebook_page_info_scraper import scrape_page
scrape_page("https://www.facebook.com/examplepage")
That is everything — both engines install and are ready to use.
🚀 Two engines, one result
Pick whichever suits the job. Both take the same URLs, return the same fields, and run the same extraction. They differ only in how the page is requested.
| 🌐 HTTP | 🎭 Browser | |
|---|---|---|
| requests with | requests | Chromium via Playwright |
| speed | ~1.4 s per page | ~3 s per page |
| memory | negligible | ~60–80 MB per page |
| runs JavaScript | — | ✅ |
| reads network traffic | — | ✅ captures GraphQL responses |
| suits | large lists, minimal setup | pages whose data never reaches the raw HTML |
from facebook_page_info_scraper import scrape_pages # 🌐 HTTP
from facebook_page_info_scraper.spider import run # 🎭 Browser
scrape_pages(urls, threads=16)
run(urls, threads=8)
The browser engine downloads Chromium (~150 MB) the first time it runs — pip cannot fetch browser binaries, so it happens on first use. One time only.
📖 What it does
Give it a Facebook page URL, get back the page's public details: name, category, email, phone, website, address, likes, ratings, opening status.
🎯 What it solves
Facebook page data used to require driving a real browser — slow, heavy, and it broke every time Facebook changed its CSS. Both engines here read Facebook's own page payload instead, so neither depends on how the page looks.
🌐 Usage — HTTP
from facebook_page_info_scraper import scrape_page, scrape_pages
page = scrape_page("https://www.facebook.com/examplepage")
pages = scrape_pages(urls, threads=16)
print(page["email"]) # hello@example.com
print(page["page_likes"]) # 12,480
python scrape.py urls.txt # -> pages.json
python scrape.py urls.txt --threads 24
python scrape.py urls.txt --out output.json
scrape_page(url, want_about=True, timeout=25)
scrape_pages(urls, threads=16, want_about=True, timeout=25)
want_about=False reads only the page header — faster, but no email or phone.
🎭 Usage — Browser
from facebook_page_info_scraper.spider import run
run(urls, threads=8) # -> pages_browser.jsonl
run(urls, threads=8, headless=False) # watch it work
python -m facebook_page_info_scraper.spider urls.txt --threads 8
python -m facebook_page_info_scraper.spider urls.txt --headed
python -m facebook_page_info_scraper.spider https://www.facebook.com/examplepage
run(urls,
threads=8, # pages rendered at once, no cap
out="pages_browser.jsonl",
settle_ms=2000, # pause after load before reading
headless=True)
This engine works in batches — pass a list of URLs rather than one at a time.
📥 Input
Any Facebook page URL. These all work with either engine:
https://www.facebook.com/examplepage
https://facebook.com/examplepage (no www)
https://www.facebook.com/examplepage/ (trailing slash)
https://www.facebook.com/pages/Example-Page/100000000000000
https://www.facebook.com/profile.php?id=100000000000000
http://sv-se.facebook.com/pages/Example-Page/100000000000000 (locale subdomain)
📤 Output
Identical from either engine.
{
"page_name": "Example Store",
"page_id": "100000000000000",
"page_category": "Bakery",
"email": "hello@example.com",
"phone_number": "+33 1 23 45 67 89",
"page_website": "https://example.com",
"address": "1 Example Street\n12345 Sampletown",
"page_likes": "12,480",
"talking_about": "215",
"were_here": "33",
"recommend_percent": "94",
"page_review_number": "18",
"open_status": "Closed now",
"price_range": "Price Range - $",
"bio": "Example Store. 12,480 likes ...",
"image": "https://scontent.xx.fbcdn.net/...",
"canonical": "https://www.facebook.com/examplepage",
"locale": "en_US",
"ok": True
}
Fields
| field | type | description |
|---|---|---|
page_name |
str |
Page name |
page_id |
str |
Numeric Facebook page ID |
page_category |
str | None |
e.g. Bakery, Clothing Store |
email |
str | list | None |
Contact email(s) |
phone_number |
str | list | None |
Contact phone(s) |
page_website |
str | list | None |
External website(s) |
address |
str | None |
Full street address |
page_likes |
str | None |
Like count, e.g. 12,480 |
page_followers |
str | None |
Follower count |
talking_about |
str | None |
"talking about this" count |
were_here |
str | None |
Check-in count |
recommend_percent |
str | None |
e.g. 74 from "74% recommend" |
page_rate |
str | None |
Star rating, where shown |
page_review_number |
str | None |
Review count |
open_status |
str | None |
Closed now, Always open, … |
price_range |
str | None |
e.g. Price Range · $ |
bio |
str | None |
Page description |
image |
str | None |
Profile picture URL |
canonical |
str |
Canonical page URL |
locale |
str |
Language Facebook served |
ok |
bool |
Whether the scrape succeeded |
error |
str |
Present only when ok is False |
Always check ok:
page = scrape_page(url)
print(page.get("page_name")if page.get("ok") else page.get("error"))
One thing to know.
phone_numberandpage_websiteare a string when the page lists one, and a list when it lists several."email": "hello@example.com" # one "email": ["sales@example.com", "press@example.com"] # several "email": None # none def as_list(v): return [] if v is None else (v if isinstance(v, list) else [v])
🩺 Check your run
One call tells you how a batch went. Works on records from either engine.
from facebook_page_info_scraper import scrape_pages, summarise
records = scrape_pages(urls, threads=16)
summarise(records)
{
"total": 213, # records in
"ok": 211, # scraped successfully
"failed": 2,
"with_about": 164, # found the About panel
"with_email": 150,
"with_phone": 115,
"with_website": 161,
"wrong_locale": 0, # pages Facebook served in another language
"avg_seconds": 1.44,
"avg_kb": 533 # bytes actually read, not page size
}
Field counts are measured against ok, not total — dead URLs never drag
your extraction numbers down. That makes the two problems easy to tell apart:
| what moved | what it means |
|---|---|
ok dropped |
fetching — blocks, rate limits, bad URLs |
ok steady, with_email dropped |
extraction — Facebook changed something |
wrong_locale above 0 |
those pages came back in another language |
Handy as a guard in scheduled jobs:
stats = summarise(records)
if stats["with_email"] / stats["ok"] < 0.60:
raise SystemExit("email extraction dropped — check for changes")
📊 Speed
Measured on the same 183-page list, same machine.
| 🐌 old (Selenium) | 🌐 HTTP | 🎭 Browser | |
|---|---|---|---|
| per page | 15–20 s | ~1.4 s | ~3 s |
| pages in parallel | ❌ | ✅ 16+ | ✅ you choose |
| 200 pages | ~50 min | under 1 min | ~2 min |
| memory | ~60 MB/page | negligible | ~60–80 MB/page |
| needs Chrome installed | ✅ | ❌ | downloads its own |
Both engines beat the old Selenium version by a wide margin — HTTP by roughly 50×, the browser engine by about 6× while still running JavaScript.
🔮 Roadmap
An AI extraction layer is planned for the tail that deterministic rules cannot reach — unlabelled free-text rows in languages whose formatting conventions vary, plus self-healing selectors that repair themselves when Facebook changes shape. It will sit behind the current parsers, not in front of them: rules first, model only where rules come up empty.
⬆️ Upgrading from 1.x
The old Selenium class still works:
pip install facebook-page-info-scraper[selenium]
from facebook_page_info_scraper import FacebookPageInfoScraper
FacebookPageInfoScraper(url).get_page_info()
Either new engine is a recommended replacement — same idea, much faster.
Two output differences:
page_rateandpage_review_numberused to be swapped. They are correct now.locationwas a country name; the newaddressis the full street address.
🤝 Contributing
Contributions are welcome. If you find an issue or have a suggestion, please open an issue or submit a pull request on GitHub.
📝 Notes
- Only public pages. Nothing behind a login.
- Be reasonable with
threads— this hits Facebook from your IP. - Scraping Facebook is against their Terms of Service. Use accordingly.
License
MIT — see LICENSE.txt.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file facebook_page_info_scraper-2.0.0.tar.gz.
File metadata
- Download URL: facebook_page_info_scraper-2.0.0.tar.gz
- Upload date:
- Size: 30.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63bbf31f143a3e5739fe41c55376e85bb60a28f1a7b81b4451119cd041fe1ea6
|
|
| MD5 |
53ac2ef1405522261688a9611b3d1175
|
|
| BLAKE2b-256 |
089f97908ab8311744295b77187f4a8d1f3097f735f20000120ca716009b722c
|
Provenance
The following attestation bundles were made for facebook_page_info_scraper-2.0.0.tar.gz:
Publisher:
publish-to-pypi.yml on wael-sudo2/facebook-page-info-scraper
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
facebook_page_info_scraper-2.0.0.tar.gz -
Subject digest:
63bbf31f143a3e5739fe41c55376e85bb60a28f1a7b81b4451119cd041fe1ea6 - Sigstore transparency entry: 2332000704
- Sigstore integration time:
-
Permalink:
wael-sudo2/facebook-page-info-scraper@75f648143c6825365f54445d127efff14b03d8f2 -
Branch / Tag:
refs/tags/v2.0.0 - Owner: https://github.com/wael-sudo2
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@75f648143c6825365f54445d127efff14b03d8f2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file facebook_page_info_scraper-2.0.0-py3-none-any.whl.
File metadata
- Download URL: facebook_page_info_scraper-2.0.0-py3-none-any.whl
- Upload date:
- Size: 29.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c550eb01f3a0d0efc523d2b61ab7a01647b12d61d44ff75ebc082ae29cd1585
|
|
| MD5 |
0fa22b9238ac2235d42c0157e4f0c31f
|
|
| BLAKE2b-256 |
734359213809092e5bc70a972f0e46b278ed8eabb048190b6f05257e9eb473a2
|
Provenance
The following attestation bundles were made for facebook_page_info_scraper-2.0.0-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on wael-sudo2/facebook-page-info-scraper
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
facebook_page_info_scraper-2.0.0-py3-none-any.whl -
Subject digest:
5c550eb01f3a0d0efc523d2b61ab7a01647b12d61d44ff75ebc082ae29cd1585 - Sigstore transparency entry: 2332000904
- Sigstore integration time:
-
Permalink:
wael-sudo2/facebook-page-info-scraper@75f648143c6825365f54445d127efff14b03d8f2 -
Branch / Tag:
refs/tags/v2.0.0 - Owner: https://github.com/wael-sudo2
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@75f648143c6825365f54445d127efff14b03d8f2 -
Trigger Event:
push
-
Statement type: