122 lines
5.4 KiB
Python
122 lines
5.4 KiB
Python
"""Internet aramasi ve sayfa okuma: Codex'e sonradan eklenen modeller icin (11 Ekim 2026).
|
||
|
||
Codex'in yerlesik web aramasi OpenAI sunucusunda calisir ve yalniz Codex'in kendi modellerine verilir; kopru onu
|
||
ek modele giden arac listesinden atar. Ek model aramayi bu betigi kabuk araciyla calistirarak yapar (internet.py
|
||
modele komutu soyler). Anahtar gerekmez; yalniz standart kitaplik.
|
||
|
||
python ara.py ara "sorgu" [--adet 8]
|
||
python ara.py oku <adres> [--en-cok 8000]
|
||
"""
|
||
import argparse
|
||
import html
|
||
import re
|
||
import sys
|
||
import urllib.parse
|
||
import urllib.request
|
||
import xml.etree.ElementTree as ET
|
||
|
||
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36"
|
||
ARAMA = "https://html.duckduckgo.com/html/?"
|
||
SURE = 25
|
||
EN_COK_BAYT = 3_000_000
|
||
|
||
|
||
def indir(adres, sure=SURE):
|
||
adres = urllib.parse.quote(adres, safe=":/?#[]@!$&'()*+,;=%~") # Turkce harfli adres ("/wiki/Türkiye")
|
||
istek = urllib.request.Request(adres, headers={"User-Agent": UA, "Accept-Language": "tr,en;q=0.8"})
|
||
with urllib.request.urlopen(istek, timeout=sure) as yanit:
|
||
ham = yanit.read(EN_COK_BAYT)
|
||
kodlama = yanit.headers.get_content_charset() or "utf-8"
|
||
tur = yanit.headers.get_content_type()
|
||
try:
|
||
return ham.decode(kodlama, "replace"), tur
|
||
except LookupError:
|
||
return ham.decode("utf-8", "replace"), tur
|
||
|
||
|
||
def _duz(parca):
|
||
return re.sub(r"\s+", " ", html.unescape(re.sub(r"<[^>]+>", "", parca))).strip()
|
||
|
||
|
||
def sonuclari_coz(sayfa, adet=8):
|
||
"""Arama sayfasindan [(baslik, adres, ozet)]."""
|
||
cikti = []
|
||
for blok in re.split(r'<div[^>]+class="[^"]*\bresult\b[^"]*"', sayfa)[1:]:
|
||
bag = re.search(r'<a[^>]+class="result__a"[^>]+href="([^"]+)"[^>]*>(.*?)</a>', blok, re.S)
|
||
if not bag:
|
||
continue
|
||
adres = html.unescape(bag.group(1))
|
||
ic = re.search(r"[?&]uddg=([^&]+)", adres)
|
||
if ic:
|
||
adres = urllib.parse.unquote(ic.group(1))
|
||
if adres.startswith("//"):
|
||
adres = "https:" + adres
|
||
if "duckduckgo.com/y.js" in adres: # reklam
|
||
continue
|
||
ozet = re.search(r'class="result__snippet"[^>]*>(.*?)</a>', blok, re.S)
|
||
cikti.append((_duz(bag.group(2)), adres, _duz(ozet.group(1)) if ozet else ""))
|
||
if len(cikti) >= adet:
|
||
break
|
||
return cikti
|
||
|
||
|
||
def metne_cevir(sayfa):
|
||
"""HTML -> okunur duz metin (betik, bicim ve gezinme kisimlari atilir)."""
|
||
sayfa = re.sub(r"(?is)<(script|style|noscript|svg|nav|footer|header|form|iframe)\b.*?</\1>", " ", sayfa)
|
||
sayfa = re.sub(r"(?is)<!--.*?-->", " ", sayfa)
|
||
sayfa = re.sub(r"(?i)<(br|/p|/div|/li|/h[1-6]|/tr)\b[^>]*>", "\n", sayfa)
|
||
metin = html.unescape(re.sub(r"<[^>]+>", " ", sayfa))
|
||
satirlar = [re.sub(r"[ \t\r\f\v]+", " ", s).strip() for s in metin.split("\n")]
|
||
return "\n".join(s for s in satirlar if s)
|
||
|
||
|
||
def ara(sorgu, adet=8, indirici=indir):
|
||
sayfa, _ = indirici(ARAMA + urllib.parse.urlencode({"q": sorgu}))
|
||
sonuc = sonuclari_coz(sayfa, adet)
|
||
if not sonuc:
|
||
if 'no-results' in sayfa.lower() or 'no results found' in sayfa.lower():
|
||
return "Sonuç bulunamadı. En fazla bir farklı sorgu deneyebilirsin."
|
||
# DDG bot kontrolünü/bozuk HTML'yi sonuç yok diye göstermeyiz. Tek yedek istek.
|
||
try:
|
||
rss, _ = indirici('https://www.bing.com/search?' + urllib.parse.urlencode({'format': 'rss', 'q': sorgu}))
|
||
kok = ET.fromstring(rss)
|
||
if kok.tag != 'rss' or kok.find('channel') is None:
|
||
raise ValueError('RSS arama yanıtı değil')
|
||
sonuc = [(i.findtext('title') or '', i.findtext('link') or '', _duz(i.findtext('description') or ''))
|
||
for i in kok.findall('./channel/item')
|
||
if (i.findtext('link') or '').startswith(('https://', 'http://'))][:adet]
|
||
except (ValueError, ET.ParseError, OSError) as hata:
|
||
raise RuntimeError('Arama hizmeti engellendi veya yanıtı okunamadı; sorguları değiştirerek tekrar etme.') from hata
|
||
if not sonuc:
|
||
return "Sonuç bulunamadı. En fazla bir farklı sorgu deneyebilirsin."
|
||
return "\n\n".join(f"{i}. {b}\n {a}\n {o}" for i, (b, a, o) in enumerate(sonuc, 1))
|
||
|
||
|
||
def oku(adres, en_cok=8000, indirici=indir):
|
||
if not re.match(r"https?://", adres):
|
||
adres = "https://" + adres
|
||
sayfa, tur = indirici(adres)
|
||
metin = metne_cevir(sayfa) if "html" in tur or "<html" in sayfa[:2000].lower() else sayfa
|
||
if len(metin) > en_cok:
|
||
metin = metin[:en_cok] + f"\n[... kesildi: {len(metin)} karakterin ilk {en_cok} karakteri]"
|
||
return metin or "Sayfada okunur metin bulunamadı."
|
||
|
||
|
||
def main(argv=None):
|
||
p = argparse.ArgumentParser(description="Internet aramasi ve sayfa okuma")
|
||
alt = p.add_subparsers(dest="is_", required=True)
|
||
a = alt.add_parser("ara"); a.add_argument("sorgu", nargs="+"); a.add_argument("--adet", type=int, default=8)
|
||
o = alt.add_parser("oku"); o.add_argument("adres"); o.add_argument("--en-cok", type=int, default=8000)
|
||
s = p.parse_args(argv)
|
||
try:
|
||
metin = ara(" ".join(s.sorgu), max(1, min(s.adet, 20))) if s.is_ == "ara" else oku(s.adres, max(500, s.en_cok))
|
||
kod = 0
|
||
except Exception as e:
|
||
metin, kod = f"Hata: {type(e).__name__}: {e}", 1
|
||
sys.stdout.buffer.write((metin + "\n").encode("utf-8", "replace"))
|
||
return kod
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|