Скрапинг данных часто воспринимается веб-сайтами как нежелательное действие, что может привести к блокировке вашего 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 следующей страницы, что позволяет скрипту перейти к следующей странице каталога для продолжения cкрапинга.
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.ru!
Комментарии: 0