Python Web scraping yapan bot Sahibinden.net tarafından engelleniyor

Katılım
8 Eylül 2018
Mesajlar
9.719
Makaleler
8
Çözümler
230
Yer
İstanbul
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.

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()
 
Hocam giriş yapmak için Selenium'da Cookie'leri ve Session'ları kullanarak giriş bilgilerini saklayabilirsin. Zaten bunu yaparsan sürekli giriş yapmak zorunda kalmazsın. Giriş yaptıktan sonra cookies ile oturumu koruyarak otomatik olarak ilan detaylarına girebilirsin.
 
Hocam giriş yapmak için Selenium'da Cookie'leri ve Session'ları kullanarak giriş bilgilerini saklayabilirsin. Zaten bunu yaparsan sürekli giriş yapmak zorunda kalmazsın. Giriş yaptıktan sonra cookies ile oturumu koruyarak otomatik olarak ilan detaylarına girebilirsin.

Gece yarısı dönüş yapabilirim.
 
İmport undetected_chromedriver as UC.
İmport time.

Options = uc.ChromeOptions()
Options. Add_argument('--no-sandbox')
Options. Add_argument('--disable-blink-features = automationcontrolled')

Driver = UC. Chrome(options = options)
driver.get("Example Domain")
Time. Sleep(10)
driver.quit()

Koda çok bakamadım bu işe yaramaz mı?
 
İmport undetected_chromedriver as UC.
İmport time.

Options = uc.ChromeOptions()
Options. Add_argument('--no-sandbox')
Options. Add_argument('--disable-blink-features = automationcontrolled')

Driver = UC. Chrome(options = options)
Driver. Get("Example Domain")
Time. Sleep(10)
driver.quit()

Koda çok bakamadım bu işe yaramaz mı?

Bu olabilir galiba işe yarar.
 
Nodriver veya botasaurus ile Google'dan yönelmiş gibi gösterebilirsin.

 
İmport undetected_chromedriver as UC.
İmport time.

Options = uc.ChromeOptions()
Options. Add_argument('--no-sandbox')
Options. Add_argument('--disable-blink-features = automationcontrolled')

Driver = UC. Chrome(options = options)
driver.get("Example Domain")
Time. Sleep(10)
driver.quit()

Koda çok bakamadım bu işe yaramaz mı?

No module named 'undetected_chromedriver' hatası alıyorum. Python 3.12 kullanıyorum. undetected_chromedriver'i terminal üzerinden kurdum, işe yaramadı.

Hocam giriş yapmak için Selenium'da Cookie'leri ve Session'ları kullanarak giriş bilgilerini saklayabilirsin. Zaten bunu yaparsan sürekli giriş yapmak zorunda kalmazsın. Giriş yaptıktan sonra cookies ile oturumu koruyarak otomatik olarak ilan detaylarına girebilirsin.

Sahibinden.net hesabım Google bağlı ve çoklu hesapları algılayabiliyor. Bu da işe yaramıyor haliyle. Belki bir arkadaşımın hesabına erişip deneyebilirim.

Nodriver veya botasaurus ile Google'dan yönelmiş gibi gösterebilirsin.


Vize sınavlarımdan ötürü buna hafta içi detaylı bakıp döneceğim.
 
Son düzenleme:
Hocam bir çözüm bulabildiniz mi?
Ben de sahibinden'i scrape etmeye çalışıyorum, hem sayfa yüklenirkenki hem de kullanıcı girişindeki bot kontrolünü geçebiliyorum, ama bir süre sonra sahibinden hesabı geçici ban yiyor, 1-2 saat sonra kalkıyor.
 
Hocam bir çözüm bulabildiniz mi?
Ben de sahibinden'i scrape etmeye çalışıyorum, hem sayfa yüklenirkenki hem de kullanıcı girişindeki bot kontrolünü geçebiliyorum, ama bir süre sonra sahibinden hesabı geçici ban yiyor, 1-2 saat sonra kalkıyor.

Sahibinden'i scrape etmek için API key almanız lazım. O da biraz cep yakıyor. Ben verileri elle çekmiştim. Bilgileri Excel formatına dönüştüren bir kod yazarak +5 bin civarı veri çekmiştim. 1 ayımı rahat aldı.
 
Hocam bir çözüm bulabildiniz mi?
Ben de sahibinden'i scrape etmeye çalışıyorum, hem sayfa yüklenirkenki hem de kullanıcı girişindeki bot kontrolünü geçebiliyorum, ama bir süre sonra sahibinden hesabı geçici ban yiyor, 1-2 saat sonra kalkıyor.
Sahibinden bu scrape edilmemek için çok uğraşıyor.

Farklı bir yöntem önereyim; Basit bir js ile browser extension yazın. Extension üzerinden veri çekmeye çalışın. Extension sizin yerinize linkleri açar, tablodan verileri vs çok rahat alırsınız. Max 1 saat sürmez şu extension yazmak.
Tek olayı arkaplanda çalıştıramayacaksınız. Kendiniz sahibindene girin, 2 3 ilanlara bakın. Sonra extension çalıştırın gerisini o halleder. Manuel kontrol gerekiyor.
 

Technopat Haberler

Geri
Yukarı