Skip to main content

Scrape your own logged-in Facebook timeline by observing the GraphQL responses your own browser session makes. No token replay, no credential injection.

Project description

scraper-for-facebook

Scrape posts from a logged-in personal Facebook timeline by observing the GraphQL responses your own browser session makes — no token replay, no credential injection. You log in once by hand; the browser generates its own fb_dtsg/doc_id/lsd, and this tool just reads what comes back.

Read DISCLAIMER.md before using this. Automating a Facebook account violates its Terms of Service, publishing this tool exposes its maintainer, and scraping other people's posts can make you a data controller over their personal data. Use a dedicated/throwaway account, not your primary one.

This is not the first tool that does this. facebook-graphql-scraper captures GraphQL responses via Selenium + selenium-wire with credential-based login. This project's difference is incremental, not categorical: it reuses a persisted browser-login profile instead of injecting a username/password, and builds on scrapling's modern, actively-maintained fetch stack (Playwright-driven Chromium) instead of the largely-unmaintained selenium-wire.

Install

This package depends on scrapling[fetchers], which pins exact Playwright/patchright versions. Installing it into a shared environment alongside other Playwright-based tools can fail to resolve, or silently break one of them. Always install this tool in an isolated environment:

uv tool install scraper-for-facebook
# or
pipx install scraper-for-facebook

Do not pip install scraper-for-facebook into a general-purpose virtualenv you share with other projects.

After installing, provision the browser (into its own isolated cache — this never touches a browser install any other tool manages):

scrape-fb setup

Platform: macOS is the tested, first-class target (v1). Linux likely works for the fetch/parse/CLI layer but is untested against a live Facebook session. Windows is unsupported.

Quick start

# 1. One-time interactive login — opens a real browser window, you log in by hand.
scrape-fb login

# 2. Verify the session (and that the browser + capture pipeline actually work).
scrape-fb doctor

# 3. Fetch the last 30 posts from a profile you're logged in and able to view.
scrape-fb fetch https://www.facebook.com/some.profile --limit 30

Output defaults to a JSON file under this tool's own data directory (never your current directory or stdout — see --output below), because captured posts contain other people's personal data (§4 of the disclaimer) that shouldn't casually end up in a git-tracked path.

CLI reference

scrape-fb --version
scrape-fb login   [--profile NAME] [--profile-dir PATH]
scrape-fb status  [--profile NAME] [--profile-dir PATH] [--json]
scrape-fb setup
scrape-fb doctor  [--profile NAME] [--profile-dir PATH]
scrape-fb fetch <profile_url_or_username>
    --profile NAME            persisted login profile (default: "default")
    --limit N                 max posts
    --since YYYY-MM-DD        lower date bound (inclusive), best-effort (see "Limitations" below)
    --until YYYY-MM-DD        upper date bound (inclusive)
    --format json|ndjson      default: json
    --output PATH             default: a non-repo path under this tool's data directory
    --scroll-pause MIN,MAX    seconds between scrolls; MIN is clamped to >= 0.5 (see "Guardrails")
    --max-scrolls N           scroll budget (default 40)
    --profile-dir PATH        override where the login profile is stored
    --headed                  show the browser (debugging)
    --raw                     include the raw captured story node per post (debug; contains PII).
                              Redacted (scrubbed) by default — combine with --no-redact for the
                              truly raw, unscrubbed node (prints an on-screen PII warning).
    --no-redact               disable redaction of --raw output (only has an effect with --raw)
    -v / --verbose            extra diagnostics (redaction-scrubbed by default)

Exit codes

Code Meaning
0 Success — limit met, requested date window fully reached, or feed genuinely exhausted
1 Other/unexpected error
2 Login required or session expired — run scrape-fb login
3 Account checkpoint (Meta flagged the session) — log in again in a real browser
4 Zero posts returned — possibly parser drift against a Facebook response-shape change
5 Profile unavailable (memorialized, blocked, restricted, or nonexistent)
7 Partial: --since was requested but not confirmed reached within --max-scrolls

