Veri toplamaya yönelik bu yaklaşım her ne kadar iyi görünse de, birçok web sitesi tarafından hoş karşılanmaz ve kazıma işlemini takip etmenin IP'mizin yasaklanması gibi sonuçları vardır.
Olumlu bir not olarak, proxy hizmetleri bu sonuçtan kaçınmaya yardımcı olur. Çevrimiçi veri toplarken farklı bir IP'ye bürünmemizi sağlarlar ve bu ne kadar güvenli görünse de birden fazla proxy kullanmak daha iyidir. Kazıma sırasında birden fazla proxy kullanmak, web sitesi ile etkileşimin rastgele görünmesini sağlar ve güvenliği artırır.
Bu kılavuz için hedef web sitesi (kaynak) bir çevrimiçi kitapçıdır. Kitaplar için bir e-ticaret web sitesini taklit eder. Üzerinde adı, fiyatı ve bulunabilirliği olan kitaplar bulunmaktadır. Bu kılavuz, döndürülen verileri düzenlemeye değil, proxy'leri döndürmeye odaklandığından, döndürülen veriler yalnızca konsolda sunulacaktır.
Proxy'leri döndürmeye ve web sitesini kazımaya yardımcı olacak işlevleri kodlamaya başlamadan önce bazı Python modüllerini yükleyin ve dosyamıza aktarın.
pip install requests beautifulSoup4 lxml
Bu kazıma betiği için gereken 5 Python modülünden 3'ü yukarıdaki komut kullanılarak kurulabilir. Requests web sitesine HTTP isteği göndermemizi sağlar, beautifulSoup4 istekler tarafından sağlanan sayfanın HTML'sinden bilgi çıkarmamızı sağlar ve LXML bir HTML ayrıştırıcısıdır.
Ek olarak, çalışıp çalışmadıklarını görmek için proxy'lerin çoklu testine ve bir JSON dosyasından okumak için json'a izin vermek için yerleşik iş parçacığı modülüne de ihtiyacımız var.
import requests
import threading
from requests.auth import HTTPProxyAuth
import json
from bs4 import BeautifulSoup
import lxml
import time
url_to_scrape = "https://books.toscrape.com"
valid_proxies = []
book_names = []
book_price = []
book_availability = []
next_button_link = ""
Proxy'leri döndüren bir kazıma betiği oluşturmak, döndürme sırasında aralarından seçim yapabileceğimiz bir proxy listesine ihtiyacımız olduğu anlamına gelir. Bazı proxy'ler kimlik doğrulaması gerektirir, bazıları ise gerektirmez. Kimlik doğrulama gerekiyorsa proxy kullanıcı adı ve parolası da dahil olmak üzere proxy ayrıntılarını içeren bir sözlük listesi oluşturmalıyız.
Bunun için en iyi yaklaşım, proxy bilgilerimizi aşağıdaki gibi düzenlenmiş ayrı bir JSON dosyasına koymaktır:
[
{
"proxy_address": "XX.X.XX.X:XX",
"proxy_username": "",
"proxy_password": ""
},
{
"proxy_address": "XX.X.XX.X:XX",
"proxy_username": "",
"proxy_password": ""
},
{
"proxy_address": "XX.X.XX.X:XX",
"proxy_username": "",
"proxy_password": ""
},
{
"proxy_address": "XX.X.XX.X:XX",
"proxy_username": "",
"proxy_password": ""
}
]
"proxy_address" alanına, iki nokta üst üste ile ayırarak IP adresini ve bağlantı noktasını girin. "proxy_username" ve "proxy_password" alanlarında, yetkilendirme için kullanıcı adı ve parolayı girin.
Yukarıda, betiğin aralarından seçim yapabileceği 4 proxy içeren bir JSON dosyasının içeriği yer almaktadır. Kullanıcı adı ve parola boş olabilir, bu da kimlik doğrulaması gerektirmeyen bir proxy'yi gösterir.
def verify_proxies(proxy:dict):
try:
if proxy['proxy_username'] != "" and proxy['proxy_password'] != "":
proxy_auth = HTTPProxyAuth(proxy['proxy_username'], proxy['proxy_password'])
res = requests.get(
url_to_scrape,
auth = proxy_auth,
proxies={
"http" : proxy['proxy_address']
}
)
else:
res = requests.get(url_to_scrape, proxies={
"http" : proxy['proxy_address'],
})
if res.status_code == 200:
valid_proxies.append(proxy)
print(f"Proxy Validated: {proxy['proxy_address']}")
except:
print("Proxy Invalidated, Moving on")
Önlem olarak, bu fonksiyon sağlanan proxy'lerin aktif ve çalışır durumda olmasını sağlar. Bunu, JSON dosyasındaki her bir sözlükte döngü oluşturarak, web sitesine bir GET isteği göndererek ve 200 durum kodu döndürülürse, bu proxy'yi dosyadaki listeden çalışan proxy'leri barındırmak için daha önce oluşturduğumuz bir değişken olan valid_proxies listesine ekleyerek başarabiliriz. Çağrı başarılı olmazsa, yürütme devam eder.
beautifulSoup, ihtiyacımız olan verileri çıkarmak için web sitesinin HTML koduna ihtiyaç duyduğundan, URL'yi ve tercih edilen proxy'yi alan ve HTML kodunu metin olarak döndüren request_function() işlevini oluşturduk. Proxy değişkeni, isteği farklı proxy'ler üzerinden yönlendirmemizi ve böylece proxy'yi döndürmemizi sağlar.
def request_function(url, proxy):
try:
if proxy['proxy_username'] != "" and proxy['proxy_password'] != "":
proxy_auth = HTTPProxyAuth(proxy['proxy_username'], proxy['proxy_password'])
response = requests.get(
url,
auth = proxy_auth,
proxies={
"http" : proxy['proxy_address']
}
)
else:
response = requests.get(url, proxies={
"http" : proxy['proxy_address']
})
if response.status_code == 200:
return response.text
except Exception as err:
print(f"Switching Proxies, URL access was unsuccessful: {err}")
return None
data_extract(), sağlanan HTML kodundan ihtiyacımız olan verileri çıkarır. Kitap adı, fiyatı ve bulunabilirliği gibi kitap bilgilerini barındıran HTML öğesini toplar. Ayrıca bir sonraki sayfanın bağlantısını da çıkarır.
Bu özellikle zordur çünkü bağlantı dinamiktir, bu yüzden dinamizmi hesaba katmamız gerekiyordu. Son olarak, kitaplara bakar ve adı, fiyatı ve kullanılabilirliği çıkarır, ardından bir sonraki sayfanın HTML kodunu almak için kullanacağımız sonraki düğme bağlantısını döndürür.
def data_extract(response):
soup = BeautifulSoup(response, "lxml")
books = soup.find_all("li", class_="col-xs-6 col-sm-4 col-md-3 col-lg-3")
next_button_link = soup.find("li", class_="next").find('a').get('href')
next_button_link=f"{url_to_scrape}/{next_button_link}" if "catalogue" in next_button_link else f"{url_to_scrape}/catalogue/{next_button_link}"
for each in books:
book_names.append(each.find("img").get("alt"))
book_price.append(each.find("p", class_="price_color").text)
book_availability.append(each.find("p", class_="instock availability").text.strip())
return next_button_link
Her şeyi birbirine bağlamak için bunu yapmak zorundayız:
with open("proxy-list.json") as json_file:
proxies = json.load(json_file)
for each in proxies:
threading.Thread(target=verify_proxies, args=(each, )).start()
time.sleep(4)
for i in range(len(valid_proxies)):
response = request_function(url_to_scrape, valid_proxies[i])
if response != None:
next_button_link = data_extract(response)
break
else:
continue
for proxy in valid_proxies:
print(f"Using Proxy: {proxy['proxy_address']}")
response = request_function(next_button_link, proxy)
if response is not None:
next_button_link = data_extract(response)
else:
continue
for each in range(len(book_names)):
print(f"No {each+1}: Book Name: {book_names[each]} Book Price: {book_price[each]} and Availability {book_availability[each]}")
import requests
import threading
from requests.auth import HTTPProxyAuth
import json
from bs4 import BeautifulSoup
import time
url_to_scrape = "https://books.toscrape.com"
valid_proxies = []
book_names = []
book_price = []
book_availability = []
next_button_link = ""
def verify_proxies(proxy: dict):
try:
if proxy['proxy_username'] != "" and proxy['proxy_password'] != "":
proxy_auth = HTTPProxyAuth(proxy['proxy_username'], proxy['proxy_password'])
res = requests.get(
url_to_scrape,
auth=proxy_auth,
proxies={
"http": proxy['proxy_address'],
}
)
else:
res = requests.get(url_to_scrape, proxies={
"http": proxy['proxy_address'],
})
if res.status_code == 200:
valid_proxies.append(proxy)
print(f"Proxy Validated: {proxy['proxy_address']}")
except:
print("Proxy Invalidated, Moving on")
# Bir sayfanın HTML öğesini alır
def request_function(url, proxy):
try:
if proxy['proxy_username'] != "" and proxy['proxy_password'] != "":
proxy_auth = HTTPProxyAuth(proxy['proxy_username'], proxy['proxy_password'])
response = requests.get(
url,
auth=proxy_auth,
proxies={
"http": proxy['proxy_address'],
}
)
else:
response = requests.get(url, proxies={
"http": proxy['proxy_address'],
})
if response.status_code == 200:
return response.text
except Exception as err:
print(f"Switching Proxies, URL access was unsuccessful: {err}")
return None
# Kazıma
def data_extract(response):
soup = BeautifulSoup(response, "lxml")
books = soup.find_all("li", class_="col-xs-6 col-sm-4 col-md-3 col-lg-3")
next_button_link = soup.find("li", class_="next").find('a').get('href')
next_button_link = f"{url_to_scrape}/{next_button_link}" if "catalogue" in next_button_link else f"{url_to_scrape}/catalogue/{next_button_link}"
for each in books:
book_names.append(each.find("img").get("alt"))
book_price.append(each.find("p", class_="price_color").text)
book_availability.append(each.find("p", class_="instock availability").text.strip())
return next_button_link
# JSON'dan proxy alın
with open("proxy-list.json") as json_file:
proxies = json.load(json_file)
for each in proxies:
threading.Thread(target=verify_proxies, args=(each,)).start()
time.sleep(4)
for i in range(len(valid_proxies)):
response = request_function(url_to_scrape, valid_proxies[i])
if response is not None:
next_button_link = data_extract(response)
break
else:
continue
for proxy in valid_proxies:
print(f"Using Proxy: {proxy['proxy_address']}")
response = request_function(next_button_link, proxy)
if response is not None:
next_button_link = data_extract(response)
else:
continue
for each in range(len(book_names)):
print(
f"No {each + 1}: Book Name: {book_names[each]} Book Price: {book_price[each]} and Availability {book_availability[each]}")
Başarılı bir yürütmeden sonra sonuçlar aşağıdaki gibi görünür. Bu, sağlanan 2 vekili kullanarak 100'den fazla kitap hakkında bilgi çıkarmaya devam eder.
Web kazıma için birden fazla proxy kullanmak, hedef kaynağa yönelik istek sayısının artmasını sağlar ve engellemelerin aşılmasına yardımcı olur. Kazıma işleminin istikrarını korumak için, statik ISP ve dinamik konut proxy'leri gibi yüksek hız ve güçlü bir güven faktörü sunan IP adreslerinin kullanılması tavsiye edilir. Ek olarak, sağlanan komut dosyasının işlevselliği, çeşitli veri kazıma gereksinimlerini karşılamak için kolayca genişletilebilir.
Yorumlar: 0