Sahibinden.net'te Selenium kullanarak ilan verisi çekmeye çalışıyorum. Başta her şey düzgün çalışsa da yaklaşık 10-15 ilan sonrası site bot olduğumu fark edip güvenlik önlemiyle (CAPTCHA veya yönlendirme) engelliyor. Ayrıca bazı ilanların detayına ulaşmak için giriş yapmam gerekiyor. Rastgele bekleme süreleri, user-agent değişimi gibi yöntemleri uygulamama rağmen bu kısıtlamalarla karşılaşmaya devam ediyorum.
Amacım, hem giriş yapılmasını sağlamak hem de sistemin bot olduğumu anlamasını engellemek. Ancak bu süreci otomatikleştirirken etik sınırları da aşmamaya çalışıyorum.
Veri çekme amacım tamamen eğitim için.
Bu konuda çözüm arıyorum, yardımcı olanlara teşekkürler.
Amacım, hem giriş yapılmasını sağlamak hem de sistemin bot olduğumu anlamasını engellemek. Ancak bu süreci otomatikleştirirken etik sınırları da aşmamaya çalışıyorum.
Veri çekme amacım tamamen eğitim için.
Bu konuda çözüm arıyorum, yardımcı olanlara teşekkürler.
Python:
import pandas as pd.
from selenium import webdriver.
from selenium.webdriver.chrome.service import Service.
from selenium.webdriver.chrome.options import Options.
from selenium.webdriver.common.by import By.
from selenium.webdriver.support.ui import WebDriverWait.
from selenium.webdriver.support import expected_conditions as EC.
from bs4 import BeautifulSoup as bs.
import time.
import random.
import logging.
# Logging ayarları.
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Chrome ayarları.
options = Options()
options.add_argument("--start-maximized")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
# Daha fazla user-agent
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15"
]
# WebDriver yolu.
driver_path = r"C:\Users\Emre\Desktop\chromedriver-win64\chromedriver.exe"
service = Service(driver_path)
browser = webdriver.Chrome(service=service, options=options)
# İlan linkleri ve detaylar için listeler.
base_url = "https://www.sahibinden.com/satilik/samsun-atakum"
linkdata = []
adinfos = []
# Sayfalama ile ilan linklerini toplama.
def collect_links():
offset = 1 # 0'dan başlanmalı.
max_offsets = 2 # Test için 1 sayfa, artırılabilir.
while len(linkdata) < 10 and offset <= max_offsets * 20:
url = f"{base_url}?pagingOffset={offset}"
try:
# Her sayfada yeni user-agent
options.add_argument(f"--user-agent={random.choice(user_agents)}")
browser.get(url)
time.sleep(random.uniform(5, 10)) # Daha uzun başlangıç bekleme.
# Sayfada insan gibi gezinme.
browser.execute_script("window.scrollTo(0, document.body.scrollHeight / 3);")
time.sleep(random.uniform(2, 5))
browser.execute_script("window.scrollTo(0, document.body.scrollHeight / 2);")
time.sleep(random.uniform(2, 5))
soup = bs(browser.page_source, "lxml")
links = soup.find_all("a", {"class": "classifiedTitle"})
if not links:
logging.info("Daha fazla ilan bulunamadı.")
break.
# Daha az link topla ve rastgele seç.
selected_links = random.sample(links, min(5, len(links))) # Her sayfadan max 5 link.
for link in selected_links:
href = link.get("href")
if href and href not in linkdata:
full_url = "https://www.sahibinden.com" + href.
linkdata.append(full_url)
logging.info(f"Offset {offset} tarandı. Toplam {len(linkdata)} ilan linki toplandı.")
offset += 20.
time.sleep(random.uniform(10, 20)) # Sayfalar arasında daha uzun bekleme.
except Exception as e:
logging.error(f"Link toplama hatası (Offset {offset}): {e}")
time.sleep(random.uniform(20, 30)) # Hata sonrası uzun bekleme.
continue.
# İlan detaylarını çekme.
def collect_details():
counter = 1
for url in linkdata:
retries = 3
while retries > 0:
try:
options.add_argument(f"--user-agent={random.choice(user_agents)}")
browser.get(url)
WebDriverWait(browser, 20).until( # Daha uzun bekleme süresi.
EC.presence_of_element_located((By.XPATH, '//*[@id="classifiedDetail"]/div/div[2]/div[2]'))
)
ilan_url = url.
# Sayfada gezinme simülasyonu.
browser.execute_script("window.scrollTo(0, 300);")
time.sleep(random.uniform(2, 4))
logging.info(f"\n-----------------------------------\n{counter}")
logging.info(f"Link: {ilan_url}")
# Fiyat.
price = browser.find_element(By.XPATH, '//*[@id="classifiedDetail"]/div/div[2]/div[2]').text.split("\n")[0].strip()
logging.info(f"Fiyat: {price}")
# Şehir, ilçe, mahalle.
try:
location = browser.find_element(By.XPATH, '//*[@id="classifiedDetail"]/div/div[2]/div[2]/h2').text.strip()
sehir, ilce, mahalle = location.split(" / ") if " / " in location else ("-", "-", location)
except:
sehir = ilce = mahalle = "-"
logging.info(f"Şehir: {sehir}")
logging.info(f"İlçe: {ilce}")
logging.info(f"Mahalle: {mahalle}")
# Varsayılan değerler.
ilan_no = ilan_tarihi = emlak_tipi = brut_m2 = net_m2 = oda_sayisi = bina_yasi = bulundu_kat = kat_sayisi = isitma = banyo_sayisi = mutfak = balkon = asansor = otopark = esyali = kullanim_durumu = site_icerisinde = site_adi = aidat = krediye_uygun = tapu_durumu = kimden = takas = "-"
# Detaylı bilgiler.
details_container = browser.find_element(By.XPATH, '//*[@id="classifiedDetail"]/div/div[2]/div[2]/ul')
detail_items = details_container.find_elements(By.XPATH, ".//li")
for item in detail_items:
detail = item.text.strip()
if "İlan No" in detail: ilan_no = detail.split("İlan No")[1].strip()
if "İlan Tarihi" in detail: ilan_tarihi = detail.split("İlan Tarihi")[1].strip()
if "Emlak Tipi" in detail: emlak_tipi = detail.split("Emlak Tipi")[1].strip()
if "m² (Brüt)" in detail: brut_m2 = detail.split("m² (Brüt)")[1].strip()
if "m² (Net)" in detail: net_m2 = detail.split("m² (Net)")[1].strip()
if "Oda Sayısı" in detail: oda_sayisi = detail.split("Oda Sayısı")[1].strip()
if "Bina Yaşı" in detail: bina_yasi = detail.split("Bina Yaşı")[1].strip()
if "Bulunduğu Kat" in detail: bulundu_kat = detail.split("Bulunduğu Kat")[1].strip()
if "Kat Sayısı" in detail: kat_sayisi = detail.split("Kat Sayısı")[1].strip()
if "Isıtma" in detail: isitma = detail.split("Isıtma")[1].strip()
if "Banyo Sayısı" in detail: banyo_sayisi = detail.split("Banyo Sayısı")[1].strip()
if "Mutfak" in detail: mutfak = detail.split("Mutfak")[1].strip()
if "Balkon" in detail: balkon = detail.split("Balkon")[1].strip()
if "Asansör" in detail: asansor = detail.split("Asansör")[1].strip()
if "Otopark" in detail: otopark = detail.split("Otopark")[1].strip()
if "Eşyalı" in detail: esyali = detail.split("Eşyalı")[1].strip()
if "Kullanım Durumu" in detail: kullanim_durumu = detail.split("Kullanım Durumu")[1].strip()
if "Site İçerisinde" in detail: site_icerisinde = detail.split("Site İçerisinde")[1].strip()
if "Site Adı" in detail: site_adi = detail.split("Site Adı")[1].strip()
if "Aidat (TL)" in detail: aidat = detail.split("Aidat (TL)")[1].strip()
if "Krediye Uygun" in detail: krediye_uygun = detail.split("Krediye Uygun")[1].strip()
if "Tapu Durumu" in detail: tapu_durumu = detail.split("Tapu Durumu")[1].strip()
if "Kimden" in detail: kimden = detail.split("Kimden")[1].strip()
if "Takas" in detail: takas = detail.split("Takas")[1].strip()
# Konsolda göster.
logging.info(f"İlan No: {ilan_no}")
logging.info(f"İlan Tarihi: {ilan_tarihi}")
logging.info(f"Emlak Tipi: {emlak_tipi}")
logging.info(f"m² (Brüt): {brut_m2}")
logging.info(f"m² (Net): {net_m2}")
logging.info(f"Oda Sayısı: {oda_sayisi}")
logging.info(f"Bina Yaşı: {bina_yasi}")
logging.info(f"Bulunduğu Kat: {bulundu_kat}")
logging.info(f"Kat Sayısı: {kat_sayisi}")
logging.info(f"Isıtma: {isitma}")
logging.info(f"Banyo Sayısı: {banyo_sayisi}")
logging.info(f"Mutfak: {mutfak}")
logging.info(f"Balkon: {balkon}")
logging.info(f"Asansör: {asansor}")
logging.info(f"Otopark: {otopark}")
logging.info(f"Eşyalı: {esyali}")
logging.info(f"Kullanım Durumu: {kullanim_durumu}")
logging.info(f"Site İçerisinde: {site_icerisinde}")
logging.info(f"Site Adı: {site_adi}")
logging.info(f"Aidat (TL): {aidat}")
logging.info(f"Krediye Uygun: {krediye_uygun}")
logging.info(f"Tapu Durumu: {tapu_durumu}")
logging.info(f"Kimden: {kimden}")
logging.info(f"Takas: {takas}")
# Verileri dictionary olarak sakla.
advert_infos = {
"Link": ilan_url,
"Fiyat": price,
"Şehir": sehir,
"İlçe": ilce,
"Mahalle": mahalle,
"İlan No": ilan_no,
"İlan Tarihi": ilan_tarihi,
"Emlak Tipi": emlak_tipi,
"m² (Brüt)": brut_m2,
"m² (Net)": net_m2,
"Oda Sayısı": oda_sayisi,
"Bina Yaşı": bina_yasi,
"Bulunduğu Kat": bulundu_kat,
"Kat Sayısı": kat_sayisi,
"Isıtma": isitma,
"Banyo Sayısı": banyo_sayisi,
"Mutfak": mutfak,
"Balkon": balkon,
"Asansör": asansor,
"Otopark": otopark,
"Eşyalı": esyali,
"Kullanım Durumu": kullanim_durumu,
"Site İçerisinde": site_icerisinde,
"Site Adı": site_adi,
"Aidat (TL)": aidat,
"Krediye Uygun": krediye_uygun,
"Tapu Durumu": tapu_durumu,
"Kimden": kimden,
"Takas": takas.
}
adinfos.append(advert_infos)
counter += 1
time.sleep(random.uniform(10, 20)) # İlanlar arasında daha uzun bekleme.
break.
except Exception as e:
logging.error(f"Hata alındı (İlan {counter}, Deneme {4-retries}): {e}")
retries -= 1
if retries > 0:
time.sleep(random.uniform(20, 40)) # Hata sonrası daha uzun bekleme.
else:
logging.error(f"İlan {counter} için tüm denemeler başarısız.")
break.
# Excel'e kaydet.
try:
logging.info("\nVeri çekme işlemi tamamlandı...\nÇekilen veriler Excel dosyasına dönüştürülüyor...")
df_data = pd.DataFrame(adinfos)
df_data.to_excel("sahibinden_atakum_ilan_detaylari.xlsx", index=False)
logging.info("\nVeriler Excel dosyasına dönüştürüldü...")
except Exception as e:
logging.error(f"Excel'e kaydetme hatası: {e}")
# Ana çalıştırma.
def main():
try:
collect_links()
collect_details()
finally:
browser.quit()
logging.info("Program sonlandı.")
if __name__ == "__main__":
main()