Əgər bu mühazirəyə qədər gəlib çatmısınızsa, demək ki, artıq veb-scraping-in necə işlədiyini və HTML-dən lazım olan məlumatları çıxarmaq üçün möhtəşəm BeautifulSoup
-dan necə istifadə etməyi yaxşı başa düşürsünüz. Amma bilin ki, veb-scraping dünyasında hər şey kitabda yazıldığı kimi hamar deyil. Bəzən məlumat toplamaq arzumuz səhvlərlə mübarizəyə çevrilir, ona görə gəlin görək hansı çətinlikləri keçib scraper-i maksimum dayanıqlı edə bilərik.
1. Web-scrapingdə ümumi xətalar
404 xətası və digər HTTP xətaları
Klassik bir problem: səhifəni almağa çalışırsınız, amma kontent əvəzinə sizə qürurla "404 Not Found" qaytarılır. Bu səhifənin silinməsi və ya köçürülməsi səbəbindən baş verə bilər. Digər yayılmış HTTP xətalarına 403 (Forbidden), 500 (Internal Server Error) və 503 (Service Unavailable) daxildir.
HTML strukturunun dəyişməsi
Məlumatların çıxarılması üçün bir ton vaxt sərf etmisiniz, amma ertəsi gün sayt bir az "parıldamaq" qərarına gəlib HTML strukturunu dəyişdirir. Oyy, yenidən hər şeyi yazmaq lazım!
Sorğu sayına məhdudiyyətlər
Bəzi saytlar, onlara bütün gün web-scraperlər "hucum edəndə" bəzi anormal hallar sezirlər. Ən yaxşı halda, sizi müəyyən bir müddətlik blok edərlər, ən pis halda isə daimi olaraq!
Gözləmə müddəti və timeout
Bəzən səhifələr uzun müddət yüklənir və ssenariniz gözləmə vaxtını keçərsə çökə bilər.
2. Səhvlərin işlənməsi metodları
try-except istifadəsi
Sizin skriptlər istənilən gözlənilməz vəziyyətdən çökməməlidir. try-except
bloklarının əlavə edilməsi səhvləri tutmağa kömək edir və sizin web-scraper-iniz heç nə olmamış kimi işləməyə davam edir.
import requests
from bs4 import BeautifulSoup
url = 'http://example.com/some-nonexistent-page'
try:
response = requests.get(url)
response.raise_for_status() # Pis cavablar üçün HTTPError yaradır
except requests.exceptions.HTTPError as errh:
print("HTTP Xətası:", errh)
except requests.exceptions.ConnectionError as errc:
print("Bağlantı Xətası:", errc)
except requests.exceptions.Timeout as errt:
print("Vaxt Aşımı Xətası:", errt)
except requests.exceptions.RequestException as err:
print("OOps: Başqa bir şey", err)
Yaxşı bir skript təkcə istisnanı tutmur - onun hər növ səhvə cavab tədbiri var. IP-dən ban edildiniz - başqa bir proxy-yə keçdiniz, sayt çöksə - bu zaman başqa birini parse edirsiniz. Əgər səhifədə olması lazım olan elementlər tapılmasa, scraper sahibinə parsing skriptini yeniləmək lazım olduğunu bildirmək və ona email göndərmək olar.
Loglama
"Bu loglar nəyə görə lazımdır?" — deyə soruşarsınız. Çünki loglar sizin ikinci görmə bacarığınızdır. Onlar sizə nə baş verdiyini başa düşməyə və səhvi mümkün qədər tez düzəltməyə kömək edəcək.
import logging
logging.basicConfig(filename='scraper.log', level=logging.INFO)
try:
# Sizin scraping kodunuz
pass
except Exception as e:
logging.error("İstisna baş verdi", exc_info=True)
Timeout və retry istifadəsi
Bəzən, sizə lazım olan hər şey bir az gözləmək və yenidən cəhd etməkdir. Bu məqsəd üçün timeout və retry-lər çox uyğundur.
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
except requests.exceptions.Timeout:
print("Vaxt aşımı baş verdi. Yenidən cəhd edilir...")
# Sorğunu təkrarlayın və ya başqa bir əməliyyat yerinə yetirin
3. Dayanıqlı scraping nümunələri
Səhv idarəsi ilə sadə scraper
Gəlin bəzi ümumi səhvləri idarə edə bilən kiçik, lakin etibarlı bir scraper yaradaq.
import requests
from bs4 import BeautifulSoup
import time
import logging
logging.basicConfig(filename='scraper.log', level=logging.INFO)
url = 'http://example.com/some-nonexistent-page'
def fetch_html(url):
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
return response.text
except requests.exceptions.HTTPError as errh:
logging.error("HTTP Səhv: %s", errh)
except requests.exceptions.ConnectionError as errc:
logging.error("Bağlantı Səhvi: %s", errc)
except requests.exceptions.Timeout as errt:
logging.warning("Vaxt aşımı baş verdi. Yenidən cəhd edilir...")
time.sleep(1) # Bir az gözləyib yenidən cəhd edirik
return fetch_html(url)
except requests.exceptions.RequestException as err:
logging.error("Ups: Başqa bir şey oldu %s", err)
return None
html_content = fetch_html(url)
if html_content:
soup = BeautifulSoup(html_content, 'html.parser')
# Məlumat çıxarmaq üçün kodunuz
else:
print("Səhifə məzmununu əldə etmək mümkün olmadı.")
Məlumatları hissə-hissə saxlamaq
Uğursuzluq halında artıq çıxarılmış məlumatları itirməmək üçün onları hissə-hissə saxlayın. Məsələn, əgər bir neçə səhifədən məlumatları çıxarırsınızsa, nəticələri irəlilədikcə saxlamanız, məlumat itkisinin riskini minimuma endirər.
import csv
def save_to_csv(data, filename='data.csv'):
with open(filename, mode='a', newline='') as file:
writer = csv.writer(file)
writer.writerow(data)
Beləliklə, skriptiniz işin ortasında dayansa belə, bütün məlumatları itirməyəcəksiniz və son saxlanılan məlumatdan davam edə biləcəksiniz.
Pars etdiyiniz səhifə qismən dəyişə bilər və məlumatların böyük hissəsi hələ də əlçatan olacaq. Əgər çox az bir hissə mövcud deyilsə, pars etməkdən imtina edib dəyərli məlumatları itirmək yaxşı olmazdı.
GO TO FULL VERSION