В этой короткой статье я покажу как сделать свой парсер, который будет получать данные с сайта Pleer.ru по ссылке из любой категории с листингом товаров — название, цену, заголовок страницы товара, id.
Статья написана в образовательных целях, чтобы быстро научиться программировать парсеры. Код сайта со временем изменится и скрипт не будет работать путём копипаста, нужно будет изменить XPath-выражения. Цель этого и всех других хау-ту статей на этом сайте состоит в том, чтобы вы понимали, как создать парсер и поддерживать его с течением времени по мере внесения изменений на исходный сайт.
Инструментарий: Python 3 + библиотеки
Я буду использовать Python 3 и некоторые распространенные библиотеки Python.
Вот некоторые данные, которые этот парсер поможет вам извлечь в csv-таблицу:
- Называние
- Цена
- Id
- Title
В парсер легко добавить любые данные с сайта, помимо уже существующих — урл картинок или сами картинки, описания, отзывы и т.д.
Я сохраню данные в виде электронной таблицы Excel (CSV), которая выглядит следующим образом:
Установка необходимых пакетов для парсинга Pleer.ru
Тут я не рассказываю про основы Python и как его установить, это тема отдельной статьи.
Буду использовать следующие библиотеки:
- requests
- csv
- time
- lxml
Устанавливаю их с помощью pip3:
pip3 install requests, csv, time, lxml
Код проекта на Python
Весь код, используемый в этом проекте, доступен для загрузки с Github по адресу https://github.com/Megaduox/parser_pleer.ru
Давайте создадим файл с именем main.py и вставим в него следующий код:
import requests
import csv
import time
from lxml import html
headers = {
'authority': 'https://www.google.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'referer': 'https://www.google.com/',
'accept-language': 'ru-RU, ru;q=0.9',
}
url = 'https://www.pleer.ru/list_svetodiodnye-dizajnerskie-lampochki.html'
domain = 'https://www.pleer.ru/'
ALL_DATA = dict()
QUEUE_URL = set()
def get_links(page_url):
first_url = page_url.split(".html")[0]
pages_count = 0
r = requests.get(page_url, headers=headers)
tree = html.fromstring(r.content)
# поставить условие, если не содержит основного контента - стоп и печать ошибки
first_page_links = tree.xpath('//div[@class="product_link h3"]//a/@href')
print('Код ответа корневого УРЛ: ', r.status_code)
time.sleep(3)
while True:
pages_count += 1
page_url = f'{first_url}_page{pages_count}.html'
print("Проверяю доступность урл:", page_url)
r = requests.get(url, headers=headers)
tree = html.fromstring(r.content)
page_links = tree.xpath('//div[@class="product_link h3"]//a/@href')
for one_link in page_links:
QUEUE_URL.add(domain+one_link) # add to QUEUE
print('Все ссылки со страниц добавил в очередь')
if r.status_code == 404 or page_links == first_page_links:
print('Останавливаю цикл, все страницы пейджинации спарсил')
break
time.sleep(3)
Вот что делает этот код:
- импортирует нужные библиотеки
- функция get_links() принимает на вход url, берёт все ссылки с него на товары из листинга, проходит по всей пейдижнации и складывает ссылки в множество QUEUE_URL
Далее добавляю код:
def get_data(product_link):
product = dict()
r = requests.get(product_link, headers=headers)
tree = html.fromstring(r.content)
product_name = tree.xpath("//span[@class='product_title']")
product_id = tree.xpath("//div[@class='product_id']")
product_price = tree.xpath("//div[@class='product_price product_price_color4']"
"/div[@class='price']/div[@class='hide']")
product_title = tree.findtext('.//title')
product['Title'] = product_title
for name in product_name:
print(name.text)
product['Name'] = name.text
for price in product_price:
print(price.text)
product['Price'] = price.text
for id in product_id:
print(id.text)
product['Id'] = id.text
time.sleep(3)
return product
Здесь функция get_data() принимает на вход один урл товара, парсит данные. Сами данные никуда не записывает, а возвращает список данных в виде словаря.
И в финале добавляю основную функцию main():
def main():
with open('data.csv', 'a', newline='') as csvfile:
fieldnames = ["Name", "Price", "Id", "Title"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames,
quoting=csv.QUOTE_ALL)
writer.writeheader()
get_links(url)
while len(QUEUE_URL) != 0:
current_url = QUEUE_URL.pop()
add_to_csv_from_file(get_data(current_url))
if __name__ == '__main__':
main()
Эта функция записывает получившиеся данные в файл csv, вызывая в своей работе get_links() для парсинга списка всех товаров и рекурсивно get_data() для парсинга конкретного урла.
Проблемы, с которыми вы можете столкнуться
- Сайт при парсинге отдаёт код 204, страница рабочая, но без контента. Решается добавлением хедеров:
headers = {
'authority': 'https://www.google.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9',
'referer': 'https://www.google.com/',
'accept-language': 'ru-RU, ru;q=0.9',
}
- Для того, чтобы сайт не забанил при парсинге, нужно делать задержку при рандомом в несколько секунд
- Пейджинация чуть хитрее, потому что несуществующие страницы отдают 200 код, а не 404 и поэтому их нельзя перебрать в цикле стандартным способом
- Чтобы парсить весь сайт нужно пилить либо через прокси, либо через Selenium
- Если товара нет в наличии на странице, то в csv-файле будет пустая ячейка, потому что меняется вёрстка
Список выше только часть проблем, с которыми сталкиваешься при парсинге и у каждого сайта они могут быть индивидуальны, особенно, если проект крупный.
Эти и многие другие проблемы являются причиной того, что компании, которые специализируются на парсинге, такие как мы, работают лучше, чем скрипты, разработанные самостоятельно. Если же есть желание разобраться самостоятельно, вы можете взять за основу мой скрипт и использовать его для отслеживания цен с сайта pleer.ru.
Если вам нужна помощь в сложных проектах по парсингу и сбору данных, напишите, мы будем рады вам помочь.