attendantelectro commited on
Commit
09dd334
·
verified ·
1 Parent(s): f1108a7

Rename main.py to scraper.py

Browse files
Files changed (2) hide show
  1. main.py +0 -305
  2. scraper.py +46 -0
main.py DELETED
@@ -1,305 +0,0 @@
1
- import os
2
- from typing import List, Dict, Optional
3
- from datetime import datetime, timedelta
4
-
5
- from fastapi import FastAPI, HTTPException, Depends, WebSocket, WebSocketDisconnect, status
6
- from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
7
- from fastapi.responses import HTMLResponse
8
- from pydantic import BaseModel
9
- from sqlalchemy import create_engine, Column, Integer, String, Table, ForeignKey, DateTime, Text
10
- from sqlalchemy.ext.declarative import declarative_base
11
- from sqlalchemy.orm import sessionmaker, relationship, Session
12
- import uvicorn
13
-
14
- # امنیت: JWT و رمزنگاری پسوردها
15
- from jose import JWTError, jwt
16
- from passlib.context import CryptContext
17
-
18
- # پیکربندی
19
- SECRET_KEY = "your-secret-key" # در محصولات واقعی تعویض شود و از متغیرهای محیطی استفاده کنید
20
- ALGORITHM = "HS256"
21
- ACCESS_TOKEN_EXPIRE_MINUTES = 30
22
-
23
- # تنظیمات رمزنگاری رمز عبور
24
- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
25
- oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
26
-
27
- # ایجاد پایگاه داده SQLite
28
- DATABASE_URL = "sqlite:///./chat.db"
29
- engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
30
- SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
31
- Base = declarative_base()
32
-
33
- # جداول پایگاه‌داده
34
- class UserModel(Base):
35
- __tablename__ = "users"
36
- id = Column(Integer, primary_key=True, index=True)
37
- username = Column(String, unique=True, index=True)
38
- hashed_password = Column(String)
39
-
40
- # جدول گروه‌ها
41
- class GroupModel(Base):
42
- __tablename__ = "groups"
43
- id = Column(Integer, primary_key=True, index=True)
44
- group_name = Column(String, unique=True, index=True)
45
- owner_id = Column(Integer, ForeignKey("users.id"))
46
- owner = relationship("UserModel")
47
-
48
- # جدول پیام‌ها
49
- class MessageModel(Base):
50
- __tablename__ = "messages"
51
- id = Column(Integer, primary_key=True, index=True)
52
- sender_id = Column(Integer, ForeignKey("users.id"))
53
- group_id = Column(Integer, ForeignKey("groups.id"))
54
- content = Column(Text)
55
- timestamp = Column(DateTime, default=datetime.utcnow)
56
-
57
- # ایجاد جداول اگر وجود نداشتند
58
- Base.metadata.create_all(bind=engine)
59
-
60
- # مدل‌های Pydantic
61
- class User(BaseModel):
62
- username: str
63
- password: str
64
-
65
- class UserOut(BaseModel):
66
- id: int
67
- username: str
68
- class Config:
69
- orm_mode = True
70
-
71
- class Token(BaseModel):
72
- access_token: str
73
- token_type: str
74
-
75
- class Group(BaseModel):
76
- group_name: str
77
-
78
- class GroupOut(BaseModel):
79
- id: int
80
- group_name: str
81
- owner: UserOut
82
- class Config:
83
- orm_mode = True
84
-
85
- class Message(BaseModel):
86
- sender: str
87
- content: str
88
- timestamp: datetime
89
-
90
- # توابع مربوط به رمزنگاری
91
- def verify_password(plain_password, hashed_password):
92
- return pwd_context.verify(plain_password, hashed_password)
93
-
94
- def get_password_hash(password):
95
- return pwd_context.hash(password)
96
-
97
- # توابع مربوط به DB
98
- def get_db():
99
- db = SessionLocal()
100
- try:
101
- yield db
102
- finally:
103
- db.close()
104
-
105
- # توابع احراز هویت JWT
106
- def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
107
- to_encode = data.copy()
108
- if expires_delta:
109
- expire = datetime.utcnow() + expires_delta
110
- else:
111
- expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
112
- to_encode.update({"exp": expire})
113
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
114
- return encoded_jwt
115
-
116
- def get_user(db: Session, username: str):
117
- return db.query(UserModel).filter(UserModel.username == username).first()
118
-
119
- def authenticate_user(db: Session, username: str, password: str):
120
- user = get_user(db, username)
121
- if not user:
122
- return False
123
- if not verify_password(password, user.hashed_password):
124
- return False
125
- return user
126
-
127
- async def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
128
- credentials_exception = HTTPException(
129
- status_code=status.HTTP_401_UNAUTHORIZED,
130
- detail="Could not validate credentials",
131
- headers={"WWW-Authenticate": "Bearer"},
132
- )
133
- try:
134
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
135
- username: str = payload.get("sub")
136
- if username is None:
137
- raise credentials_exception
138
- except JWTError:
139
- raise credentials_exception
140
-
141
- user = get_user(db, username=username)
142
- if user is None:
143
- raise credentials_exception
144
- return user
145
-
146
- # ایجاد سرور FastAPI
147
- app = FastAPI()
148
-
149
- # لاگ ساده: در پروژه‌های عملی می‌توانید از logging پیشرفته استفاده کنید
150
- @app.middleware("http")
151
- async def add_process_time_header(request, call_next):
152
- response = await call_next(request)
153
- return response
154
-
155
- # --- Endpointهای احراز هویت ---
156
-
157
- @app.post("/register/", response_model=UserOut)
158
- def register_user(user: User, db: Session = Depends(get_db)):
159
- db_user = get_user(db, username=user.username)
160
- if db_user:
161
- raise HTTPException(status_code=400, detail="Username already registered")
162
- hashed_pwd = get_password_hash(user.password)
163
- new_user = UserModel(username=user.username, hashed_password=hashed_pwd)
164
- db.add(new_user)
165
- db.commit()
166
- db.refresh(new_user)
167
- return new_user
168
-
169
- @app.post("/token", response_model=Token)
170
- def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(),
171
- db: Session = Depends(get_db)):
172
- user = authenticate_user(db, form_data.username, form_data.password)
173
- if not user:
174
- raise HTTPException(status_code=401, detail="Incorrect username or password")
175
-
176
- access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
177
- access_token = create_access_token(
178
- data={"sub": user.username}, expires_delta=access_token_expires
179
- )
180
- return {"access_token": access_token, "token_type": "bearer"}
181
-
182
- # --- Endpoint های مربوط به گروه‌ها ---
183
-
184
- @app.post("/groups/", response_model=GroupOut)
185
- def create_group(group: Group, current_user: UserModel = Depends(get_current_user),
186
- db: Session = Depends(get_db)):
187
- # بررسی وجود گروه با نام مشابه
188
- db_group = db.query(GroupModel).filter(GroupModel.group_name == group.group_name).first()
189
- if db_group:
190
- raise HTTPException(status_code=400, detail="Group name already exists")
191
- new_group = GroupModel(group_name=group.group_name, owner_id=current_user.id)
192
- db.add(new_group)
193
- db.commit()
194
- db.refresh(new_group)
195
- return new_group
196
-
197
- @app.get("/groups/", response_model=List[GroupOut])
198
- def get_groups(current_user: UserModel = Depends(get_current_user),
199
- db: Session = Depends(get_db)):
200
- # فرض می‌کنیم هر گروهی متعلق به یک کاربر نیست،
201
- # در دنیای واقعی ممکن است کاربران عضو گروه‌های مختلفی باشند (نیاز به جدول ارتباطی دارد)
202
- groups = db.query(GroupModel).all()
203
- return groups
204
-
205
- # --- WebSocket برای ارسال و دریافت پیام‌ها ---
206
- # در این مثال از یک ConnectionManager ساده استفاده می‌کنیم
207
- class ConnectionManager:
208
- def __init__(self):
209
- # نگهداری اتصالات بر اساس id گروه
210
- self.active_connections: Dict[int, List[WebSocket]] = {}
211
-
212
- async def connect(self, group_id: int, websocket: WebSocket):
213
- await websocket.accept()
214
- if group_id not in self.active_connections:
215
- self.active_connections[group_id] = []
216
- self.active_connections[group_id].append(websocket)
217
-
218
- def disconnect(self, group_id: int, websocket: WebSocket):
219
- if group_id in self.active_connections:
220
- self.active_connections[group_id].remove(websocket)
221
-
222
- async def broadcast(self, group_id: int, message: Message):
223
- if group_id in self.active_connections:
224
- for connection in self.active_connections[group_id]:
225
- await connection.send_json(message.dict())
226
-
227
- manager = ConnectionManager()
228
-
229
- @app.websocket("/ws/groups/{group_id}")
230
- async def websocket_endpoint(websocket: WebSocket, group_id: int,
231
- token: str = Depends(oauth2_scheme),
232
- db: Session = Depends(get_db)):
233
- # احراز هویت مجدد روی WebSocket
234
- try:
235
- current_user = await get_current_user(token, db)
236
- except HTTPException:
237
- await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
238
- return
239
-
240
- await manager.connect(group_id, websocket)
241
- try:
242
- while True:
243
- data = await websocket.receive_json()
244
- # ایجاد شی پیام جهت ارسال
245
- message = Message(
246
- sender=current_user.username,
247
- content=data.get("content"),
248
- timestamp=datetime.utcnow()
249
- )
250
- # ذخیره پیام در پایگاه داده
251
- new_msg = MessageModel(sender_id=current_user.id, group_id=group_id, content=message.content)
252
- db.add(new_msg)
253
- db.commit()
254
- await manager.broadcast(group_id, message)
255
- except WebSocketDisconnect:
256
- manager.disconnect(group_id, websocket)
257
- except Exception as e:
258
- # در صورت بروز خطای دیگر، می‌توانیم آن را لاگ کرده و websocket را ببندیم.
259
- await websocket.close()
260
-
261
- # نمونه از صفحه HTML جهت تست WebSocket (در پروژه تولید رابط کاربری جداگانه نوشته می شود)
262
- html = """
263
- <!DOCTYPE html>
264
- <html>
265
- <head>
266
- <title>WebSocket Chat Room</title>
267
- </head>
268
- <body>
269
- <h1>WebSocket Chat</h1>
270
- <form id="form">
271
- <input type="text" id="messageText" autocomplete="off"/>
272
- <button>Send</button>
273
- </form>
274
- <ul id='messages'>
275
- </ul>
276
- <script>
277
- // برای تست، جای token و group_id را تنظیم کنید
278
- let token = prompt("Enter your JWT token:");
279
- let group_id = prompt("Enter group id:");
280
- const ws = new WebSocket(`ws://localhost:8000/ws/groups/${group_id}?token=${token}`);
281
- ws.onmessage = function(event) {
282
- const messages = document.getElementById('messages')
283
- const message = document.createElement('li')
284
- const data = JSON.parse(event.data)
285
- message.innerText = data.sender + ": " + data.content;
286
- messages.appendChild(message);
287
- };
288
- document.getElementById('form').onsubmit = function(e) {
289
- e.preventDefault()
290
- const input = document.getElementById("messageText")
291
- ws.send(JSON.stringify({content: input.value}))
292
- input.value = ''
293
- }
294
- </script>
295
- </body>
296
- </html>
297
- """
298
-
299
- @app.get("/")
300
- def get():
301
- return HTMLResponse(html)
302
-
303
- # اجرای سرور
304
- if __name__ == "__main__":
305
- uvicorn.run(app, host="0.0.0.0", port=8000)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scraper.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from selenium import webdriver
2
+ from selenium.webdriver.chrome.service import Service
3
+ from webdriver_manager.chrome import ChromeDriverManager
4
+ from selenium.webdriver.chrome.options import Options
5
+ import zipfile
6
+ import os
7
+
8
+ def scrape_pages(base_url, start_page, end_page):
9
+ chrome_options = Options()
10
+ chrome_options.add_argument("--headless")
11
+ chrome_options.add_argument("--no-sandbox")
12
+ chrome_options.add_argument("--disable-dev-shm-usage")
13
+
14
+ driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
15
+
16
+ if not os.path.exists('pages'):
17
+ os.makedirs('pages')
18
+
19
+ for page in range(start_page, end_page + 1):
20
+ url = f"{base_url}?page={page}"
21
+ driver.get(url)
22
+ html = driver.page_source
23
+
24
+ with open(f'pages/t{page}.html', 'w', encoding='utf-8') as f:
25
+ f.write(html)
26
+ print(f"Saved: t{page}.html")
27
+
28
+ driver.quit()
29
+
30
+ # ایجاد فایل ZIP
31
+ with zipfile.ZipFile('html.zip', 'w', zipfile.ZIP_DEFLATED) as zipf:
32
+ for root, dirs, files in os.walk('pages'):
33
+ for file in files:
34
+ zipf.write(os.path.join(root, file), file)
35
+
36
+ print("All pages saved and zipped as html.zip")
37
+
38
+ if __name__ == "__main__":
39
+ base_url = "https://shahvani.com/dastans"
40
+ start_page = 1
41
+ end_page = 10 # این عدد را می‌توانید به تابع بدهید یا از کاربر بگیرید
42
+
43
+ # مثال: اگر می‌خواهید تعداد صفحات را به صورت پویا مشخص کنید
44
+ # end_page = get_last_page_number() # تابعی که تعداد صفحات را برمی‌گرداند
45
+
46
+ scrape_pages(base_url, start_page, end_page)