Skip to content

Commit cb50924

Browse files
committed
First Release
1 parent 92f10c3 commit cb50924

2 files changed

Lines changed: 156 additions & 151 deletions

File tree

.gitignore

Lines changed: 59 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,68 @@
1-
# Byte-compiled / optimized / DLL files
2-
__pycache__/
3-
*.py[cod]
4-
*$py.class
5-
6-
# C extensions
7-
*.so
8-
9-
# Distribution / packaging
10-
.Python
11-
build/
12-
develop-eggs/
13-
dist/
14-
downloads/
15-
eggs/
16-
.eggs/
17-
lib/
18-
lib64/
19-
parts/
20-
sdist/
21-
var/
22-
wheels/
23-
share/python-wheels/
24-
*.egg-info/
25-
.installed.cfg
26-
*.egg
27-
MANIFEST
28-
29-
# PyInstaller
30-
# Usually these files are written by a python script from a template
31-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32-
*.manifest
33-
*.spec
34-
35-
# Installer logs
36-
pip-log.txt
37-
pip-delete-this-directory.txt
38-
39-
# Unit test / coverage reports
40-
htmlcov/
41-
.tox/
42-
.nox/
43-
.coverage
44-
.coverage.*
45-
.cache
46-
nosetests.xml
47-
coverage.xml
48-
*.cover
49-
*.py,cover
50-
.hypothesis/
51-
.pytest_cache/
52-
cover/
53-
54-
# Translations
55-
*.mo
56-
*.pot
57-
58-
# Django stuff:
1+
# Ignore default files and directories
2+
.DS_Store
3+
Thumbs.db
4+
node_modules/
595
*.log
60-
local_settings.py
61-
db.sqlite3
62-
db.sqlite3-journal
63-
64-
# Flask stuff:
65-
instance/
66-
.webassets-cache
67-
68-
# Scrapy stuff:
69-
.scrapy
70-
71-
# Sphinx documentation
72-
docs/_build/
73-
74-
# PyBuilder
75-
.pybuilder/
76-
target/
77-
78-
# Jupyter Notebook
79-
.ipynb_checkpoints
80-
81-
# IPython
82-
profile_default/
83-
ipython_config.py
6+
*.tmp
7+
*.bak
8+
*.swp
849

85-
# pyenv
86-
# For a library or package, you might want to ignore these files since the code is
87-
# intended to run in multiple environments; otherwise, check them in:
88-
# .python-version
10+
# Disallow pushing files starting with "Backup-" and "to-do.txt"
11+
/Backup-*
12+
/to-do.txt
8913

90-
# pipenv
91-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94-
# install all needed dependencies.
95-
#Pipfile.lock
14+
# Exclude sensitive configuration files
15+
config.ini
16+
secrets.yaml
9617

97-
# poetry
98-
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99-
# This is especially recommended for binary packages to ensure reproducibility, and is more
100-
# commonly ignored for libraries.
101-
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102-
#poetry.lock
18+
# Exclude editor and IDE files
19+
.vscode/
20+
.idea/
10321

104-
# pdm
105-
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106-
#pdm.lock
107-
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108-
# in version control.
109-
# https://pdm.fming.dev/#use-with-ide
110-
.pdm.toml
111-
112-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113-
__pypackages__/
114-
115-
# Celery stuff
116-
celerybeat-schedule
117-
celerybeat.pid
118-
119-
# SageMath parsed files
120-
*.sage.py
121-
122-
# Environments
123-
.env
124-
.venv
125-
env/
22+
# Exclude virtual environment files
12623
venv/
127-
ENV/
128-
env.bak/
129-
venv.bak/
130-
131-
# Spyder project settings
132-
.spyderproject
133-
.spyproject
134-
135-
# Rope project settings
136-
.ropeproject
137-
138-
# mkdocs documentation
139-
/site
140-
141-
# mypy
142-
.mypy_cache/
143-
.dmypy.json
144-
dmypy.json
145-
146-
# Pyre type checker
147-
.pyre/
24+
env/
25+
virtualenv/
14826

149-
# pytype static type analyzer
150-
.pytype/
27+
# Exclude compiled files and build artifacts
28+
*.pyc
29+
*.pyo
30+
__pycache__/
31+
*.class
32+
*.jar
33+
*.war
15134

152-
# Cython debug symbols
153-
cython_debug/
35+
# Ignore user-specific settings files
36+
*.iml
37+
*.DS_Store
38+
*.pydevproject
15439

155-
# PyCharm
156-
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157-
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158-
# and can be added to the global gitignore or merged into this file. For a more nuclear
159-
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
160-
#.idea/
40+
# Exclude autogenerated documentation
41+
docs/_build/
42+
doc/_build/
43+
44+
# Exclude database files
45+
*.db
46+
*.sqlite3
47+
*.sqlite
48+
49+
# Exclude media and binary files
50+
*.png
51+
*.jpg
52+
*.jpeg
53+
*.gif
54+
*.ico
55+
*.pdf
56+
*.zip
57+
*.gz
58+
*.tar
59+
*.rar
60+
*.7z
61+
*.exe
62+
*.dll
63+
64+
# Exclude temporary and generated files
65+
*.log
66+
*.swp
67+
*.tmp
68+
*.bak

