Dasturlar internet orqali qanday “gaplaşadi”?
Telefoningizdagi ob-havo ilovasi, bank ilovasidagi valyuta kursi, taksi çaqiriş xizmati — bularning hammasi internetdagi boşqa kompyuterlar (serverlar) bilan maʼlumot almaşadi. Bu almaşinuv köpinça HTTP protokoli orqali böladi: sizning dasturingiz (mijoz) sörov yuboradi, server esa javob qaytaradi.
Har bir HTTP sörovning asosiy qismlari:
- Manzil (
URL) — qaysi serverga va qaysi resursga murojaat qilinyapti. - Metod — nima qilmoqçimiz:
GET(maʼlumot oliş),POST(yangi maʼlumot yuboriş),PUT/PATCH(yangilaş),DELETE(öçiriş). - Sarlavhalar (
headers) — qöşimça maʼlumot: qaysi formatni kutyapmiz, kim ekanmiz va hokazo. - Tana (
body) — yuborilayotgan maʼlumotning özi (GETda odatda bölmaydi).
Server javobida esa holat kodi (status code), sarlavhalar va tana böladi. Dasturlar uçun möljallangan bunday manzillar töplami API (Application Programming Interface) deyiladi va ular köpinça maʼlumotni JSON formatida qaytaradi.
requests kutubxonasini örnatiş
Python'ning standart kutubxonasida urllib moduli bor, lekin uning bilan işlaş biroz noqulay. Deyarli barça Python dasturçilari buning örniga requests kutubxonasidan foydalanadi. U standart kutubxonaga kirmaydi, şuning uçun avval örnatamiz:
pip install requests
Birinçi GET sörov
Özbekiston Respublikasi Markaziy banki valyuta kurslarini oçiq JSON körinişida eʼlon qiladi: cbu.uz/uz/arkhiv-kursov-valyut/json/. Bu manzilni brauzerda oçsangiz, valyutalar röyxatini körasiz. Endi xuddi şuni Python orqali qilamiz.
import requests
# Eslatma: bu darslik yozilayotganda manzilga ulanib tekşirib bölmadi, şuning uçun
# quyida körsatilgan javob tuzilişi umumiy tavsif. Özingizda bir marta print() qilib köring.
URL = "https://cbu.uz/uz/arkhiv-kursov-valyut/json/"
javob = requests.get(URL, timeout=10)
print(javob.status_code) # 200 — hammasi joyida
kurslar = javob.json() # JSON matnni Python röyxatiga aylantiradi
print(type(kurslar), len(kurslar))
print(kurslar[0])
Natija taxminan şunday böladi (valyutalar soni va qiymatlar boşqaça bölişi mumkin, kurslar har kuni özgaradi):
200
<class 'list'> 75
{'id': 69, 'Code': '840', 'Ccy': 'USD', 'CcyNm_RU': 'Доллар США', 'CcyNm_UZ': 'AQŞ dollari', 'CcyNm_UZC': 'АҚШ доллари', 'CcyNm_EN': 'US Dollar', 'Nominal': '1', 'Rate': '12650.00', 'Diff': '-12.40', 'Date': '24.10.2026'}
Javobdagi har bir element — bitta valyuta haqidagi luğat. Bizga eng kerakli maydonlar:
| Maydon | Maʼnosi |
|---|---|
Ccy | valyutaning uç harfli kodi (USD, EUR, RUB...) |
CcyNm_UZ | valyuta nomi özbekça (CcyNm_UZC — kirill yozuvida, CcyNm_EN, CcyNm_RU — boşqa tillarda) |
Nominal | kurs neçta birlik uçun berilgani (odatda "1") |
Rate | Nominal birlikning sömdagi qiymati (satr körinişida!) |
Diff | oldingi kurs bilan farq |
Date | kurs amal qiladigan sana, kun.oy.yil formatida |
Holat kodlari
Server javobidagi uç xonali son sörov qanday yakunlanganini bildiradi. Birinçi raqamga qarab guruhni darhol tuşuniş mumkin.
| Kod | Maʼnosi | Qaçon uçraydi |
|---|---|---|
200 | OK | hammasi joyida |
201 | Created | yangi maʼlumot yaratildi (POSTdan keyin) |
301 / 302 | yönaltiriş | sahifa boşqa manzilga köçgan |
400 | Bad Request | sörov notöğri tuzilgan |
401 / 403 | ruxsat yöq | kalit yoki parol kerak / taqiqlangan |
404 | Not Found | bunday manzil yöq |
429 | Too Many Requests | juda köp sörov yubordingiz |
500 / 503 | server xatosi | muammo serverning özida |
Qisqasi: 2xx — muvaffaqiyat, 3xx — yönaltiriş, 4xx — sizning xatoingiz, 5xx — serverning xatosi. requestsda javob.ok xossasi kod 400 dan kiçik bölsa True qaytaradi, javob.raise_for_status() esa xato kodida istisno kötaradi.
json moduli: matn ↔ Python obyektlari
JSON — bu oddiy matn, lekin uning tuzilişi Python luğat va röyxatlariga juda öxşaydi. Standart kutubxonadagi json moduli ikki yönalişda işlaydi: json.loads() matnni Python obyektiga, json.dumps() esa Python obyektini matnga aylantiradi. Bu misol tarmoqsiz işlaydi:
import json
matn = '{"Ccy": "USD", "Rate": "12650.00", "Nominal": "1", "faol": true, "izoh": null}'
valyuta = json.loads(matn)
print(type(valyuta).__name__)
print(valyuta["Ccy"], float(valyuta["Rate"]) * 2)
print(valyuta["faol"], valyuta["izoh"])
hisobot = {"şahar": "Toşkent", "kurslar": [12650.0, 13700.0], "yangilandi": True}
print(json.dumps(hisobot, ensure_ascii=False))
print(json.dumps(hisobot, ensure_ascii=False, indent=2))
Natija:
dict
USD 25300.0
True None
{"şahar": "Toşkent", "kurslar": [12650.0, 13700.0], "yangilandi": true}
{
"şahar": "Toşkent",
"kurslar": [
12650.0,
13700.0
],
"yangilandi": true
}
Eʼtibor bering: JSONdagi true, false, null Python'da True, False, None ga aylandi. ensure_ascii=False özbekça harflarni \u02bb kabi kodlarga aylantirmasdan, öz holiça yoziş uçun kerak, indent=2 esa natijani öqişga qulay qiladi.
Faylga yoziş va fayldan öqiş uçun s harfisiz json.dump() va json.load() funksiyalari bor:
import json
from pathlib import Path
sozlamalar = {"asosiy_valyuta": "USD", "valyutalar": ["USD", "EUR", "RUB"]}
fayl = Path("sozlamalar.json")
with fayl.open("w", encoding="utf-8") as f:
json.dump(sozlamalar, f, ensure_ascii=False, indent=2)
with fayl.open(encoding="utf-8") as f:
oqilgan = json.load(f)
print(oqilgan == sozlamalar, oqilgan["valyutalar"])
Natija:
True ['USD', 'EUR', 'RUB']
Valyuta maʼlumotlarini qayta işlaş
Tarmoq kodini maʼlumotni qayta işlaş kodidan ajratiş yaxşi odat. Şunda hisob-kitob qismini internetsiz ham sinab köriş mumkin. Quyidagi misolda API javobiga öxşaş kiçik namuna röyxatdan foydalanamiz (kurslar öylab topilgan).
namuna = [
{"Ccy": "USD", "CcyNm_UZ": "AQŞ dollari", "Nominal": "1", "Rate": "12650.00", "Date": "24.10.2026"},
{"Ccy": "EUR", "CcyNm_UZ": "Yevro", "Nominal": "1", "Rate": "13700.50", "Date": "24.10.2026"},
{"Ccy": "RUB", "CcyNm_UZ": "Rossiya rubli", "Nominal": "1", "Rate": "155.40", "Date": "24.10.2026"},
{"Ccy": "TRY", "CcyNm_UZ": "Turk lirasi", "Nominal": "1", "Rate": "370.25", "Date": "24.10.2026"},
]
def kurslar_lugati(royxat: list[dict]) -> dict[str, float]:
"""{'USD': 12650.0, ...} körinişidagi luğat: 1 birlikning sömdagi narxi."""
return {v["Ccy"]: float(v["Rate"]) / int(v["Nominal"]) for v in royxat}
def somga(miqdor: float, valyuta: str, kurslar: dict[str, float]) -> float:
return miqdor * kurslar[valyuta]
def valyutaga(som: float, valyuta: str, kurslar: dict[str, float]) -> float:
return som / kurslar[valyuta]
kurslar = kurslar_lugati(namuna)
print(kurslar)
print(f"250 USD = {somga(250, 'USD', kurslar):,.0f} söm")
print(f"1 000 000 söm = {valyutaga(1_000_000, 'TRY', kurslar):,.2f} TRY")
Natija:
{'USD': 12650.0, 'EUR': 13700.5, 'RUB': 155.4, 'TRY': 370.25}
250 USD = 3,162,500 söm
1 000 000 söm = 2,700.88 TRY
Töliq ilova: valyuta kalkulyatori
Endi hammasini birlaştiramiz: kurslarni internetdan olamiz, xatolarni uşlaymiz va foydalanuvçiga natija körsatamiz. Har bir tarmoq sörovida timeout beriş şart: busiz server javob bermasa, dasturingiz çeksiz kutib qolişi mumkin.
import requests
URL = "https://cbu.uz/uz/arkhiv-kursov-valyut/json/"
def kurslarni_ol() -> tuple[dict[str, float], str]:
"""Markaziy bankdan kurslarni oladi. (kurslar, sana) qaytaradi."""
javob = requests.get(URL, timeout=10)
javob.raise_for_status() # 4xx/5xx bölsa, HTTPError kötaradi
royxat = javob.json()
kurslar = {v["Ccy"]: float(v["Rate"]) / int(v["Nominal"]) for v in royxat}
sana = royxat[0]["Date"] if royxat else "nomaʼlum"
return kurslar, sana
def main() -> None:
try:
kurslar, sana = kurslarni_ol()
except requests.exceptions.Timeout:
print("Server 10 soniya içida javob bermadi. Keyinroq urinib köring.")
return
except requests.exceptions.ConnectionError:
print("Internetga ulanib bölmadi. Aloqani tekşiring.")
return
except requests.exceptions.HTTPError as xato:
print("Server xato qaytardi:", xato)
return
except (ValueError, KeyError):
print("Javob formati kutilganidek emas.")
return
print(f"Markaziy bank kurslari ({sana})")
for kod in ("USD", "EUR", "RUB", "TRY", "KZT"):
if kod in kurslar:
print(f" 1 {kod} = {kurslar[kod]:>10,.2f} söm")
valyuta = input("Valyuta kodi (masalan, USD): ").strip().upper()
if valyuta not in kurslar:
print("Bunday valyuta topilmadi.")
return
miqdor = float(input(f"Neça {valyuta}? "))
print(f"{miqdor:,.2f} {valyuta} = {miqdor * kurslar[valyuta]:,.0f} söm")
if __name__ == "__main__":
main()
Bu yerda istisnolar tartibi muhim: requests.exceptions içidagi xatolar öziga xos, ValueError esa javob.json() notöğri matn olganda yoki float() aylantira olmaganda çiqadi. Har bir holatda foydalanuvçiga tuşunarli xabar beramiz.
Web scraping asoslari
Har bir sayt ham API taqdim etmaydi. Baʼzan kerakli maʼlumot faqat oddiy HTML sahifada böladi. Sahifadan maʼlumotni dastur yordamida ajratib oliş web scraping deyiladi. Bu iş uçun eng maşhur kutubxona — BeautifulSoup (bs4 paketi).
pip install requests beautifulsoup4
Avval qoidalar haqida. Scraping qilişdan oldin:
- Saytda rasmiy
APIbormi, tekşiring — u doim afzal. - Saytning foydalaniş şartlarini (
Terms of Service) öqing: baʼzi saytlar avtomatik yiğişni taqiqlaydi. robots.txtfaylini hurmat qiling: unda qaysi sahifalarni robotlar oçmasligi kerakligi yozilgan.- Serverni ortiqça yuklamang: sörovlar orasida pauza qiling, bir xil sahifani qayta-qayta yuklamang.
- Şaxsiy maʼlumotlarni yiğmang.
robots.txt qoidalarini standart kutubxonadagi urllib.robotparser bilan tekşiriş mumkin. Odatda set_url() va read() bilan faylni saytdan öqiysiz; quyida esa tarmoqsiz işlaşi uçun qoidalarni töğridan-töğri beramiz:
from urllib.robotparser import RobotFileParser
qoidalar = """
User-agent: *
Disallow: /admin/
Disallow: /savat/
Crawl-delay: 2
""".splitlines()
rp = RobotFileParser()
rp.parse(qoidalar)
for yol in ["/kitoblar/", "/admin/panel", "/savat/"]:
ruxsat = rp.can_fetch("MeningBotim", "https://kitob.example" + yol)
print(f"{yol:15} -> {'mumkin' if ruxsat else 'taqiqlangan'}")
print("Pauza:", rp.crawl_delay("MeningBotim"), "soniya")
Natija:
/kitoblar/ -> mumkin
/admin/panel -> taqiqlangan
/savat/ -> taqiqlangan
Pauza: 2 soniya
Endi BeautifulSoup bilan HTMLdan maʼlumot ajratamiz. Saytga sörov yubormaslik uçun kiçik kitob dökoni sahifasini satr körinişida beramiz. Haqiqiy loyihada bu satr örniga requests.get(url, timeout=10).text böladi.
from bs4 import BeautifulSoup
html = """
<html><body>
<h1>Kitob dökoni</h1>
<div class="kitob">
<h2>Ötkan kunlar</h2>
<span class="narx">65000</span>
</div>
<div class="kitob">
<h2>Mehrobdan çayon</h2>
<span class="narx">58000</span>
</div>
<a href="/kitoblar?sahifa=2">Keyingi sahifa</a>
</body></html>
"""
sahifa = BeautifulSoup(html, "html.parser")
print(sahifa.h1.get_text())
for kitob in sahifa.find_all("div", class_="kitob"):
nom = kitob.find("h2").get_text(strip=True)
narx = int(kitob.select_one(".narx").get_text())
print(f"{nom}: {narx:,} söm")
havola = sahifa.find("a")
print(havola["href"])
Kitob dökoni
Ötkan kunlar: 65,000 söm
Mehrobdan çayon: 58,000 söm
/kitoblar?sahifa=2
Asosiy metodlar: find() birinçi mos elementni, find_all() hammasini qaytaradi; select() va select_one() esa CSS selektorlari bilan işlaydi (.narx — narx klassli element). get_text() teg içidagi matnni, element["href"] esa atribut qiymatini beradi.
E-poçta yuboriş: smtplib
Python standart kutubxonasi bilan xat yuboriş ham mumkin. Xatning özini email.message.EmailMessage yordamida tuzamiz, uni yuborişni esa smtplib bajaradi. Xatni tuziş tarmoqsiz işlaydi:
from email.message import EmailMessage
xat = EmailMessage()
xat["Subject"] = "Bugungi valyuta kurslari"
xat["From"] = "bot@example.com"
xat["To"] = "dilnoza@example.com"
xat.set_content("1 USD = 12 650 söm\n1 EUR = 13 700 söm")
print(xat["Subject"])
print(xat["To"])
print(xat.get_content())
Natija:
Bugungi valyuta kurslari
dilnoza@example.com
1 USD = 12 650 söm
1 EUR = 13 700 söm
Yuboriş uçun poçta serveri (SMTP) manzili, port va parol kerak. Parolni heç qaçon kod içiga yozmang: kod GitHubga yuklanganda yoki döstingizga yuborilganda parol ham oşkor böladi. Uni muhit özgaruvçisida saqlang. Gmail kabi xizmatlarda oddiy parol emas, ikki bosqiçli tasdiqlaş yoqilgandan keyin yaratiladigan maxsus ilova paroli (App Password) işlatiladi.
export EMAIL_MANZIL="sizning.manzil@gmail.com"
export EMAIL_PAROL="ilova-paroli-shu-yerga"
import os
import smtplib
from email.message import EmailMessage
manzil = os.environ["EMAIL_MANZIL"]
parol = os.environ["EMAIL_PAROL"] # kod içida parol yöq!
xat = EmailMessage()
xat["Subject"] = "Bugungi valyuta kurslari"
xat["From"] = manzil
xat["To"] = "dilnoza@example.com"
xat.set_content("1 USD = 12 650 söm\n1 EUR = 13 700 söm")
try:
with smtplib.SMTP_SSL("smtp.gmail.com", 465, timeout=20) as server:
server.login(manzil, parol)
server.send_message(xat)
print("Xat yuborildi.")
except smtplib.SMTPAuthenticationError:
print("Login yoki ilova paroli notöğri.")
except (smtplib.SMTPException, OSError) as xato:
print("Xat yuborilmadi:", xato)
SMTP_SSL 465-port orqali boşidanoq şifrlangan ulaniş oçadi. Baʼzi serverlar 587-portda smtplib.SMTP(...) va undan keyin server.starttls() çaqiruvini talab qiladi — poçta xizmatingiz sozlamalariga qarang. with bloki tugaganda ulaniş avtomatik yopiladi.
Xulosa
HTTP— mijoz sörov yuboradi, server holat kodi, sarlavhalar va tana bilan javob beradi;2xxmuvaffaqiyat,4xxmijoz xatosi,5xxserver xatosi.requests.get(url, timeout=...)bilan maʼlumot olinadi;raise_for_status()xato kodlarini istisnoga aylantiradi.json.loads()/json.dumps()matn bilan,json.load()/json.dump()fayl bilan işlaydi; özbekça matn uçunensure_ascii=False.- Markaziy bank
APIsidaCcy,Rate,Nominal,Datemaydonlari bor;Ratesatr, unifloat()ga aylantiring. - Scraping qilişdan oldin
API, foydalaniş şartlari varobots.txtni tekşiring;BeautifulSoupbilanfind,find_all,selectişlatiladi. - Xat
EmailMessagebilan tuziladi vasmtplibbilan yuboriladi; parol faqat muhit özgaruvçisida saqlanadi.
Maşqlar
jsonmodulidan foydalanib, talabalar baholari luğatini ({"Aziza": [5, 4, 5], ...}) har bir talabaning örtaça bahosi bilan birga çiroyliJSONmatnga aylantiring.
Yeçim
import json
baholar = {"Aziza": [5, 4, 5], "Bekzod": [3, 4, 4], "Gulnora": [5, 5, 5]}
natija = {ism: {"baholar": b, "orta": round(sum(b) / len(b), 2)} for ism, b in baholar.items()}
print(json.dumps(natija, ensure_ascii=False, indent=2))
- Valyuta kurslari luğatini (
{"USD": 12650.0, "EUR": 13700.5, ...}) olib, eng qimmat va eng arzon valyutani hamda ikki valyuta orasidagi kross-kursni (masalan, 1 EUR neça USD) hisoblaydigan funksiyalar yozing.
Yeçim
kurslar = {"USD": 12650.0, "EUR": 13700.5, "RUB": 155.4, "TRY": 370.25}
def kross_kurs(dan: str, ga: str, kurslar: dict[str, float]) -> float:
return kurslar[dan] / kurslar[ga]
eng_qimmat = max(kurslar, key=kurslar.get)
eng_arzon = min(kurslar, key=kurslar.get)
print("Eng qimmat:", eng_qimmat, "| Eng arzon:", eng_arzon)
print(f"1 EUR = {kross_kurs('EUR', 'USD', kurslar):.4f} USD")
print(f"1 USD = {kross_kurs('USD', 'TRY', kurslar):.2f} TRY")
holat_matni(kod)funksiyasinimatchyordamida yozing: uHTTPholat kodiga qarab “Muvaffaqiyat”, “Yönaltiriş”, “Mijoz xatosi”, “Server xatosi” yoki “Nomaʼlum” qaytarsin.
Yeçim
def holat_matni(kod: int) -> str:
match kod // 100:
case 2:
return "Muvaffaqiyat"
case 3:
return "Yönaltiriş"
case 4:
return "Mijoz xatosi"
case 5:
return "Server xatosi"
case _:
return "Nomaʼlum"
for kod in (200, 301, 404, 503, 99):
print(kod, holat_matni(kod))
- Valyuta kalkulyatorini kengaytiring: kurslarni olganda ularni
kurslar_kesh.jsonfayliga saqlang, internet bölmasa esa oxirgi saqlangan kurslardan foydalaning va bu haqda ogohlantiring.
Yeçim
import json
from pathlib import Path
import requests
URL = "https://cbu.uz/uz/arkhiv-kursov-valyut/json/"
KESH = Path("kurslar_keş.json")
def kurslarni_ol() -> dict[str, float]:
try:
javob = requests.get(URL, timeout=10)
javob.raise_for_status()
kurslar = {v["Ccy"]: float(v["Rate"]) / int(v["Nominal"]) for v in javob.json()}
KESH.write_text(json.dumps(kurslar, indent=2), encoding="utf-8")
return kurslar
except (requests.exceptions.RequestException, ValueError, KeyError):
if KESH.exists():
print("Ogohlantiriş: internet yöq, saqlangan kurslar işlatilmoqda.")
return json.loads(KESH.read_text(encoding="utf-8"))
raise
kurslar = kurslarni_ol()
print(f"1 USD = {kurslar['USD']:,.2f} söm")