Building a Lightweight Financial News Sentiment Analyzer with Python and SerpApi
Tags: python api finance sentimentanalysis beginners
Description:
Learn how to build a simple financial news sentiment analyzer in Python using SerpApi. The project retrieves recent news for assets such as Apple, Tesla, and Bitcoin, then classifies the language as bullish, bearish, or neutral using a lightweight lexicon-based approach.
## Introduction
Financial markets move quickly.
Every day, investors are exposed to thousands of headlines discussing earnings, company announcements, market movements, upgrades, downgrades, risks, and economic events.
The problem is not necessarily finding financial news.
The problem is processing large amounts of news quickly.
In this project, I built a small Python-based financial sentiment engine that retrieves recent financial news and automatically classifies each article as:
- 🟢 Bullish
- 🔴 Bearish
- 🟡 Neutral
The project uses SerpApi to retrieve Google News results and Python to perform the sentiment classification.
if you dont have SerpApi account please visit https://serpapi.com to grap one
The goal is not to build a magical stock-price predictor.
Instead, this project demonstrates how a developer can combine:
Python
↓
SerpApi
↓
Google News
↓
Financial headlines
↓
Text processing
↓
Sentiment scoring
↓
Bullish / Bearish / Neutral
This is a lightweight foundation that can later be extended into a much more advanced financial research system.
What We Are Building
The application accepts an asset such as:
Apple
Tesla
Bitcoin
It then searches for recent financial news related to that asset.
For example:
Apple financial market news
The returned articles are processed and the program extracts:
Title
Snippet
Source
The title and snippet are combined and passed through a simple sentiment engine.
A simplified example might look like:
Headline:
Apple reports record growth in quarterly revenue
Detected terms:
record
growth
Result:
BULLISH 🟢
Another headline might contain:
Apple shares fall after weak earnings outlook
Detected terms:
fall
Result:
BEARISH 🔴
And an article without enough bullish or bearish language might produce:
NEUTRAL 🟡
Project Architecture
The project is intentionally simple.
┌─────────────────────┐
│ Python App │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ SerpApi │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Google News │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ News Headlines │
│ + Snippets │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Sentiment Engine │
└──────────┬──────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
Bullish Neutral Bearish
🟢 🟡 🔴
The current implementation is contained in a single Python file, setiment_engine.py. It defines a FinancialSentimentEngine class, bullish and bearish token sets, a news retrieval method, a sentiment analyzer, and a pipeline runner.
Requirements
You need:
- Python 3
- A SerpApi account/API key
- Internet access
- A terminal
- The
serpapiPython package
The official SerpApi Python package can be installed with:
pip install serpapi
The current SerpApi Python client is based around serpapi.Client, which is the approach used in this project.
Step 1: Create the Project
Create a project directory:
mkdir financial-sentiment
cd financial-sentiment
Create a virtual environment:
python -m venv .venv
Activate it on Windows:
.venv\Scripts\activate
You should see something similar to:
(.venv) C:\Users\YourName\financial-sentiment>
Step 2: Install SerpApi
Upgrade pip:
python -m pip install --upgrade pip
Then install the official SerpApi package:
python -m pip install serpapi
Verify the installation:
python -m pip show serpapi
The important detail here is that the modern client uses:
import serpapi
client = serpapi.Client(api_key="...")
rather than the older:
from serpapi import GoogleSearch
This difference is important because using the wrong interface can result in:
ImportError: cannot import name 'GoogleSearch' from 'serpapi'
The official SerpApi Python repository identifies serpapi.Client as the primary interface and recommends the serpapi package.
Step 3: Configure the API Key
Do not hard-code your API key into your Python source.
Instead, store it in an environment variable.
On Windows CMD:
set SERPAPI_API_KEY=YOUR_API_KEY
For a persistent Windows environment variable:
setx SERPAPI_API_KEY "YOUR_API_KEY"
After using setx, open a new terminal.
You can check whether the variable exists without printing the secret:
if defined SERPAPI_API_KEY (echo API key is configured) else (echo API key is missing)
A good result is:
API key is configured
Environment variables are also the approach recommended by the official SerpApi Python package documentation for keeping API keys separate from application code.
Step 4: The Python Application
Here is the complete implementation.
import os
import re
import sys
import time
import serpapi
class FinancialSentimentEngine:
"""Fetch financial news and classify its sentiment."""
BULLISH_TOKENS = {
"growth",
"surge",
"gain",
"profit",
"bullish",
"higher",
"record",
"success",
"buy",
"upgrade",
}
BEARISH_TOKENS = {
"drop",
"fall",
"loss",
"crash",
"bearish",
"lower",
"risk",
"decline",
"sell",
"downgrade",
}
def __init__(self, api_key: str):
if not api_key:
raise ValueError("Missing SERPAPI_API_KEY.")
self.client = serpapi.Client(api_key=api_key)
def fetch_market_news(self, ticker: str) -> list:
"""Fetch recent financial news using SerpApi Google News."""
print(
f"[Engine] Querying financial news for ticker: {ticker}..."
)
search_parameters = {
"engine": "google",
"q": f"{ticker} financial market news",
"tbm": "nws",
"tbs": "qdr:w",
}
try:
dictionary_results = self.client.search(search_parameters)
if "error" in dictionary_results:
print(
f"[Error] SerpApi returned an error: "
f"{dictionary_results['error']}"
)
return []
return dictionary_results.get("news_results", [])
except Exception as exc:
print(f"[Error] Network query failed: {exc}")
return []
@classmethod
def analyze_text_sentiment(cls, text: str) -> str:
"""Perform lightweight lexicon-based sentiment classification."""
normalized_text = text.lower()
bull_score = sum(
1
for token in cls.BULLISH_TOKENS
if re.search(
rf"\b{re.escape(token)}\b",
normalized_text
)
)
bear_score = sum(
1
for token in cls.BEARISH_TOKENS
if re.search(
rf"\b{re.escape(token)}\b",
normalized_text
)
)
if bull_score > bear_score:
return "BULLISH 🟢"
if bear_score > bull_score:
return "BEARISH 🔴"
return "NEUTRAL 🟡"
def run_pipeline(self, ticker: str) -> None:
"""Fetch news and classify the first five articles."""
news_articles = self.fetch_market_news(ticker)
if not news_articles:
print(
f"[Warning] No news found for {ticker} "
"within the selected time window."
)
return
print(f"\n=== SENTIMENT REPORT: {ticker.upper()} ===")
for index, article in enumerate(
news_articles[:5],
start=1
):
title = article.get("title", "No title")
snippet = article.get("snippet", "")
source = article.get(
"source",
"Unknown source"
)
if isinstance(source, dict):
source = source.get(
"name",
"Unknown source"
)
sentiment = self.analyze_text_sentiment(
f"{title} {snippet}"
)
print(f"\n[{index}] Source: {source}")
print(f" Headline: {title}")
print(f" Sentiment: {sentiment}")
def main():
api_key = os.getenv("SERPAPI_API_KEY")
if not api_key:
print(
"[Abort] Set the SERPAPI_API_KEY "
"environment variable first."
)
sys.exit(1)
engine = FinancialSentimentEngine(api_key)
assets = [
"Apple",
"Tesla",
"Bitcoin",
]
for index, asset in enumerate(assets):
engine.run_pipeline(asset)
print("-" * 60)
if index < len(assets) - 1:
time.sleep(1)
if __name__ == "__main__":
main()
This implementation follows the structure of the uploaded source while correcting the SerpApi client usage and indentation problems that caused the earlier failure.
Step 5: Understanding the Sentiment Engine
The heart of the project is the sentiment classifier.
We define two groups of words.
Bullish words
BULLISH_TOKENS = {
"growth",
"surge",
"gain",
"profit",
"bullish",
"higher",
"record",
"success",
"buy",
"upgrade",
}
These terms generally represent positive market language.
Bearish words
BEARISH_TOKENS = {
"drop",
"fall",
"loss",
"crash",
"bearish",
"lower",
"risk",
"decline",
"sell",
"downgrade",
}
These represent negative market language.
The project then normalizes the article text:
normalized_text = text.lower()
This prevents capitalization from affecting the matching.
For example:
Growth
growth
GROWTH
all become:
growth
Why Use Regular Expressions?
Instead of checking whether a token simply exists somewhere inside the text, the implementation uses word boundaries:
re.search(
rf"\b{re.escape(token)}\b",
normalized_text
)
This helps reduce accidental partial matches.
For example, we want:
risk
to match the word:
risk
rather than accidentally matching unrelated words that merely contain the same character sequence.
Calculating the Scores
The bullish score is calculated with:
bull_score = sum(
1
for token in cls.BULLISH_TOKENS
if re.search(
rf"\b{re.escape(token)}\b",
normalized_text
)
)
The bearish score works the same way:
bear_score = sum(
1
for token in cls.BEARISH_TOKENS
if re.search(
rf"\b{re.escape(token)}\b",
normalized_text
)
)
The final decision is simple:
bullish score > bearish score
↓
BULLISH
bearish score > bullish score
↓
BEARISH
scores are equal
↓
NEUTRAL
The uploaded implementation follows exactly this three-way decision structure.
Step 6: Retrieving Financial News
The application creates a SerpApi search request:
search_parameters = {
"engine": "google",
"q": f"{ticker} financial market news",
"tbm": "nws",
"tbs": "qdr:w",
}
The important pieces are:
engine
"engine": "google"
This specifies the Google search engine interface.
q
"q": f"{ticker} financial market news"
For:
Apple
the query becomes:
Apple financial market news
tbm
"tbm": "nws"
This is used to target Google News results.
tbs
"tbs": "qdr:w"
This asks for a recent time window of approximately one week.
SerpApi's client accepts Google search parameters through client.search(...), with results returned in a dictionary-like object.
Step 7: Extracting Articles
The application retrieves:
news_articles = self.fetch_market_news(ticker)
Then it processes only the first five results:
for index, article in enumerate(
news_articles[:5],
start=1
):
For every article, it extracts:
title = article.get("title", "No title")
snippet = article.get("snippet", "")
It also handles the source field because the returned source data can be represented as a dictionary:
source = article.get(
"source",
"Unknown source"
)
if isinstance(source, dict):
source = source.get(
"name",
"Unknown source"
)
Finally, the title and snippet are combined:
sentiment = self.analyze_text_sentiment(
f"{title} {snippet}"
)
This gives the sentiment engine more context than the title alone.
Step 8: Running the Pipeline
The main() function reads the API key:
api_key = os.getenv("SERPAPI_API_KEY")
Then it creates the engine:
engine = FinancialSentimentEngine(api_key)
The demonstration analyzes:
assets = [
"Apple",
"Tesla",
"Bitcoin",
]
The pipeline runs once for each asset.
Step 9: Run the Program
Save the program as:
setiment_engine.py
Then run:
python setiment_engine.py
You should see output similar to:
[Engine] Querying financial news for ticker: Apple...
=== SENTIMENT REPORT: APPLE ===
[1] Source: Example News
Headline: Apple reports strong revenue growth
Sentiment: BULLISH 🟢
[2] Source: Example News
Headline: Apple faces concerns about lower demand
Sentiment: BEARISH 🔴
------------------------------------------------------------
[Engine] Querying financial news for ticker: Tesla...
=== SENTIMENT REPORT: TESLA ===
[1] Source: Example News
Headline: Tesla announces higher production
Sentiment: BULLISH 🟢
The exact articles and classifications will change because the program retrieves current search results at runtime.
What Makes This Project Useful?
At first glance, counting words might look too simple.
And it is simple.
But simple systems can be useful as a starting point.
This project demonstrates several important software engineering concepts:
API integration
The application communicates with an external service and consumes structured search results.
Environment-based configuration
The API credential is separated from the source code.
Object-oriented design
The financial engine is encapsulated in:
class FinancialSentimentEngine:
Error handling
The application catches failed requests and handles missing search results.
Text processing
The application normalizes text and analyzes lexical features.
Pipeline architecture
The complete process is divided into stages:
Input
↓
Search
↓
Extraction
↓
Normalization
↓
Scoring
↓
Classification
↓
Output
Important Limitation: This Is Not a Trading Signal
This is probably the most important part of the project.
The program is not predicting the future price of a stock or cryptocurrency.
It is also not a professional quantitative trading model.
It does not account for:
- Market structure
- Price action
- Trading volume
- Macroeconomic data
- Earnings estimates
- Technical indicators
- Institutional positioning
- Options activity
- News credibility
- Context
- Negation
- Sarcasm
- Historical correlations
For example, consider:
Apple avoids a major revenue decline despite weaker demand.
A simple lexical system may see:
decline
weaker
and classify the article negatively, even though the overall meaning could be more nuanced.
That is one of the fundamental weaknesses of keyword-based sentiment analysis.
The system should therefore be viewed as a news-research utility, not as an automated investment decision maker.
How I Would Improve This Project
This project provides a foundation for something much more advanced.
The next version could introduce a proper NLP model instead of manually defined keywords.
For example:
Financial News
│
▼
Text Cleaning
│
▼
NLP Model / LLM
│
▼
Sentiment Score
│
┌───────────┼───────────┐
▼ ▼ ▼
Bullish Neutral Bearish
The output could become numerical:
{
"asset": "Apple",
"sentiment": "bullish",
"score": 0.82
}
instead of simply:
BULLISH 🟢
Possible Future Features
The project could eventually become a complete financial research platform.
For example:
Financial Research Platform
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
News API Market Data Social Data
│ │ │
└───────────────────┼───────────────────┘
▼
NLP / AI Analysis
│
┌───────────────┼───────────────┐
▼ ▼ ▼
Sentiment Trends Events
│ │ │
└───────────────┼───────────────┘
▼
Research Dashboard
Possible additions include:
- Historical sentiment storage
- PostgreSQL
- REST APIs
- FastAPI
- Redis caching
- Background workers
- Market price APIs
- Technical indicators
- Sentiment charts
- News deduplication
- Source credibility scoring
- LLM-based financial summarization
- Portfolio monitoring
- Web dashboards
- Alerts
That would transform this from a small command-line experiment into a much more complete financial intelligence platform.
Security Notes
Never put your real API key inside:
api_key = "my-real-secret-key"
Do not commit API keys to GitHub.
Do not put them in screenshots.
Do not publish them in DEV.to articles.
Use:
os.getenv("SERPAPI_API_KEY")
and configure the key through your environment.
If a key is accidentally published, treat it as compromised and rotate it.
A Note About the Name
The file in this project is currently called:
setiment_engine.py
The intended spelling is probably:
sentiment_engine.py
The typo does not affect Python functionality, but I recommend renaming it before publishing the repository:
ren setiment_engine.py sentiment_engine.py
Then run:
python sentiment_engine.py
That will make the public project look more polished.
Project Structure
For the first version, the project can remain small:
financial-sentiment/
│
├── .venv/
│
├── sentiment_engine.py
│
├── .gitignore
│
└── README.md
Your .gitignore should include:
.venv/
.env
__pycache__/
*.pyc
Final Result
With only Python and SerpApi, we now have a working pipeline capable of:
Asset
↓
Financial News Search
↓
Recent Articles
↓
Headline + Snippet
↓
Lexicon Analysis
↓
Bullish / Bearish / Neutral
It is small, understandable, and easy to extend.
More importantly, it demonstrates an important engineering principle:
You do not need to begin with an enormous AI system to build something useful.
Start with a clear pipeline.
Then improve each stage.
Conclusion
This project started as a simple question:
Can we automatically process recent financial news and get a quick indication of its overall tone?
Using Python and SerpApi, the answer is yes.
The current implementation is deliberately lightweight. It uses a manually defined financial vocabulary and compares bullish and bearish word counts.
That makes it easy to understand and easy to modify.
But it is only the beginning.
A future version could combine real market data, historical sentiment, machine learning, NLP, and large language models to build a far more sophisticated financial research system.
For now, this project provides a clean starting point for developers who want to learn how to connect Python to an external API and turn raw news data into a simple analytical output.
**The next step is not making the code bigger.
The next step is making the analysis smarter.**
Disclaimer
This project is for educational and research purposes only. The sentiment output is not financial advice and should not be used as the sole basis for investment or trading decisions.
The importance of the research
Am in a developing phase of building an autonomous AI trading quantum system for more visit https://github.com/ssebinacharles/quant-bot-command-center
Top comments (1)
thanks for your support