tgdata 0.0.0__tar.gz → 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tgdata-0.0.0 → tgdata-0.0.1}/PKG-INFO +88 -137
- tgdata-0.0.1/README.md +234 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/setup.py +1 -1
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/connection_engine.py +20 -4
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/message_engine.py +78 -45
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_00_connection.py +1 -1
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_01_list_group_chats.py +1 -1
- tgdata-0.0.1/tgdata/smoke_tests/test_05_with_progress_feature.py +330 -0
- tgdata-0.0.1/tgdata/smoke_tests/test_06_polling_simple.py +124 -0
- tgdata-0.0.1/tgdata/smoke_tests/test_07_on_new_message_simple.py +159 -0
- tgdata-0.0.1/tgdata/smoke_tests/test_07_real_time_event_handler.py +433 -0
- tgdata-0.0.1/tgdata/smoke_tests/test_08_batch_callback.py +351 -0
- tgdata-0.0.0/tgdata/smoke_tests/test_10_polling.py → tgdata-0.0.1/tgdata/smoke_tests/test_08_polling.py +25 -22
- tgdata-0.0.1/tgdata/smoke_tests/test_debug_min_id.py +91 -0
- tgdata-0.0.1/tgdata/smoke_tests/test_polling_debug.py +190 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/tgdata.py +84 -31
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/PKG-INFO +88 -137
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/SOURCES.txt +9 -2
- tgdata-0.0.0/README.md +0 -283
- {tgdata-0.0.0 → tgdata-0.0.1}/setup.cfg +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/__init__.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/models.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/progress.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/__init__.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/my_test.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_02_get_message_count.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_03_get_all_messages.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_04_get_all_messages_in_batches.py +0 -0
- /tgdata-0.0.0/tgdata/smoke_tests/test_06_advanced_features.py → /tgdata-0.0.1/tgdata/smoke_tests/test_10_advanced_features.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/utils.py +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/dependency_links.txt +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/requires.txt +0 -0
- {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tgdata
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1
|
|
4
4
|
Summary: A production-grade Python library for extracting and processing Telegram group and channel messages
|
|
5
5
|
Author: enes kuzucu
|
|
6
6
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -46,20 +46,72 @@ A production-grade Python library for extracting and processing Telegram group a
|
|
|
46
46
|
pip install tgdata
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
|
|
50
|
+
## Authentication
|
|
51
|
+
|
|
52
|
+
tgdata supports 1 authentication at the moment.
|
|
53
|
+
|
|
54
|
+
(2 other are being implemented)
|
|
55
|
+
|
|
56
|
+
1. get telegram development credentials in telegram API Development Tools from [https://my.telegram.org/apps](https://my.telegram.org/apps)
|
|
57
|
+
|
|
58
|
+
2. Create a `config.ini` file with your Telegram API credentials like this:
|
|
59
|
+
|
|
60
|
+
```ini
|
|
61
|
+
[Telegram]
|
|
62
|
+
|
|
63
|
+
# you can get telegram development credentials in telegram API Development Tools
|
|
64
|
+
api_id = 1234566
|
|
65
|
+
api_hash = a24adjfakjdfakjshdflkajsbdflk
|
|
66
|
+
phone = +905064004949 # use full phone number including + and country code
|
|
67
|
+
username = 'powerpuffdude'
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
|
|
49
72
|
## Quick Start
|
|
50
73
|
|
|
74
|
+
### List All Group Chats
|
|
75
|
+
|
|
76
|
+
This is required for finding chat id for the chat of interest.
|
|
77
|
+
|
|
51
78
|
```python
|
|
52
79
|
from tgdata import TgData
|
|
53
80
|
import asyncio
|
|
54
81
|
|
|
55
82
|
async def main():
|
|
56
83
|
# Initialize the client
|
|
57
|
-
tg = TgData()
|
|
84
|
+
tg = TgData("config.ini")
|
|
58
85
|
|
|
59
86
|
# List available groups and channels
|
|
60
87
|
groups = await tg.list_groups()
|
|
61
|
-
|
|
62
|
-
|
|
88
|
+
|
|
89
|
+
print(groups)
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Outputs:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Python Devs 10012312313
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
### Get all messages of a chat
|
|
101
|
+
|
|
102
|
+
Once you optain chat id, you can use it to get all messages.
|
|
103
|
+
Upto 2500 messages you will not see limiting from Telegram.
|
|
104
|
+
If group is really active (+20 messages each day for over a year) then it is better to use batch logic.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from tgdata import TgData
|
|
109
|
+
import asyncio
|
|
110
|
+
|
|
111
|
+
async def main():
|
|
112
|
+
# Initialize the client
|
|
113
|
+
tg = TgData("config.ini")
|
|
114
|
+
|
|
63
115
|
# Fetch messages from a specific group
|
|
64
116
|
messages = await tg.get_messages(
|
|
65
117
|
group_id=-1001234567890, # Your group ID
|
|
@@ -69,40 +121,43 @@ async def main():
|
|
|
69
121
|
|
|
70
122
|
# Export to CSV
|
|
71
123
|
tg.export_messages(messages, "messages.csv")
|
|
72
|
-
|
|
73
|
-
# Get message statistics
|
|
74
|
-
stats = tg.get_statistics(messages)
|
|
75
|
-
print(f"Total messages: {stats['total_messages']}")
|
|
76
|
-
print(f"Date range: {stats['date_range']['first']} to {stats['date_range']['last']}")
|
|
77
124
|
|
|
78
125
|
asyncio.run(main())
|
|
79
126
|
```
|
|
80
127
|
|
|
81
|
-
|
|
128
|
+
### Get message count of a chat
|
|
82
129
|
|
|
83
|
-
Create a `config.ini` file with your Telegram API credentials:
|
|
84
130
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from tgdata import TgData
|
|
134
|
+
import asyncio
|
|
135
|
+
|
|
136
|
+
async def main():
|
|
137
|
+
# Initialize the client
|
|
138
|
+
tg = TgData("config.ini")
|
|
139
|
+
|
|
140
|
+
# Fetch messages from a specific group
|
|
141
|
+
message_count = await tg.get_message_count(
|
|
142
|
+
group_id=-1001234567890, # Your group ID
|
|
143
|
+
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
print(message_count)
|
|
147
|
+
|
|
148
|
+
asyncio.run(main())
|
|
90
149
|
```
|
|
91
150
|
|
|
92
|
-
|
|
151
|
+
|
|
152
|
+
|
|
93
153
|
|
|
94
154
|
## Advanced Usage
|
|
95
155
|
|
|
96
|
-
###
|
|
156
|
+
### get_messages with start_date parameter
|
|
97
157
|
|
|
98
158
|
```python
|
|
99
|
-
from tgdata import TgData
|
|
100
|
-
from datetime import datetime, timedelta
|
|
101
|
-
import asyncio
|
|
102
159
|
|
|
103
|
-
|
|
104
|
-
tg = TgData()
|
|
105
|
-
|
|
160
|
+
tg = TgData("config.ini")
|
|
106
161
|
# Fetch recent messages for ETL processing
|
|
107
162
|
yesterday = datetime.now() - timedelta(days=1)
|
|
108
163
|
messages = await tg.get_messages(
|
|
@@ -111,21 +166,7 @@ async def etl_pipeline():
|
|
|
111
166
|
with_progress=True
|
|
112
167
|
)
|
|
113
168
|
|
|
114
|
-
# Filter messages
|
|
115
|
-
filtered = tg.filter_messages(
|
|
116
|
-
messages,
|
|
117
|
-
keyword="important",
|
|
118
|
-
start_date=yesterday
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
# Export for data pipeline
|
|
122
|
-
tg.export_messages(filtered, "daily_extract.json", format="json")
|
|
123
|
-
|
|
124
|
-
# Get metrics
|
|
125
|
-
metrics = await tg.get_metrics()
|
|
126
|
-
print(f"Processed {len(filtered)} messages")
|
|
127
169
|
|
|
128
|
-
asyncio.run(etl_pipeline())
|
|
129
170
|
```
|
|
130
171
|
|
|
131
172
|
### Incremental Message Fetching
|
|
@@ -134,9 +175,9 @@ asyncio.run(etl_pipeline())
|
|
|
134
175
|
from tgdata import TgData
|
|
135
176
|
|
|
136
177
|
async def incremental_fetch():
|
|
137
|
-
tg = TgData()
|
|
178
|
+
tg = TgData("config.ini")
|
|
138
179
|
|
|
139
|
-
# Get the latest message ID from your storage
|
|
180
|
+
# Get the latest message ID from your storage, or db
|
|
140
181
|
last_processed_id = load_checkpoint() # Your implementation
|
|
141
182
|
|
|
142
183
|
# Fetch only messages after that ID
|
|
@@ -144,15 +185,9 @@ async def incremental_fetch():
|
|
|
144
185
|
group_id=-1001234567890,
|
|
145
186
|
after_id=last_processed_id
|
|
146
187
|
)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
process_messages(new_messages)
|
|
151
|
-
|
|
152
|
-
# Save new checkpoint
|
|
153
|
-
save_checkpoint(new_messages['MessageId'].max())
|
|
154
|
-
|
|
155
|
-
print(f"New messages: {len(new_messages)}")
|
|
188
|
+
|
|
189
|
+
save_checkpoint(new_messages['MessageId'].max()) # Your implementation
|
|
190
|
+
|
|
156
191
|
|
|
157
192
|
asyncio.run(incremental_fetch())
|
|
158
193
|
```
|
|
@@ -174,24 +209,10 @@ async def monitor_extraction():
|
|
|
174
209
|
)
|
|
175
210
|
```
|
|
176
211
|
|
|
177
|
-
###
|
|
212
|
+
### Custom callback
|
|
213
|
+
|
|
214
|
+
|
|
178
215
|
|
|
179
|
-
```python
|
|
180
|
-
async def monitor_real_time():
|
|
181
|
-
tg = TgData()
|
|
182
|
-
|
|
183
|
-
# Register handler for new messages
|
|
184
|
-
@tg.on_new_message(group_id=-1001234567890)
|
|
185
|
-
async def handle_message(event):
|
|
186
|
-
print(f"New message from {event.sender_id}: {event.message.text}")
|
|
187
|
-
|
|
188
|
-
# React to commands
|
|
189
|
-
if event.message.text == "!ping":
|
|
190
|
-
await event.reply("Pong!")
|
|
191
|
-
|
|
192
|
-
# Run event loop
|
|
193
|
-
await tg.run_with_event_loop()
|
|
194
|
-
```
|
|
195
216
|
|
|
196
217
|
### Polling for New Messages
|
|
197
218
|
|
|
@@ -213,69 +234,9 @@ async def poll_messages():
|
|
|
213
234
|
)
|
|
214
235
|
```
|
|
215
236
|
|
|
216
|
-
## API Reference
|
|
217
|
-
|
|
218
|
-
### TgData
|
|
219
|
-
|
|
220
|
-
Main class for interacting with Telegram groups and channels.
|
|
221
|
-
|
|
222
|
-
#### Methods
|
|
223
|
-
|
|
224
|
-
**Core Methods:**
|
|
225
|
-
- `list_groups()` - List all accessible groups and channels
|
|
226
|
-
- `get_messages()` - Fetch messages with various filters
|
|
227
|
-
- `search_messages()` - Search for specific content
|
|
228
|
-
- `filter_messages()` - Filter messages by criteria
|
|
229
|
-
- `export_messages()` - Export to CSV or JSON
|
|
230
|
-
- `get_statistics()` - Get message statistics
|
|
231
|
-
- `get_metrics()` - Get session metrics
|
|
232
|
-
- `get_message_count()` - Get total message count without fetching all
|
|
233
237
|
|
|
234
|
-
|
|
235
|
-
- `on_new_message()` - Decorator to register real-time message handlers
|
|
236
|
-
- `poll_for_messages()` - Poll for new messages at intervals
|
|
237
|
-
- `run_with_event_loop()` - Run client with event loop for real-time events
|
|
238
|
+
### on_new_message method
|
|
238
239
|
|
|
239
|
-
### Checkpoint Management
|
|
240
|
-
|
|
241
|
-
For production ETL pipelines, implement your own checkpoint logic:
|
|
242
|
-
|
|
243
|
-
```python
|
|
244
|
-
# Save last processed message ID to your database
|
|
245
|
-
last_id = messages['MessageId'].max()
|
|
246
|
-
await save_to_database(group_id, last_id)
|
|
247
|
-
|
|
248
|
-
# On next run, fetch only new messages
|
|
249
|
-
last_id = await load_from_database(group_id)
|
|
250
|
-
new_messages = await tg.get_messages(group_id=group_id, after_id=last_id)
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
## Production Deployment
|
|
254
|
-
|
|
255
|
-
### Best Practices
|
|
256
|
-
|
|
257
|
-
1. **Use environment variables for credentials**:
|
|
258
|
-
```python
|
|
259
|
-
import os
|
|
260
|
-
config_path = os.getenv("TELEGRAM_CONFIG", "config.ini")
|
|
261
|
-
tg = TgData(config_path=config_path)
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
2. **Implement error handling**:
|
|
265
|
-
```python
|
|
266
|
-
try:
|
|
267
|
-
messages = await tg.get_messages(group_id=group_id)
|
|
268
|
-
except Exception as e:
|
|
269
|
-
logger.error(f"Failed to fetch messages: {e}")
|
|
270
|
-
# Implement retry logic or alerting
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
3. **Monitor rate limits**:
|
|
274
|
-
```python
|
|
275
|
-
health = await tg.health_check()
|
|
276
|
-
if not health['primary_connection']:
|
|
277
|
-
# Handle connection issues
|
|
278
|
-
```
|
|
279
240
|
|
|
280
241
|
### Performance Tips
|
|
281
242
|
|
|
@@ -297,13 +258,3 @@ MIT License - see LICENSE file for details
|
|
|
297
258
|
## Contributing
|
|
298
259
|
|
|
299
260
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
300
|
-
|
|
301
|
-
## Support
|
|
302
|
-
|
|
303
|
-
- Documentation: [Full documentation](https://github.com/yourusername/tgdata)
|
|
304
|
-
- Issues: [GitHub Issues](https://github.com/yourusername/tgdata/issues)
|
|
305
|
-
- Examples: See the [examples/](examples/) directory
|
|
306
|
-
|
|
307
|
-
## Disclaimer
|
|
308
|
-
|
|
309
|
-
This tool is for legitimate data collection and analysis only. Users must comply with Telegram's Terms of Service and applicable laws. Always respect user privacy and platform rate limits.
|
tgdata-0.0.1/README.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# tgdata
|
|
2
|
+
|
|
3
|
+
A production-grade Python library for extracting and processing Telegram group and channel messages. Designed for ETL pipelines, data analysis, and archival purposes.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Production-Ready**: Built for reliability and scale in ETL pipelines
|
|
8
|
+
- 📊 **Efficient Data Extraction**: Fetch messages from groups and channels with rate limit handling
|
|
9
|
+
- 🔄 **Incremental Updates**: Fetch only new messages with `after_id` parameter
|
|
10
|
+
- 📈 **Progress Tracking**: Monitor long-running operations with real-time progress
|
|
11
|
+
- 🔌 **Clean Architecture**: Focused on data extraction with minimal dependencies
|
|
12
|
+
- 🛡️ **Robust Error Handling**: Automatic retries with exponential backoff
|
|
13
|
+
- 📁 **Multiple Export Formats**: Export to CSV, JSON, or integrate with your data pipeline
|
|
14
|
+
- 🔔 **Real-time Updates**: Listen for new messages with event handlers
|
|
15
|
+
- ⏱️ **Polling Support**: Poll for new messages at configurable intervals
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install tgdata
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## Authentication
|
|
25
|
+
|
|
26
|
+
tgdata supports 1 authentication at the moment.
|
|
27
|
+
|
|
28
|
+
(2 other are being implemented)
|
|
29
|
+
|
|
30
|
+
1. get telegram development credentials in telegram API Development Tools from [https://my.telegram.org/apps](https://my.telegram.org/apps)
|
|
31
|
+
|
|
32
|
+
2. Create a `config.ini` file with your Telegram API credentials like this:
|
|
33
|
+
|
|
34
|
+
```ini
|
|
35
|
+
[Telegram]
|
|
36
|
+
|
|
37
|
+
# you can get telegram development credentials in telegram API Development Tools
|
|
38
|
+
api_id = 1234566
|
|
39
|
+
api_hash = a24adjfakjdfakjshdflkajsbdflk
|
|
40
|
+
phone = +905064004949 # use full phone number including + and country code
|
|
41
|
+
username = 'powerpuffdude'
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
### List All Group Chats
|
|
49
|
+
|
|
50
|
+
This is required for finding chat id for the chat of interest.
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from tgdata import TgData
|
|
54
|
+
import asyncio
|
|
55
|
+
|
|
56
|
+
async def main():
|
|
57
|
+
# Initialize the client
|
|
58
|
+
tg = TgData("config.ini")
|
|
59
|
+
|
|
60
|
+
# List available groups and channels
|
|
61
|
+
groups = await tg.list_groups()
|
|
62
|
+
|
|
63
|
+
print(groups)
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Outputs:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
Python Devs 10012312313
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### Get all messages of a chat
|
|
75
|
+
|
|
76
|
+
Once you optain chat id, you can use it to get all messages.
|
|
77
|
+
Upto 2500 messages you will not see limiting from Telegram.
|
|
78
|
+
If group is really active (+20 messages each day for over a year) then it is better to use batch logic.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from tgdata import TgData
|
|
83
|
+
import asyncio
|
|
84
|
+
|
|
85
|
+
async def main():
|
|
86
|
+
# Initialize the client
|
|
87
|
+
tg = TgData("config.ini")
|
|
88
|
+
|
|
89
|
+
# Fetch messages from a specific group
|
|
90
|
+
messages = await tg.get_messages(
|
|
91
|
+
group_id=-1001234567890, # Your group ID
|
|
92
|
+
limit=1000,
|
|
93
|
+
with_progress=True
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Export to CSV
|
|
97
|
+
tg.export_messages(messages, "messages.csv")
|
|
98
|
+
|
|
99
|
+
asyncio.run(main())
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Get message count of a chat
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from tgdata import TgData
|
|
108
|
+
import asyncio
|
|
109
|
+
|
|
110
|
+
async def main():
|
|
111
|
+
# Initialize the client
|
|
112
|
+
tg = TgData("config.ini")
|
|
113
|
+
|
|
114
|
+
# Fetch messages from a specific group
|
|
115
|
+
message_count = await tg.get_message_count(
|
|
116
|
+
group_id=-1001234567890, # Your group ID
|
|
117
|
+
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
print(message_count)
|
|
121
|
+
|
|
122
|
+
asyncio.run(main())
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
## Advanced Usage
|
|
129
|
+
|
|
130
|
+
### get_messages with start_date parameter
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
|
|
134
|
+
tg = TgData("config.ini")
|
|
135
|
+
# Fetch recent messages for ETL processing
|
|
136
|
+
yesterday = datetime.now() - timedelta(days=1)
|
|
137
|
+
messages = await tg.get_messages(
|
|
138
|
+
group_id=-1001234567890,
|
|
139
|
+
start_date=yesterday,
|
|
140
|
+
with_progress=True
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Incremental Message Fetching
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from tgdata import TgData
|
|
150
|
+
|
|
151
|
+
async def incremental_fetch():
|
|
152
|
+
tg = TgData("config.ini")
|
|
153
|
+
|
|
154
|
+
# Get the latest message ID from your storage, or db
|
|
155
|
+
last_processed_id = load_checkpoint() # Your implementation
|
|
156
|
+
|
|
157
|
+
# Fetch only messages after that ID
|
|
158
|
+
new_messages = await tg.get_messages(
|
|
159
|
+
group_id=-1001234567890,
|
|
160
|
+
after_id=last_processed_id
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
save_checkpoint(new_messages['MessageId'].max()) # Your implementation
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
asyncio.run(incremental_fetch())
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Progress Monitoring
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
async def monitor_extraction():
|
|
173
|
+
tg = TgData()
|
|
174
|
+
|
|
175
|
+
def progress_callback(current, total, rate):
|
|
176
|
+
percent = (current / total * 100) if total else 0
|
|
177
|
+
print(f"Progress: {current}/{total} ({percent:.1f}%) - {rate:.1f} msg/s")
|
|
178
|
+
|
|
179
|
+
messages = await tg.get_messages(
|
|
180
|
+
group_id=-1001234567890,
|
|
181
|
+
limit=10000,
|
|
182
|
+
progress_callback=progress_callback
|
|
183
|
+
)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Custom callback
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
### Polling for New Messages
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
async def poll_messages():
|
|
195
|
+
tg = TgData()
|
|
196
|
+
|
|
197
|
+
# Define callback for new messages
|
|
198
|
+
async def process_batch(messages_df):
|
|
199
|
+
print(f"Got {len(messages_df)} new messages")
|
|
200
|
+
# Process messages here
|
|
201
|
+
|
|
202
|
+
# Poll every 30 seconds
|
|
203
|
+
await tg.poll_for_messages(
|
|
204
|
+
group_id=-1001234567890,
|
|
205
|
+
interval=30,
|
|
206
|
+
callback=process_batch,
|
|
207
|
+
max_iterations=10 # Stop after 10 polls
|
|
208
|
+
)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
### on_new_message method
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
### Performance Tips
|
|
216
|
+
|
|
217
|
+
- Use connection pooling for parallel operations
|
|
218
|
+
- Implement checkpoint logic for incremental processing
|
|
219
|
+
- Implement progress callbacks for visibility
|
|
220
|
+
- Export data incrementally for large datasets
|
|
221
|
+
|
|
222
|
+
## Requirements
|
|
223
|
+
|
|
224
|
+
- Python 3.7+
|
|
225
|
+
- Telegram API credentials (not bot tokens)
|
|
226
|
+
- Group/channel membership
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
MIT License - see LICENSE file for details
|
|
231
|
+
|
|
232
|
+
## Contributing
|
|
233
|
+
|
|
234
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name='tgdata', # Package name
|
|
5
|
-
version='0.0.
|
|
5
|
+
version='0.0.1', # Version of your package
|
|
6
6
|
author='enes kuzucu', # Your name
|
|
7
7
|
|
|
8
8
|
description='A production-grade Python library for extracting and processing Telegram group and channel messages',
|
|
@@ -294,10 +294,26 @@ class ConnectionEngine:
|
|
|
294
294
|
logger.error(f"Connection validation failed: {e}")
|
|
295
295
|
return False
|
|
296
296
|
|
|
297
|
-
async def handle_rate_limit(self, error: FloodWaitError, client: Optional[TelegramClient] = None):
|
|
298
|
-
"""
|
|
299
|
-
|
|
300
|
-
|
|
297
|
+
async def handle_rate_limit(self, error: FloodWaitError, client: Optional[TelegramClient] = None, strategy: str = 'wait'):
|
|
298
|
+
"""
|
|
299
|
+
Handle rate limit errors with configurable strategy.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
error: The FloodWaitError from Telegram
|
|
303
|
+
client: The client that hit the rate limit
|
|
304
|
+
strategy: 'wait' (wait exact time) or 'exponential' (exponential backoff)
|
|
305
|
+
"""
|
|
306
|
+
base_wait_time = error.seconds
|
|
307
|
+
|
|
308
|
+
if strategy == 'exponential':
|
|
309
|
+
# Add random jitter (0-30% extra) to prevent thundering herd
|
|
310
|
+
import random
|
|
311
|
+
jitter = random.uniform(0, 0.3)
|
|
312
|
+
wait_time = base_wait_time * (1 + jitter)
|
|
313
|
+
logger.warning(f"Rate limit hit! Using exponential backoff: waiting {wait_time:.1f}s (base: {base_wait_time}s)")
|
|
314
|
+
else:
|
|
315
|
+
wait_time = base_wait_time
|
|
316
|
+
logger.warning(f"Rate limit hit! Waiting {wait_time} seconds...")
|
|
301
317
|
|
|
302
318
|
if self._pool and client:
|
|
303
319
|
self._pool.mark_rate_limited(client, wait_time)
|