Neural Sync Active
Data Collection from Social Media APIs
Registry Synced
Data Collection from Social Media APIs
2220 words
11 min read
Reading compass
Now · 🎯 Learning Objectives
Data Collection from Social Media APIs
🎯 Learning Objectives
- Understand how REST APIs work for social media data collection
- Implement OAuth authentication for accessing platform data
- Handle rate limits, pagination, and data formatting
- Evaluate ethical and legal considerations of data collection
- Apply sampling strategies for social media data
1. Social Media APIs: Overview
1.1 Intuition
Social media platforms like Twitter, Facebook, and Reddit hold vast amounts of public conversation data. But you can't just download everything — platforms provide APIs (Application Programming Interfaces) that let you request specific data programmatically. Think of an API like a restaurant menu: you can only order what's on the menu, you have to follow the restaurant's rules, and you can't take food from the kitchen directly.
APIs enforce rules about how much data you can collect, how often you can make requests, and what types of data are available. Understanding these rules is essential for any serious social media researcher.
1.2 What is a REST API?
REST (Representational State Transfer) is the most common API architecture. Key concepts:
| Concept | Meaning | Example |
|---|---|---|
| Endpoint | A specific URL that returns data | https://api.twitter.com/2/tweets |
| HTTP Method | What action to perform | GET (read), POST (create) |
| Parameters | Filters and options | ?query=AI&max_results=10 |
| Headers | Authentication and metadata | Authorization: Bearer TOKEN |
| Response | Data returned (usually JSON) | {"data": [{"id": "123", "text": "..."}]} |
How it works:
(Diagram)
1.3 Common Social Media APIs
| Platform | API Name | Key Endpoints | Rate Limits |
|---|---|---|---|
| Twitter/X | Twitter API v2 | /2/tweets, /2/users | 300 req/15 min (standard) |
| Reddit API | /r/{subreddit}/hot | 60 req/min | |
| Graph API | /{page-id}/posts | 200 req/hr (per user) | |
| Basic Display API | /me/media | 200 req/hr | |
| YouTube | Data API v3 | /videos, /search | 10,000 units/day |
2. Authentication: OAuth 2.0
2.1 Intuition
You can't just knock on a platform's door and ask for data — you need to prove who you are and what you're allowed to do. OAuth 2.0 is the standard protocol for this. It's like a hotel key card system: you check in at the front desk (get a token), and that token grants you access to specific areas (endpoints) for a limited time.
2.2 OAuth Flow
(Diagram)
2.3 Token Types
| Token | Lifetime | Purpose |
|---|---|---|
| Bearer Token | 1-2 hours | Sent with each request |
| Refresh Token | Days/months | Get new bearer token without re-login |
| API Key | Permanent | Identifies your application |
2.4 Python Example: Twitter API v2
pythonimport requests import json # Your credentials from developer portal bearer_token = "AAAAAAAAAAAAAAAAAAAA..." def create_headers(bearer_token): return {"Authorization": f"Bearer {bearer_token}"} def connect_to_endpoint(url, headers): response = requests.get(url, headers=headers) if response.status_code != 200: raise Exception(f"Request returned {response.status_code}: {response.text}") return response.json() # Search for recent tweets about "machine learning" url = "https://api.twitter.com/2/tweets/search/recent" params = { "query": "machine learning", "max_results": 10, "tweet.fields": "created_at,public_metrics" } headers = create_headers(bearer_token) response = requests.get(url, headers=headers, params=params) data = response.json() for tweet in data['data']: print(f"{tweet['created_at']}: {tweet['text']}")
Output (abbreviated):
pseudo2024-01-15T10:30:00Z: Just finished a great course on machine learning! 2024-01-15T10:28:00Z: Machine learning is transforming healthcare diagnostics...
3. Rate Limiting & Pagination
3.1 Rate Limiting
Platforms limit how many requests you can make to prevent abuse. Common strategies:
| Strategy | Description | Example |
|---|---|---|
| Fixed window | Max requests per time window | 300 requests per 15 minutes |
| Sliding window | Rolling time window | 60 requests per minute |
| Token bucket | Tokens replenish at a fixed rate | 10 tokens/s, max 100 |
Response headers to watch for:
pseudox-rate-limit-limit: 300 # Max requests allowed x-rate-limit-remaining: 284 # Requests remaining in window x-rate-limit-reset: 1643123456 # Unix timestamp when window resets
3.2 Handling Rate Limits
pythonimport time import requests def rate_limited_request(url, headers, params, max_retries=3): for attempt in range(max_retries): response = requests.get(url, headers=headers, params=params) if response.status_code == 429: # Too Many Requests reset_time = int(response.headers.get('x-rate-limit-reset', 0)) wait_time = max(reset_time - time.time(), 0) + 1 print(f"Rate limited. Waiting {wait_time} seconds...") time.sleep(wait_time) continue if response.status_code == 200: remaining = response.headers.get('x-rate-limit-remaining', '?') print(f"Requests remaining: {remaining}") return response.json() print(f"Error {response.status_code}: {response.text}") return None print("Max retries exceeded") return None
3.3 Pagination
APIs rarely return all results at once — they paginate. Common pagination methods:
| Method | How it works | Example Parameter |
|---|---|---|
| Cursor-based | Next page token | next_token=abc123 |
| Page-based | Page number | page=2 |
| Offset-based | Skip N items | offset=100 |
Cursor-based pagination loop:
pythondef collect_all_tweets(query, max_tweets=500): all_tweets = [] next_token = None while len(all_tweets) < max_tweets: params = { "query": query, "max_results": 100, "tweet.fields": "created_at" } if next_token: params["next_token"] = next_token response = requests.get(url, headers=headers, params=params) data = response.json() if 'data' in data: all_tweets.extend(data['data']) print(f"Collected {len(all_tweets)} tweets so far") # Check for next page if 'meta' in data and 'next_token' in data['meta']: next_token = data['meta']['next_token'] else: break return all_tweets[:max_tweets]
4. Data Formats & Processing
4.1 JSON Structure
Social media APIs typically return JSON. Here's what a tweet object looks like:
json{ "data": { "id": "1234567890", "text": "Machine learning is amazing! #AI", "created_at": "2024-01-15T10:30:00.000Z", "author_id": "98765", "public_metrics": { "retweet_count": 15, "reply_count": 3, "like_count": 142, "quote_count": 2 }, "entities": { "hashtags": [{"tag": "AI"}], "mentions": [{"username": "ml_expert"}] } }, "includes": { "users": [ { "id": "98765", "name": "ML Enthusiast", "username": "ml_fan", "public_metrics": { "followers_count": 2500, "following_count": 180, "tweet_count": 3400 } } ] } }
4.2 Converting to Structured Data
pythonimport pandas as pd def tweets_to_dataframe(tweets_data): """Convert raw API response to a pandas DataFrame.""" rows = [] for tweet in tweets_data.get('data', []): row = { 'tweet_id': tweet['id'], 'text': tweet['text'], 'created_at': tweet['created_at'], 'retweets': tweet['public_metrics']['retweet_count'], 'likes': tweet['public_metrics']['like_count'], 'replies': tweet['public_metrics']['reply_count'], } rows.append(row) df = pd.DataFrame(rows) df['created_at'] = pd.to_datetime(df['created_at']) return df
5. Sampling Strategies
5.1 Why Sample?
Social media generates massive data — Twitter alone produces 500M+ tweets daily. You can't collect everything. Sampling strategies help you get representative data.
5.2 Sampling Methods
| Method | Description | When to Use |
|---|---|---|
| Random sampling | Random selection of posts/users | General population studies |
| Stratified sampling | Divide by categories, sample each | Comparing subgroups |
| Snowball sampling | Start with seeds, follow connections | Network analysis |
| Time-based sampling | Collect during specific periods | Event analysis |
| Keyword filtering | Collect posts matching keywords | Topic-specific studies |
5.3 Worked Example: Stratified Sampling
Suppose you want to compare political discourse across 5 countries. You decide to collect 2000 tweets per country.
pythoncountries = ['US', 'UK', 'IN', 'BR', 'JP'] tweets_per_country = 2000 collected = {} for country in countries: query = f"politics lang:en place_country:{country}" collected[country] = collect_all_tweets(query, tweets_per_country) print(f"Collected {len(collected[country])} tweets from {country}")
Tracing Table:
| Step | Action | Country | Tweets Collected | Cumulative |
|---|---|---|---|---|
| 1 | Query US politics | US | 2000 | 2000 |
| 2 | Query UK politics | UK | 2000 | 4000 |
| 3 | Query IN politics | IN | 2000 | 6000 |
| 4 | Query BR politics | BR | 2000 | 8000 |
| 5 | Query JP politics | JP | 2000 | 10000 |
6. Ethical & Legal Considerations
6.1 Platform Terms of Service
Every platform has rules. Violating them can get your app banned or worse — legal action.
| Rule | Why It Exists |
|---|---|
| No data resale | Protects user privacy |
| Rate limits | Prevents server overload |
| User consent | Required for private data |
| Attribution | Give credit to platform |
| No scraping (some platforms) | Explicit prohibition |
6.2 GDPR & Data Privacy
If you're collecting data from EU users, GDPR applies:
| Requirement | What You Must Do |
|---|---|
| Lawful basis | Have a legitimate reason |
| Consent | Inform users and get consent |
| Data minimization | Collect only what you need |
| Right to deletion | Delete user data on request |
| Anonymization | Remove personally identifiable info |
6.3 Ethical Guidelines
(Diagram)
Key ethical principles:
- Minimize harm: Don't expose sensitive information
- Be transparent: Disclose data collection methods
- Respect privacy: Anonymize, aggregate where possible
- Get consent: For non-public data
- Follow platform rules: Terms of service matter
7. Common Pitfalls
Pitfall 1: Ignoring Rate Limits
The mistake: Making too many requests too quickly, getting permanently banned.
Why students make it: The first few requests work fine, so they assume there's no limit. Then suddenly everything breaks.
How to catch it: Always log response headers. Watch for
x-rate-limit-remaining approaching 0.
Correct approach: Implement exponential backoff: wait 1s after first 429, 2s after second, 4s after third.Pitfall 2: Storing API Keys in Code
The mistake: Hardcoding bearer tokens in Python files, then committing to GitHub.
Why students make it: It's the quickest way to get something working.
How to catch it: Before any git commit, check for suspicious strings. Use
git-secrets or similar tools.
Correct approach: Use environment variables or a .env file (never committed).pythonimport os from dotenv import load_dotenv load_dotenv() bearer_token = os.getenv("TWITTER_BEARER_TOKEN")
Pitfall 3: Not Handling Pagination
The mistake: Only collecting the first page of results (e.g., 10 tweets instead of 1000+).
Why students make it: The first request works and returns data. It's easy to forget that more data exists.
How to catch it: Check if the response has pagination tokens. Most APIs include
next_token or next_page_url in responses.
Correct approach: Always loop through pagination until no more pages or you have enough data.8. Key Concepts Reference
| Concept | Definition | Why It Matters |
|---|---|---|
| REST API | Web API using HTTP methods | Standard for most social media platforms |
| OAuth 2.0 | Token-based authentication | Secure, delegated access |
| Bearer Token | Access credential sent in headers | Proves authorization |
| Rate Limit | Max requests per time window | Prevents abuse |
| Pagination | Splitting results into pages | Handles large datasets |
| Cursor | Pointer to next page of results | Efficient pagination |
| JSON | JavaScript Object Notation | Standard data format |
| GDPR | EU data protection regulation | Legal compliance requirement |
9. 📝 Practice Questions
Q1: You make 300 API requests in 10 minutes. Rate limit is 300 per 15 minutes. How long must you wait before the next request?Answer: The window resets 15 minutes after the first request in the window. Since you made 300 requests in 10 minutes, you've exhausted your quota. You need to wait until the 15-minute window from your first request expires. If your first request was at t=0, you can request again at t=15 minutes (5 more minutes of waiting). Q2: What's the difference between a bearer token and a refresh token?Answer: A bearer token is short-lived (1-2 hours) and is sent with each API request to authenticate. A refresh token is long-lived (days to months) and is used to obtain new bearer tokens without requiring the user to re-authenticate. Refresh tokens are stored securely on the server side and never sent with API requests. Q3: An API returns paginated results withnext_token. The first page contains 100 results. How many API calls are needed to collect 500 results?Answer: Each call returns up to 100 results (max_results=100). To get 500 results: 500/100 = 5 calls. Call 1 gets page 1 with next_token; call 2 uses that token for page 2; and so on until call 5 completes. Total: 5 API calls. Q4: Why should you use environment variables instead of hardcoding API keys?Answer: Hardcoding API keys in source code exposes them to anyone with access to the codebase. If committed to version control, they become permanently visible. Environment variables keep secrets out of code, can be set per-deployment (dev/staging/production), and reduce the risk of accidental exposure. Q5: A platform returns HTTP 429 after 50 requests. Your rate limit was supposed to be 300. What might be wrong?Answer: Several possibilities: (1) The rate limit might be per-endpoint, not global — you might be hitting a different endpoint than you registered. (2) Your app might be in a lower tier (e.g., Essential vs. Academic). (3) The rate limit might reset on a different schedule than you assumed (e.g., per minute, not per 15 minutes). (4) You might have accidentally triggered a separate rate limit (e.g., per-user instead of per-app). Check the response headers forx-rate-limit-limitto see the actual limit. Q6: What is the difference between cursor-based and offset-based pagination?Answer: Cursor-based pagination uses a token pointing to a specific item, guaranteeing no duplicates even if new data is added (stable cursor). Offset-based pagination skips N items, which can cause duplicates or missed items if data changes between pages. Cursor-based is preferred for real-time data (like social media feeds), while offset-based is simpler for static datasets. Q7: Under GDPR, what must you do if a user requests deletion of their data from your research dataset?Answer: You must (1) identify all records containing their data across your systems, (2) delete those records or anonymize them so the user is no longer identifiable, (3) confirm deletion to the user within the required timeframe (usually 30 days), (4) ensure no backups retain the identifiable data. You should have a process for handling such requests before starting data collection. Q8: You're collecting tweets about a sensitive health topic. What ethical considerations apply?Answer: (1) Anonymize user handles and IDs before analysis/storage. (2) Consider whether users expected their tweets to be public for this purpose. (3) Aggregate findings rather than quoting individual tweets. (4) Store data securely with access controls. (5) Have an IRB/ethics review if possible. (6) Be prepared for potential media attention or platform scrutiny. Q9: An API returns JSON withdataandincludesfields. What areincludesfor?Answer: Theincludesfield contains expanded objects referenced in thedatafield. For example, a tweet indatamight haveauthor_id: "123", and the actual user object with name, username, and metrics is inincludes.users. This is called "side-loading" or "embedding" and reduces the number of API calls needed to get related data. It's more efficient than making separate calls for each user. Q10: Compare snowball sampling with stratified sampling for social media research.Answer: Snowball sampling starts with initial "seed" users and follows their connections/mentions, making it ideal for network analysis and hard-to-reach populations. Stratified sampling divides the population into relevant categories (by country, language, etc.) and samples each proportionally, making it better for comparative studies. Snowball can introduce selection bias (connected users are similar), while stratified requires knowing the categories in advance.
10. 🔗 Cross-References
- Week 1 - SNA Basics: Graph metrics from collected data
- Week 3 - Text Analysis: Processing collected text data
- Week 4 - Cyber Crime: API misuse patterns
- BSCS4024 (Computer Networks): HTTP, REST API fundamentals Join Discord PreviousSNA BasicsNextText Analysis