Скрапінг даних часто сприймається веб-сайтами як небажана дія, що може призвести до блокування вашої IP-адреси. Проте існують ефективні способи мінімізації можливих наслідків, наприклад, використання проксі-серверів.
Проксі-сервери дають змогу приховувати справжню IP-адресу, роблячи скрапінг менш підозрілим для системи безпеки сервісу. Застосування декількох проксі та їхня ротація може значно зменшити ймовірність блокування, тому що взаємодія з вебсайтами виглядатиме природнішою.
Як приклад ми розглянемо використання цього методу на сайті інтернет-магазину книг. Скрапер збиратиме таку інформацію про книги, як назва, ціна та доступність. Основний акцент у цьому посібнику буде зроблено на техніці ротації проксі, а не на обробці та організації отриманих даних.
Перед тим як приступити до написання функцій для ротації проксі та скрапінгу веб-сайту, важливо підготувати робоче середовище, встановивши та імпортувавши необхідні модулі Python. Три з п'яти необхідних модулів Python для цього скрипта встановлюються за допомогою такої команди:
pip install requests beautifulSoup4 lxml
Requests дає нам змогу надсилати HTTP-запити на вебсайт, beautifulsoup4 дає змогу витягувати інформацію з HTML-сторінки, яку надає requests, а lxml є парсером HTML.
Крім того, нам також будуть потрібні вбудований модуль threading для множинного тестування проксі на працездатність і json для читання з JSON-файлу:
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 = ""
Щоб ефективно реалізувати скрапінг із ротацією проксі, необхідно мати список проксі, який можна використовувати для зміни IP-адрес у процесі роботи. Найкращий підхід до цього процесу - завантажити інформацію про наші проксі в окремий JSON-файл, організований таким чином:
[
{
"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" вказуємо IP-адресу і порт через двокрапку, у рядках "proxy_username" і "proxy_password" логін і пароль для авторизації.
Розглянемо приклад змісту JSON-файлу з чотирма проксі, які можна використовувати для скрапінгу. У цьому прикладі, деякі проксі вимагають аутентифікації - ім'я користувача та пароль, тоді як інші - ні.
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")
Щоб переконатися в працездатності проксі зі списку, необхідно перевірити кожен із них, надсилаючи GET-запити на обраний веб-сайт. Якщо сервер відповість статус-кодом 200, проксі вважається активним і додається до списку діючих проксі. У разі невдачі скрипт продовжує перевірку наступних проксі.
Для успішного скрапінгу даних з використанням бібліотеки BeautifulSoup, необхідно спочатку отримати HTML-код веб-сайту. Реалізація функції "request_function()", яка надсилає HTTP-запит через обраний проксі, дає змогу отримати цей HTML-код. Функція приймає URL веб-сайту і проксі, через який буде відправлено запит, забезпечуючи тим самим ротацію проксі для мінімізації ризику блокування.
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()" витягує необхідні дані з наданого HTML-коду. Вона збирає HTML-елемент, що містить інформацію про книгу, таку як назва, ціна та наявність. Також функція витягує посилання на наступну сторінку.
Функція тепер повертає не тільки списки назв книг, цін та інформації про наявність, а й повний URL наступної сторінки, що дає змогу скрипту перейти до наступної сторінки каталогу для продовження скрапінгу.
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
Щоб зв'язати все разом, нам необхідно виконати такі дії:
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")
# Отримайте HTML-елемент сторінки
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
# Процес скрапінгу
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
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]}")
Після успішного виконання скрипта результати показують, що ми змогли витягти інформацію більш ніж про 100 книг, використовуючи два наданих проксі.
Таким чином, використання декількох проксі під час веб-скрапінгу дає змогу збільшити кількість запитів на цільовий ресурс і обійти блокування. Щоб забезпечити стабільність процесу скрапінгу, рекомендується використовувати IP-адреси з високою швидкістю і траст-фактором, як-от статичні ISP і динамічні резидентські проксі-сервери. Функціональність наданого скрипта може бути легко розширена для задоволення інших потреб під час скрапінгу даних.
Мы получили вашу заявку!
Ответ будет отправлен на почту в ближайшее время.
С уважением proxy-seller.com!
Коментарі: 0