A one-line summary on stderr always states the post count, observed date range, and why the run stopped — so a partial --since run is never mistaken for a complete one.

Guardrails

  • The scroll-pause floor (--scroll-pause) is clamped to ≥ 0.5s and cannot be set to 0 — this is the one non-bypassable limit in this tool, and it exists both to reduce your account's checkpoint/ban risk and to keep this from being usable as a mass-scraping tool.
  • One target profile per invocation; no batch/multi-profile mode; no built-in scheduler or daemon loop.
  • Deeper --since runs scroll more, and more scrolling raises checkpoint risk. If you value the account, prefer shallow/recent fetches and --headed runs over deep history.

Limitations (v1)

  • Facebook only — no Instagram, no Threads (see roadmap).
  • Personal-profile timeline posts only — no groups, pages, or photo albums.
  • --since is best-effort: because this tool observes pagination rather than driving it, Facebook can stall further pagination before your requested date is reached. Exit code 7 and the stderr summary tell you when that happened.
  • Media is captured as URLs only (no file download) — and those URLs are signed, expire, and are scoped to your viewing session; treat them as sensitive.
  • No guaranteed deep-history reach; no incremental --since-last state (yet).

Python API

from scraper_for_facebook import FacebookScraper, Post, Media, LinkAttachment
from scraper_for_facebook.errors import (
    LoginRequiredError, SessionExpiredError, ChallengeError,
    ProfileUnavailableError, SessionClosedError,
)

# One-time interactive login (opens a headed browser; you log in by hand).
FacebookScraper(profile="default").login()

with FacebookScraper(profile="default") as fb:                 # headless reuse
    posts: list[Post] = fb.fetch_profile(
        "https://www.facebook.com/some.profile", limit=30, since="2026-01-01",
    )
    for post in fb.iter_profile("https://www.facebook.com/some.profile", limit=30):
        ...  # must be consumed inside the `with` block

FacebookScraper(profile="default").status()   # -> Status.LOGGED_IN | EXPIRED | CHECKPOINT

Contributing

uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
pre-commit install
pytest

Unit tests run against synthetic, PII-free fixtures (tests/fixtures/) — never against real captures. Live integration tests (tests/live/) are opt-in (SFB_LIVE_TESTS=1) and never run in CI. See the design doc in this repo's history for the full architecture and the reasoning behind each guardrail.

License

MIT — see LICENSE. The license covers the code; it does not cover what you do with the data you collect (see DISCLAIMER.md).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scraper_for_facebook-0.1.0.tar.gz (45.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scraper_for_facebook-0.1.0-py3-none-any.whl (38.5 kB view details)

Uploaded Python 3

File details

Details for the file scraper_for_facebook-0.1.0.tar.gz.

File metadata

  • Download URL: scraper_for_facebook-0.1.0.tar.gz
  • Upload date:
  • Size: 45.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for scraper_for_facebook-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6f79663faef55eeba73ffd2b7b475bb1b5c13d8ff35dec2b4e649e676614e88b
MD5 1a3a6b4612e2ed501469a8520b6fa8ca
BLAKE2b-256 1cb4e5f3f0aa48dbfbca06abfda050a31d0603fe9faf46f3635cb53b86379048

See more details on using hashes here.

Provenance

The following attestation bundles were made for scraper_for_facebook-0.1.0.tar.gz:

Publisher: publish.yml on tjdwls101010/Scraper-for-Facebook

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file scraper_for_facebook-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for scraper_for_facebook-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 992bfb48d69e78626a9798ffbb7cee6a377bc9ff39de2f6fe459a2c7089e1c97
MD5 9bcb8902f90ac7da4e0dfbc03cc636be
BLAKE2b-256 7b09178865c38de3cf6724a587b60c9b971dbbd814e5d07cb849bf9f8fae3f1b

See more details on using hashes here.

Provenance

The following attestation bundles were made for scraper_for_facebook-0.1.0-py3-none-any.whl:

Publisher: publish.yml on tjdwls101010/Scraper-for-Facebook

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page