Parse nginx access log top IPs in Python
Reads an nginx access log line by line, extracts the client IP, and returns the most frequent IPs using a regex and Counter.
Python code
29 linesimport re
from collections import Counter
def top_ips(log_file, n=10):
ip_pattern = re.compile(r'^(\S+)')
ip_counts = Counter()
with open(log_file, 'r') as f:
for line in f:
match = ip_pattern.match(line)
if match:
ip_counts[match.group(1)] += 1
return ip_counts.most_common(n)
if __name__ == "__main__":
# Sample nginx access log data
sample_log = """192.168.1.1 - - [10/Oct/2023:13:55:36 +0000] "GET /index.html HTTP/1.1" 200 2326
10.0.0.2 - - [10/Oct/2023:13:55:37 +0000] "GET /api/data HTTP/1.1" 200 153
192.168.1.1 - - [10/Oct/2023:13:55:38 +0000] "GET /about HTTP/1.1" 404 12
203.0.113.5 - - [10/Oct/2023:13:55:39 +0000] "POST /login HTTP/1.1" 200 89
10.0.0.2 - - [10/Oct/2023:13:55:40 +0000] "GET /api/data HTTP/1.1" 200 153
192.168.1.1 - - [10/Oct/2023:13:55:41 +0000] "GET /contact HTTP/1.1" 200 45"""
with open('access.log', 'w') as f:
f.write(sample_log)
for ip, count in top_ips('access.log', 3):
print(f"{ip}: {count}")
Output
192.168.1.1: 3
10.0.0.2: 2
203.0.113.5: 1
How it works
This script uses a regex r'^(\S+)' to capture the first whitespace-delimited token on each line, which is the client IP in nginx's default combined log format. The Counter from collections tallies each IP as lines are read, and most_common(n) returns the top n IPs sorted by descending count. Reading the file line by line keeps memory usage low even for large logs. The if __name__ == "__main__" block creates a sample log file for demonstration, then prints the top IPs and their counts.
Common mistakes
- Using `re.search` without anchoring and matching the IP in the middle of the line instead of the start.
- Forgetting that the regex must start with `^` to avoid matching part of the timestamp or other fields.
- Not handling lines that don't match the pattern (e.g., blank lines) which can cause AttributeError if you assume a match.
Variations
- Use `split()[0]` instead of regex for simpler extraction when the log format is consistent.
- Read the entire file into memory with `readlines()` and use a generator expression for counting, but this is less memory-efficient for large logs.
Real-world use cases
- Identifying heavy clients that are hammering your web server to adjust rate limits or evict abusive traffic.
- Spotting scraping bots by comparing IP frequency against known bot signatures in an analytics pipeline.
- Auditing access logs before a security review to detect suspicious IPs that correlate with failed login attempts.
Sponsored
More from Automation & scripting
- Aggregate Log Errors Count by Hour in Python easy
- Automate Tweeting New Blog Posts in Python easy
- Automatically Clean Temporary Files from Applications Using Python medium
- Automatically Download the Latest Software Release from GitHub with Python medium
- Automatically Generate Charts from CSV Files with One Command medium
- Automatically Generate Hardware Inventory Reports in Python easy
Keep learning
Related tutorials and quizzes for this topic.