ua-stats.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import json
2+
import matplotlib.pyplot as plt
3+
from wordcloud import WordCloud
4+
#import os
5+
6+
# Color Codes for Printing
7+
GREEN = "\033[32m"
8+
YELLOW = "\033[33m"
9+
BLUE = "\033[34m"
10+
RED = "\033[31m"
11+
RESET = "\033[0m"
12+
13+
# Load user agents from the JSON file
14+
json_file_path = "user_agents.json" # Update the file path to the correct one
15+
try:
16+
with open(json_file_path, "r") as json_file:
17+
user_agents = json.load(json_file)
18+
except FileNotFoundError:
19+
print(f"{RED}[ERROR]{RESET}JSON file '{json_file_path}' not found.")
20+
exit()
21+
22+
# Count the number of different groups in the JSON file for mobile and general user agents
23+
mobile_group_counts = {}
24+
general_group_counts = {}
25+
for ua in user_agents:
26+
if ua["Host"] == "Mobile":
27+
if ua["group"]:
28+
mobile_group_counts[ua["group"]] = mobile_group_counts.get(ua["group"], 0) + 1
29+
else:
30+
if ua["group"]:
31+
general_group_counts[ua["group"]] = general_group_counts.get(ua["group"], 0) + 1
32+
33+
def create_labeled_pie_chart(groups, title):
34+
plt.figure()
35+
labels = [f"{group} ({count})" for group, count in groups.items()]
36+
sizes = groups.values()
37+
plt.pie(sizes, labels=labels, autopct="%1.1f%%", startangle=140)
38+
plt.title(title)
39+
40+
# Create the legend in the upper left corner with a defined box position
41+
plt.legend(labels, loc="upper left", bbox_to_anchor=(1, 1))
42+
43+
plt.tight_layout()
44+
45+
# User input for pie charts
46+
while True:
47+
print("Select an option:")
48+
print("1. Pie chart for Mobile User Agents (Count < 10)")
49+
print("2. Pie chart for Mobile User Agents (10 <= Count < 500)")
50+
print("3. Pie chart for General User Agents (10 <= Count < 50)")
51+
print("4. Pie chart for General User Agents (50 <= Count < 500)")
52+
print("5. Pie chart for General User Agents (Count >= 500)")
53+
print("6. Word Cloud for Mobile User Agent Group Names")
54+
print("7. Word Cloud for General User Agent Group Names")
55+
print("8. Exit")
56+
choice = input("Enter your choice (1/2/3/4/5/6/7/8): ")
57+
58+
if choice == "1":
59+
create_labeled_pie_chart({group: count for group, count in mobile_group_counts.items() if count < 10}, "Mobile User Agents (Count < 10)")
60+
plt.subplots_adjust(bottom=0.1, top=1.0) # Adjust the layout
61+
#plt.savefig(os.path.join(charts_dir, "mobile_pie_chart.png"))
62+
elif choice == "2":
63+
create_labeled_pie_chart({group: count for group, count in mobile_group_counts.items() if 10 <= count < 500}, "Mobile User Agents (10 <= Count < 500)")
64+
#plt.savefig(os.path.join(charts_dir, "mobile_pie_chart_10_to_500.png"))
65+
elif choice == "3":
66+
create_labeled_pie_chart({group: count for group, count in general_group_counts.items() if 10 <= count < 50}, "General User Agents (10 <= Count < 50)")
67+
plt.subplots_adjust(bottom=0.1, top=1.0) # Adjust the layout
68+
#plt.savefig(os.path.join(charts_dir, "general_pie_chart_10_to_50.png"))
69+
elif choice == "4":
70+
create_labeled_pie_chart({group: count for group, count in general_group_counts.items() if 50 <= count < 500}, "General User Agents (50 <= Count < 500)")
71+
#plt.savefig(os.path.join(charts_dir, "general_pie_chart_50_to_500.png"))
72+
elif choice == "5":
73+
create_labeled_pie_chart({group: count for group, count in general_group_counts.items() if count >= 500}, "General User Agents (Count >= 500)")
74+
#plt.savefig(os.path.join(charts_dir, "general_pie_chart_500_and_above.png"))
75+
elif choice == "6":
76+
# Create a word cloud for mobile user agent group names
77+
wordcloud = WordCloud(width=800, height=400, background_color="white").generate_from_frequencies(mobile_group_counts)
78+
plt.figure()
79+
plt.imshow(wordcloud, interpolation="bilinear")
80+
plt.axis("off")
81+
plt.title("Highest Mobile User Agents")
82+
#plt.savefig(os.path.join(charts_dir, "mobile_wordcloud.png"))
83+
elif choice == "7":
84+
# Create a word cloud for general user agent group names
85+
wordcloud = WordCloud(width=800, height=400, background_color="white").generate_from_frequencies(general_group_counts)
86+
plt.figure()
87+
plt.imshow(wordcloud, interpolation="bilinear")
88+
plt.axis("off")
89+
plt.title("Highest General User Agents")
90+
#plt.savefig(os.path.join(charts_dir, "general_wordcloud.png"))
91+
elif choice == "8":
92+
print("Exiting the program.")
93+
break
94+
else:
95+
print("Invalid choice. Please enter a valid choice.")
96+
# Display the selected pie chart
97+
plt.show()

0 commit comments

Comments
 (0)